1 /* $NetBSD: nouveau_nvkm_engine_fifo_base.c,v 1.4 2021/12/19 11:34:45 riastradh Exp $ */ 2 3 /* 4 * Copyright 2012 Red Hat Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: Ben Skeggs 25 */ 26 #include <sys/cdefs.h> 27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_engine_fifo_base.c,v 1.4 2021/12/19 11:34:45 riastradh Exp $"); 28 29 #include "priv.h" 30 #include "chan.h" 31 32 #include <core/client.h> 33 #include <core/gpuobj.h> 34 #include <core/notify.h> 35 #include <subdev/mc.h> 36 37 #include <nvif/event.h> 38 #include <nvif/cl0080.h> 39 #include <nvif/unpack.h> 40 41 void 42 nvkm_fifo_recover_chan(struct nvkm_fifo *fifo, int chid) 43 { 44 unsigned long flags; 45 if (WARN_ON(!fifo->func->recover_chan)) 46 return; 47 spin_lock_irqsave(&fifo->lock, flags); 48 fifo->func->recover_chan(fifo, chid); 49 spin_unlock_irqrestore(&fifo->lock, flags); 50 } 51 52 void 53 nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags) 54 { 55 return fifo->func->pause(fifo, flags); 56 } 57 58 void 59 nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags) 60 { 61 return fifo->func->start(fifo, flags); 62 } 63 64 void 65 nvkm_fifo_fault(struct nvkm_fifo *fifo, struct nvkm_fault_data *info) 66 { 67 return fifo->func->fault(fifo, info); 68 } 69 70 void 71 nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags, 72 struct nvkm_fifo_chan **pchan) 73 { 74 struct nvkm_fifo_chan *chan = *pchan; 75 if (likely(chan)) { 76 *pchan = NULL; 77 spin_unlock_irqrestore(&fifo->lock, flags); 78 } 79 } 80 81 struct nvkm_fifo_chan * 82 nvkm_fifo_chan_inst_locked(struct nvkm_fifo *fifo, u64 inst) 83 { 84 struct nvkm_fifo_chan *chan; 85 list_for_each_entry(chan, &fifo->chan, head) { 86 if (chan->inst->addr == inst) { 87 list_del(&chan->head); 88 list_add(&chan->head, &fifo->chan); 89 return chan; 90 } 91 } 92 return NULL; 93 } 94 95 struct nvkm_fifo_chan * 96 nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags) 97 { 98 struct nvkm_fifo_chan *chan; 99 unsigned long flags; 100 spin_lock_irqsave(&fifo->lock, flags); 101 if ((chan = nvkm_fifo_chan_inst_locked(fifo, inst))) { 102 *rflags = flags; 103 return chan; 104 } 105 spin_unlock_irqrestore(&fifo->lock, flags); 106 return NULL; 107 } 108 109 struct nvkm_fifo_chan * 110 nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags) 111 { 112 struct nvkm_fifo_chan *chan; 113 unsigned long flags; 114 spin_lock_irqsave(&fifo->lock, flags); 115 list_for_each_entry(chan, &fifo->chan, head) { 116 if (chan->chid == chid) { 117 list_del(&chan->head); 118 list_add(&chan->head, &fifo->chan); 119 *rflags = flags; 120 return chan; 121 } 122 } 123 spin_unlock_irqrestore(&fifo->lock, flags); 124 return NULL; 125 } 126 127 void 128 nvkm_fifo_kevent(struct nvkm_fifo *fifo, int chid) 129 { 130 nvkm_event_send(&fifo->kevent, 1, chid, NULL, 0); 131 } 132 133 static int 134 nvkm_fifo_kevent_ctor(struct nvkm_object *object, void *data, u32 size, 135 struct nvkm_notify *notify) 136 { 137 struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); 138 if (size == 0) { 139 notify->size = 0; 140 notify->types = 1; 141 notify->index = chan->chid; 142 return 0; 143 } 144 return -ENOSYS; 145 } 146 147 static const struct nvkm_event_func 148 nvkm_fifo_kevent_func = { 149 .ctor = nvkm_fifo_kevent_ctor, 150 }; 151 152 static int 153 nvkm_fifo_cevent_ctor(struct nvkm_object *object, void *data, u32 size, 154 struct nvkm_notify *notify) 155 { 156 if (size == 0) { 157 notify->size = 0; 158 notify->types = 1; 159 notify->index = 0; 160 return 0; 161 } 162 return -ENOSYS; 163 } 164 165 static const struct nvkm_event_func 166 nvkm_fifo_cevent_func = { 167 .ctor = nvkm_fifo_cevent_ctor, 168 }; 169 170 void 171 nvkm_fifo_cevent(struct nvkm_fifo *fifo) 172 { 173 nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0); 174 } 175 176 static void 177 nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index) 178 { 179 struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); 180 fifo->func->uevent_fini(fifo); 181 } 182 183 static void 184 nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index) 185 { 186 struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); 187 fifo->func->uevent_init(fifo); 188 } 189 190 static int 191 nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size, 192 struct nvkm_notify *notify) 193 { 194 union { 195 struct nvif_notify_uevent_req none; 196 } *req = data; 197 int ret = -ENOSYS; 198 199 if (!(ret = nvif_unvers(ret, &data, &size, req->none))) { 200 notify->size = sizeof(struct nvif_notify_uevent_rep); 201 notify->types = 1; 202 notify->index = 0; 203 } 204 205 return ret; 206 } 207 208 static const struct nvkm_event_func 209 nvkm_fifo_uevent_func = { 210 .ctor = nvkm_fifo_uevent_ctor, 211 .init = nvkm_fifo_uevent_init, 212 .fini = nvkm_fifo_uevent_fini, 213 }; 214 215 void 216 nvkm_fifo_uevent(struct nvkm_fifo *fifo) 217 { 218 struct nvif_notify_uevent_rep rep = { 219 }; 220 nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep)); 221 } 222 223 static int 224 nvkm_fifo_class_new_(struct nvkm_device *device, 225 const struct nvkm_oclass *oclass, void *data, u32 size, 226 struct nvkm_object **pobject) 227 { 228 struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); 229 return fifo->func->class_new(fifo, oclass, data, size, pobject); 230 } 231 232 static const struct nvkm_device_oclass 233 nvkm_fifo_class_ = { 234 .ctor = nvkm_fifo_class_new_, 235 }; 236 237 static int 238 nvkm_fifo_class_new(struct nvkm_device *device, 239 const struct nvkm_oclass *oclass, void *data, u32 size, 240 struct nvkm_object **pobject) 241 { 242 const struct nvkm_fifo_chan_oclass *sclass = oclass->engn; 243 struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); 244 return sclass->ctor(fifo, oclass, data, size, pobject); 245 } 246 247 static const struct nvkm_device_oclass 248 nvkm_fifo_class = { 249 .ctor = nvkm_fifo_class_new, 250 }; 251 252 static int 253 nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, 254 const struct nvkm_device_oclass **class) 255 { 256 struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); 257 const struct nvkm_fifo_chan_oclass *sclass; 258 int c = 0; 259 260 if (fifo->func->class_get) { 261 int ret = fifo->func->class_get(fifo, index, oclass); 262 if (ret == 0) 263 *class = &nvkm_fifo_class_; 264 return ret; 265 } 266 267 while ((sclass = fifo->func->chan[c])) { 268 if (c++ == index) { 269 oclass->base = sclass->base; 270 oclass->engn = sclass; 271 *class = &nvkm_fifo_class; 272 return 0; 273 } 274 } 275 276 return c; 277 } 278 279 static void 280 nvkm_fifo_intr(struct nvkm_engine *engine) 281 { 282 struct nvkm_fifo *fifo = nvkm_fifo(engine); 283 fifo->func->intr(fifo); 284 } 285 286 static int 287 nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend) 288 { 289 struct nvkm_fifo *fifo = nvkm_fifo(engine); 290 if (fifo->func->fini) 291 fifo->func->fini(fifo); 292 return 0; 293 } 294 295 static int 296 nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data) 297 { 298 struct nvkm_fifo *fifo = nvkm_fifo(engine); 299 switch (mthd) { 300 case NV_DEVICE_FIFO_CHANNELS: *data = fifo->nr; return 0; 301 default: 302 if (fifo->func->info) 303 return fifo->func->info(fifo, mthd, data); 304 break; 305 } 306 return -ENOSYS; 307 } 308 309 static int 310 nvkm_fifo_oneinit(struct nvkm_engine *engine) 311 { 312 struct nvkm_fifo *fifo = nvkm_fifo(engine); 313 if (fifo->func->oneinit) 314 return fifo->func->oneinit(fifo); 315 return 0; 316 } 317 318 static void 319 nvkm_fifo_preinit(struct nvkm_engine *engine) 320 { 321 nvkm_mc_reset(engine->subdev.device, NVKM_ENGINE_FIFO); 322 } 323 324 static int 325 nvkm_fifo_init(struct nvkm_engine *engine) 326 { 327 struct nvkm_fifo *fifo = nvkm_fifo(engine); 328 fifo->func->init(fifo); 329 return 0; 330 } 331 332 static void * 333 nvkm_fifo_dtor(struct nvkm_engine *engine) 334 { 335 struct nvkm_fifo *fifo = nvkm_fifo(engine); 336 void *data = fifo; 337 if (fifo->func->dtor) 338 data = fifo->func->dtor(fifo); 339 nvkm_event_fini(&fifo->kevent); 340 nvkm_event_fini(&fifo->cevent); 341 nvkm_event_fini(&fifo->uevent); 342 spin_lock_destroy(&fifo->lock); 343 return data; 344 } 345 346 static const struct nvkm_engine_func 347 nvkm_fifo = { 348 .dtor = nvkm_fifo_dtor, 349 .preinit = nvkm_fifo_preinit, 350 .oneinit = nvkm_fifo_oneinit, 351 .info = nvkm_fifo_info, 352 .init = nvkm_fifo_init, 353 .fini = nvkm_fifo_fini, 354 .intr = nvkm_fifo_intr, 355 .base.sclass = nvkm_fifo_class_get, 356 }; 357 358 int 359 nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device, 360 int index, int nr, struct nvkm_fifo *fifo) 361 { 362 int ret; 363 364 fifo->func = func; 365 INIT_LIST_HEAD(&fifo->chan); 366 spin_lock_init(&fifo->lock); 367 368 if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR)) 369 fifo->nr = NVKM_FIFO_CHID_NR; 370 else 371 fifo->nr = nr; 372 bitmap_clear(fifo->mask, 0, fifo->nr); 373 374 ret = nvkm_engine_ctor(&nvkm_fifo, device, index, true, &fifo->engine); 375 if (ret) 376 return ret; 377 378 if (func->uevent_init) { 379 ret = nvkm_event_init(&nvkm_fifo_uevent_func, 1, 1, 380 &fifo->uevent); 381 if (ret) 382 return ret; 383 } 384 385 ret = nvkm_event_init(&nvkm_fifo_cevent_func, 1, 1, &fifo->cevent); 386 if (ret) 387 return ret; 388 389 return nvkm_event_init(&nvkm_fifo_kevent_func, 1, nr, &fifo->kevent); 390 } 391