1 /* 2 * Copyright 2012 Red Hat Inc. 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 */ 24 #include "priv.h" 25 #include "chan.h" 26 27 #include <core/client.h> 28 #include <core/gpuobj.h> 29 #include <core/notify.h> 30 31 #include <nvif/event.h> 32 #include <nvif/unpack.h> 33 34 void 35 nvkm_fifo_recover_chan(struct nvkm_fifo *fifo, int chid) 36 { 37 unsigned long flags; 38 if (WARN_ON(!fifo->func->recover_chan)) 39 return; 40 spin_lock_irqsave(&fifo->lock, flags); 41 fifo->func->recover_chan(fifo, chid); 42 spin_unlock_irqrestore(&fifo->lock, flags); 43 } 44 45 void 46 nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags) 47 { 48 return fifo->func->pause(fifo, flags); 49 } 50 51 void 52 nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags) 53 { 54 return fifo->func->start(fifo, flags); 55 } 56 57 void 58 nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags, 59 struct nvkm_fifo_chan **pchan) 60 { 61 struct nvkm_fifo_chan *chan = *pchan; 62 if (likely(chan)) { 63 *pchan = NULL; 64 spin_unlock_irqrestore(&fifo->lock, flags); 65 } 66 } 67 68 struct nvkm_fifo_chan * 69 nvkm_fifo_chan_inst_locked(struct nvkm_fifo *fifo, u64 inst) 70 { 71 struct nvkm_fifo_chan *chan; 72 list_for_each_entry(chan, &fifo->chan, head) { 73 if (chan->inst->addr == inst) { 74 list_del(&chan->head); 75 list_add(&chan->head, &fifo->chan); 76 return chan; 77 } 78 } 79 return NULL; 80 } 81 82 struct nvkm_fifo_chan * 83 nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags) 84 { 85 struct nvkm_fifo_chan *chan; 86 unsigned long flags; 87 spin_lock_irqsave(&fifo->lock, flags); 88 if ((chan = nvkm_fifo_chan_inst_locked(fifo, inst))) { 89 *rflags = flags; 90 return chan; 91 } 92 spin_unlock_irqrestore(&fifo->lock, flags); 93 return NULL; 94 } 95 96 struct nvkm_fifo_chan * 97 nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags) 98 { 99 struct nvkm_fifo_chan *chan; 100 unsigned long flags; 101 spin_lock_irqsave(&fifo->lock, flags); 102 list_for_each_entry(chan, &fifo->chan, head) { 103 if (chan->chid == chid) { 104 list_del(&chan->head); 105 list_add(&chan->head, &fifo->chan); 106 *rflags = flags; 107 return chan; 108 } 109 } 110 spin_unlock_irqrestore(&fifo->lock, flags); 111 return NULL; 112 } 113 114 void 115 nvkm_fifo_kevent(struct nvkm_fifo *fifo, int chid) 116 { 117 nvkm_event_send(&fifo->kevent, 1, chid, NULL, 0); 118 } 119 120 static int 121 nvkm_fifo_kevent_ctor(struct nvkm_object *object, void *data, u32 size, 122 struct nvkm_notify *notify) 123 { 124 struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); 125 if (size == 0) { 126 notify->size = 0; 127 notify->types = 1; 128 notify->index = chan->chid; 129 return 0; 130 } 131 return -ENOSYS; 132 } 133 134 static const struct nvkm_event_func 135 nvkm_fifo_kevent_func = { 136 .ctor = nvkm_fifo_kevent_ctor, 137 }; 138 139 static int 140 nvkm_fifo_cevent_ctor(struct nvkm_object *object, void *data, u32 size, 141 struct nvkm_notify *notify) 142 { 143 if (size == 0) { 144 notify->size = 0; 145 notify->types = 1; 146 notify->index = 0; 147 return 0; 148 } 149 return -ENOSYS; 150 } 151 152 static const struct nvkm_event_func 153 nvkm_fifo_cevent_func = { 154 .ctor = nvkm_fifo_cevent_ctor, 155 }; 156 157 void 158 nvkm_fifo_cevent(struct nvkm_fifo *fifo) 159 { 160 nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0); 161 } 162 163 static void 164 nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index) 165 { 166 struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); 167 fifo->func->uevent_fini(fifo); 168 } 169 170 static void 171 nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index) 172 { 173 struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); 174 fifo->func->uevent_init(fifo); 175 } 176 177 static int 178 nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size, 179 struct nvkm_notify *notify) 180 { 181 union { 182 struct nvif_notify_uevent_req none; 183 } *req = data; 184 int ret = -ENOSYS; 185 186 if (!(ret = nvif_unvers(ret, &data, &size, req->none))) { 187 notify->size = sizeof(struct nvif_notify_uevent_rep); 188 notify->types = 1; 189 notify->index = 0; 190 } 191 192 return ret; 193 } 194 195 static const struct nvkm_event_func 196 nvkm_fifo_uevent_func = { 197 .ctor = nvkm_fifo_uevent_ctor, 198 .init = nvkm_fifo_uevent_init, 199 .fini = nvkm_fifo_uevent_fini, 200 }; 201 202 void 203 nvkm_fifo_uevent(struct nvkm_fifo *fifo) 204 { 205 struct nvif_notify_uevent_rep rep = { 206 }; 207 nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep)); 208 } 209 210 static int 211 nvkm_fifo_class_new(struct nvkm_device *device, 212 const struct nvkm_oclass *oclass, void *data, u32 size, 213 struct nvkm_object **pobject) 214 { 215 const struct nvkm_fifo_chan_oclass *sclass = oclass->engn; 216 struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); 217 return sclass->ctor(fifo, oclass, data, size, pobject); 218 } 219 220 static const struct nvkm_device_oclass 221 nvkm_fifo_class = { 222 .ctor = nvkm_fifo_class_new, 223 }; 224 225 static int 226 nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, 227 const struct nvkm_device_oclass **class) 228 { 229 struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); 230 const struct nvkm_fifo_chan_oclass *sclass; 231 int c = 0; 232 233 if (fifo->func->class_get) { 234 int ret = fifo->func->class_get(fifo, index, &sclass); 235 if (ret == 0) { 236 oclass->base = sclass->base; 237 oclass->engn = sclass; 238 *class = &nvkm_fifo_class; 239 return 0; 240 } 241 return ret; 242 } 243 244 while ((sclass = fifo->func->chan[c])) { 245 if (c++ == index) { 246 oclass->base = sclass->base; 247 oclass->engn = sclass; 248 *class = &nvkm_fifo_class; 249 return 0; 250 } 251 } 252 253 return c; 254 } 255 256 static void 257 nvkm_fifo_intr(struct nvkm_engine *engine) 258 { 259 struct nvkm_fifo *fifo = nvkm_fifo(engine); 260 fifo->func->intr(fifo); 261 } 262 263 static int 264 nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend) 265 { 266 struct nvkm_fifo *fifo = nvkm_fifo(engine); 267 if (fifo->func->fini) 268 fifo->func->fini(fifo); 269 return 0; 270 } 271 272 static int 273 nvkm_fifo_oneinit(struct nvkm_engine *engine) 274 { 275 struct nvkm_fifo *fifo = nvkm_fifo(engine); 276 if (fifo->func->oneinit) 277 return fifo->func->oneinit(fifo); 278 return 0; 279 } 280 281 static int 282 nvkm_fifo_init(struct nvkm_engine *engine) 283 { 284 struct nvkm_fifo *fifo = nvkm_fifo(engine); 285 fifo->func->init(fifo); 286 return 0; 287 } 288 289 static void * 290 nvkm_fifo_dtor(struct nvkm_engine *engine) 291 { 292 struct nvkm_fifo *fifo = nvkm_fifo(engine); 293 void *data = fifo; 294 if (fifo->func->dtor) 295 data = fifo->func->dtor(fifo); 296 nvkm_event_fini(&fifo->kevent); 297 nvkm_event_fini(&fifo->cevent); 298 nvkm_event_fini(&fifo->uevent); 299 return data; 300 } 301 302 static const struct nvkm_engine_func 303 nvkm_fifo = { 304 .dtor = nvkm_fifo_dtor, 305 .oneinit = nvkm_fifo_oneinit, 306 .init = nvkm_fifo_init, 307 .fini = nvkm_fifo_fini, 308 .intr = nvkm_fifo_intr, 309 .base.sclass = nvkm_fifo_class_get, 310 }; 311 312 int 313 nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device, 314 int index, int nr, struct nvkm_fifo *fifo) 315 { 316 int ret; 317 318 fifo->func = func; 319 INIT_LIST_HEAD(&fifo->chan); 320 spin_lock_init(&fifo->lock); 321 322 if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR)) 323 fifo->nr = NVKM_FIFO_CHID_NR; 324 else 325 fifo->nr = nr; 326 bitmap_clear(fifo->mask, 0, fifo->nr); 327 328 ret = nvkm_engine_ctor(&nvkm_fifo, device, index, true, &fifo->engine); 329 if (ret) 330 return ret; 331 332 if (func->uevent_init) { 333 ret = nvkm_event_init(&nvkm_fifo_uevent_func, 1, 1, 334 &fifo->uevent); 335 if (ret) 336 return ret; 337 } 338 339 ret = nvkm_event_init(&nvkm_fifo_cevent_func, 1, 1, &fifo->cevent); 340 if (ret) 341 return ret; 342 343 return nvkm_event_init(&nvkm_fifo_kevent_func, 1, nr, &fifo->kevent); 344 } 345