1/* 2 * Copyright 2007 Nouveau Project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include <stdlib.h> 24#include <errno.h> 25#include <sys/time.h> 26 27#include "nouveau_private.h" 28 29#define NOTIFIER(__v) \ 30 struct nouveau_notifier_priv *nvnotify = nouveau_notifier(notifier); \ 31 volatile uint32_t *__v = (uint32_t *)((char *)nvnotify->map + (id * 32)) 32 33int 34nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, 35 int count, struct nouveau_notifier **notifier) 36{ 37 struct nouveau_notifier_priv *nvnotify; 38 int ret; 39 40 if (!chan || !notifier || *notifier) 41 return -EINVAL; 42 43 nvnotify = calloc(1, sizeof(struct nouveau_notifier_priv)); 44 if (!nvnotify) 45 return -ENOMEM; 46 nvnotify->base.channel = chan; 47 nvnotify->base.handle = handle; 48 49 nvnotify->drm.channel = chan->id; 50 nvnotify->drm.handle = handle; 51 nvnotify->drm.count = count; 52 if ((ret = drmCommandWriteRead(nouveau_device(chan->device)->fd, 53 DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, 54 &nvnotify->drm, 55 sizeof(nvnotify->drm)))) { 56 nouveau_notifier_free((void *)&nvnotify); 57 return ret; 58 } 59 60 nvnotify->map = (char *)nouveau_channel(chan)->notifier_block + 61 nvnotify->drm.offset; 62 *notifier = &nvnotify->base; 63 return 0; 64} 65 66void 67nouveau_notifier_free(struct nouveau_notifier **notifier) 68{ 69 70 struct nouveau_notifier_priv *nvnotify; 71 struct nouveau_channel_priv *nvchan; 72 struct nouveau_device_priv *nvdev; 73 struct drm_nouveau_gpuobj_free f; 74 75 if (!notifier || !*notifier) 76 return; 77 nvnotify = nouveau_notifier(*notifier); 78 *notifier = NULL; 79 80 nvchan = nouveau_channel(nvnotify->base.channel); 81 nvdev = nouveau_device(nvchan->base.device); 82 83 f.channel = nvchan->drm.channel; 84 f.handle = nvnotify->base.handle; 85 drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE, &f, sizeof(f)); 86 free(nvnotify); 87} 88 89void 90nouveau_notifier_reset(struct nouveau_notifier *notifier, int id) 91{ 92 NOTIFIER(n); 93 94 n[NV_NOTIFY_TIME_0 /4] = 0x00000000; 95 n[NV_NOTIFY_TIME_1 /4] = 0x00000000; 96 n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000; 97 n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS << 98 NV_NOTIFY_STATE_STATUS_SHIFT); 99} 100 101uint32_t 102nouveau_notifier_status(struct nouveau_notifier *notifier, int id) 103{ 104 NOTIFIER(n); 105 106 return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT; 107} 108 109uint32_t 110nouveau_notifier_return_val(struct nouveau_notifier *notifier, int id) 111{ 112 NOTIFIER(n); 113 114 return n[NV_NOTIFY_RETURN_VALUE/4]; 115} 116 117static inline double 118gettime(void) 119{ 120 struct timeval tv; 121 122 gettimeofday(&tv, NULL); 123 return (double)tv.tv_sec + tv.tv_usec / 1000000.0; 124} 125 126int 127nouveau_notifier_wait_status(struct nouveau_notifier *notifier, int id, 128 uint32_t status, double timeout) 129{ 130 NOTIFIER(n); 131 double time = 0, t_start = gettime(); 132 133 while (time <= timeout) { 134 uint32_t v; 135 136 v = n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT; 137 if (v == status) 138 return 0; 139 140 if (timeout) 141 time = gettime() - t_start; 142 } 143 144 return -EBUSY; 145} 146 147