Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 56f67dc1 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent 2ebfa1bc
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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>
+54 −3
Original line number Diff line number Diff line
@@ -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))
+1 −2
Original line number Diff line number Diff line
@@ -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;
+6 −0
Original line number Diff line number Diff line
@@ -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)
{
+0 −57
Original line number Diff line number Diff line
@@ -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)
{