diff options
Diffstat (limited to 'src/nv_notifier.c')
-rw-r--r-- | src/nv_notifier.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/nv_notifier.c b/src/nv_notifier.c new file mode 100644 index 0000000..88f0edb --- /dev/null +++ b/src/nv_notifier.c @@ -0,0 +1,126 @@ +#include "nv_include.h" + +#define NV_NOTIFIER_SIZE 32 +#define NV_NOTIFY_TIME_0 0x00000000 +#define NV_NOTIFY_TIME_1 0x00000004 +#define NV_NOTIFY_RETURN_VALUE 0x00000008 +#define NV_NOTIFY_STATE 0x0000000C +#define NV_NOTIFY_STATE_STATUS_MASK 0xFF000000 +#define NV_NOTIFY_STATE_STATUS_SHIFT 24 +#define NV_NOTIFY_STATE_STATUS_COMPLETED 0x00 +#define NV_NOTIFY_STATE_STATUS_IN_PROCESS 0x01 +#define NV_NOTIFY_STATE_ERROR_CODE_MASK 0x0000FFFF +#define NV_NOTIFY_STATE_ERROR_CODE_SHIFT 0 + +#define NOTIFIER(__v) \ + NVPtr pNv = NVPTR(pScrn); \ + volatile uint32_t *__v = (void*)pNv->NotifierBlock + notifier->offset + +drm_nouveau_notifier_alloc_t * +NVNotifierAlloc(ScrnInfoPtr pScrn, uint32_t handle) +{ + NVPtr pNv = NVPTR(pScrn); + drm_nouveau_notifier_alloc_t *notifier; + int ret; + + notifier = xcalloc(1, sizeof(*notifier)); + if (!notifier) { + NVNotifierDestroy(pScrn, notifier); + return NULL; + } + + notifier->channel = pNv->fifo.channel; + notifier->handle = handle; + notifier->count = 1; + ret = drmCommandWriteRead(pNv->drm_fd, DRM_NOUVEAU_NOTIFIER_ALLOC, + notifier, sizeof(*notifier)); + if (ret) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to create notifier 0x%08x: %d\n", + handle, ret); + NVNotifierDestroy(pScrn, notifier); + return NULL; + } + + return notifier; +} + +void +NVNotifierDestroy(ScrnInfoPtr pScrn, drm_nouveau_notifier_alloc_t *notifier) +{ + if (notifier) { + /*XXX: destroy notifier object */ + xfree(notifier); + } +} + +void +NVNotifierReset(ScrnInfoPtr pScrn, drm_nouveau_notifier_alloc_t *notifier) +{ + NOTIFIER(n); + + n[NV_NOTIFY_TIME_0 /4] = + n[NV_NOTIFY_TIME_1 /4] = + n[NV_NOTIFY_RETURN_VALUE/4] = 0; + n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS << + NV_NOTIFY_STATE_STATUS_SHIFT); +} + +uint32_t +NVNotifierStatus(ScrnInfoPtr pScrn, drm_nouveau_notifier_alloc_t *notifier) +{ + NOTIFIER(n); + + return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT; +} + +uint32_t +NVNotifierErrorCode(ScrnInfoPtr pScrn, drm_nouveau_notifier_alloc_t *notifier) +{ + NOTIFIER(n); + + return n[NV_NOTIFY_STATE/4] & NV_NOTIFY_STATE_ERROR_CODE_MASK; +} + +uint32_t +NVNotifierReturnVal(ScrnInfoPtr pScrn, drm_nouveau_notifier_alloc_t *notifier) +{ + NOTIFIER(n); + + return n[NV_NOTIFY_RETURN_VALUE/4]; +} + +Bool +NVNotifierWaitStatus(ScrnInfoPtr pScrn, drm_nouveau_notifier_alloc_t *notifier, + unsigned int status, unsigned int timeout) +{ + NOTIFIER(n); + unsigned int t_start, time = 0; + + t_start = GetTimeInMillis(); + while (time <= timeout) { +#if 0 + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "N(0x%08x)/%d = 0x%08x/0x%08x/0x%08x/0x%08x\n", + notifier->handle, time, n[0], n[1], n[2], n[3]); +#endif + if (n[NV_NOTIFY_STATE/4] & NV_NOTIFY_STATE_ERROR_CODE_MASK) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Notifier returned error: 0x%04x\n", + NVNotifierErrorCode(pScrn, notifier)); + return FALSE; + } + + if ((n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT) + == status) + return TRUE; + + if (timeout) + time = GetTimeInMillis() - t_start; + } + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Notifier (0x%08x) timeout!\n", notifier->handle); + return FALSE; +} + |