gpfifogk104.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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 "changk104.h"
  25. #include <core/client.h>
  26. #include <core/gpuobj.h>
  27. #include <subdev/fb.h>
  28. #include <subdev/mmu.h>
  29. #include <subdev/timer.h>
  30. #include <nvif/class.h>
  31. #include <nvif/cla06f.h>
  32. #include <nvif/unpack.h>
  33. static int
  34. gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan)
  35. {
  36. struct gk104_fifo *fifo = chan->fifo;
  37. struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
  38. struct nvkm_device *device = subdev->device;
  39. struct nvkm_client *client = chan->base.object.client;
  40. int ret = 0;
  41. mutex_lock(&subdev->mutex);
  42. nvkm_wr32(device, 0x002634, chan->base.chid);
  43. if (nvkm_msec(device, 2000,
  44. if (!(nvkm_rd32(device, 0x002634) & 0x00100000))
  45. break;
  46. ) < 0) {
  47. nvkm_error(subdev, "channel %d [%s] kick timeout\n",
  48. chan->base.chid, client->name);
  49. ret = -ETIMEDOUT;
  50. }
  51. mutex_unlock(&subdev->mutex);
  52. return ret;
  53. }
  54. static u32
  55. gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine)
  56. {
  57. switch (engine->subdev.index) {
  58. case NVKM_ENGINE_SW :
  59. case NVKM_ENGINE_CE0 :
  60. case NVKM_ENGINE_CE1 :
  61. case NVKM_ENGINE_CE2 : return 0x0000;
  62. case NVKM_ENGINE_GR : return 0x0210;
  63. case NVKM_ENGINE_SEC : return 0x0220;
  64. case NVKM_ENGINE_MSPDEC: return 0x0250;
  65. case NVKM_ENGINE_MSPPP : return 0x0260;
  66. case NVKM_ENGINE_MSVLD : return 0x0270;
  67. case NVKM_ENGINE_VIC : return 0x0280;
  68. case NVKM_ENGINE_MSENC : return 0x0290;
  69. case NVKM_ENGINE_NVDEC : return 0x02100270;
  70. case NVKM_ENGINE_NVENC0: return 0x02100290;
  71. case NVKM_ENGINE_NVENC1: return 0x0210;
  72. default:
  73. WARN_ON(1);
  74. return 0;
  75. }
  76. }
  77. static int
  78. gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
  79. struct nvkm_engine *engine, bool suspend)
  80. {
  81. struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
  82. struct nvkm_gpuobj *inst = chan->base.inst;
  83. u32 offset = gk104_fifo_gpfifo_engine_addr(engine);
  84. int ret;
  85. ret = gk104_fifo_gpfifo_kick(chan);
  86. if (ret && suspend)
  87. return ret;
  88. if (offset) {
  89. nvkm_kmap(inst);
  90. nvkm_wo32(inst, (offset & 0xffff) + 0x00, 0x00000000);
  91. nvkm_wo32(inst, (offset & 0xffff) + 0x04, 0x00000000);
  92. if ((offset >>= 16)) {
  93. nvkm_wo32(inst, offset + 0x00, 0x00000000);
  94. nvkm_wo32(inst, offset + 0x04, 0x00000000);
  95. }
  96. nvkm_done(inst);
  97. }
  98. return ret;
  99. }
  100. static int
  101. gk104_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base,
  102. struct nvkm_engine *engine)
  103. {
  104. struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
  105. struct nvkm_gpuobj *inst = chan->base.inst;
  106. u32 offset = gk104_fifo_gpfifo_engine_addr(engine);
  107. if (offset) {
  108. u64 addr = chan->engn[engine->subdev.index].vma.offset;
  109. u32 datalo = lower_32_bits(addr) | 0x00000004;
  110. u32 datahi = upper_32_bits(addr);
  111. nvkm_kmap(inst);
  112. nvkm_wo32(inst, (offset & 0xffff) + 0x00, datalo);
  113. nvkm_wo32(inst, (offset & 0xffff) + 0x04, datahi);
  114. if ((offset >>= 16)) {
  115. nvkm_wo32(inst, offset + 0x00, datalo);
  116. nvkm_wo32(inst, offset + 0x04, datahi);
  117. }
  118. nvkm_done(inst);
  119. }
  120. return 0;
  121. }
  122. static void
  123. gk104_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base,
  124. struct nvkm_engine *engine)
  125. {
  126. struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
  127. nvkm_gpuobj_unmap(&chan->engn[engine->subdev.index].vma);
  128. nvkm_gpuobj_del(&chan->engn[engine->subdev.index].inst);
  129. }
  130. static int
  131. gk104_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base,
  132. struct nvkm_engine *engine,
  133. struct nvkm_object *object)
  134. {
  135. struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
  136. int engn = engine->subdev.index;
  137. int ret;
  138. if (!gk104_fifo_gpfifo_engine_addr(engine))
  139. return 0;
  140. ret = nvkm_object_bind(object, NULL, 0, &chan->engn[engn].inst);
  141. if (ret)
  142. return ret;
  143. return nvkm_gpuobj_map(chan->engn[engn].inst, chan->vm,
  144. NV_MEM_ACCESS_RW, &chan->engn[engn].vma);
  145. }
  146. static void
  147. gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
  148. {
  149. struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
  150. struct gk104_fifo *fifo = chan->fifo;
  151. struct nvkm_device *device = fifo->base.engine.subdev.device;
  152. u32 coff = chan->base.chid * 8;
  153. if (!list_empty(&chan->head)) {
  154. gk104_fifo_runlist_remove(fifo, chan);
  155. nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800);
  156. gk104_fifo_gpfifo_kick(chan);
  157. gk104_fifo_runlist_commit(fifo, chan->runl);
  158. }
  159. nvkm_wr32(device, 0x800000 + coff, 0x00000000);
  160. }
  161. static void
  162. gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base)
  163. {
  164. struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
  165. struct gk104_fifo *fifo = chan->fifo;
  166. struct nvkm_device *device = fifo->base.engine.subdev.device;
  167. u32 addr = chan->base.inst->addr >> 12;
  168. u32 coff = chan->base.chid * 8;
  169. nvkm_mask(device, 0x800004 + coff, 0x000f0000, chan->runl << 16);
  170. nvkm_wr32(device, 0x800000 + coff, 0x80000000 | addr);
  171. if (list_empty(&chan->head) && !chan->killed) {
  172. gk104_fifo_runlist_insert(fifo, chan);
  173. nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
  174. gk104_fifo_runlist_commit(fifo, chan->runl);
  175. nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400);
  176. }
  177. }
  178. static void *
  179. gk104_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base)
  180. {
  181. struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
  182. nvkm_vm_ref(NULL, &chan->vm, chan->pgd);
  183. nvkm_gpuobj_del(&chan->pgd);
  184. return chan;
  185. }
  186. static const struct nvkm_fifo_chan_func
  187. gk104_fifo_gpfifo_func = {
  188. .dtor = gk104_fifo_gpfifo_dtor,
  189. .init = gk104_fifo_gpfifo_init,
  190. .fini = gk104_fifo_gpfifo_fini,
  191. .ntfy = g84_fifo_chan_ntfy,
  192. .engine_ctor = gk104_fifo_gpfifo_engine_ctor,
  193. .engine_dtor = gk104_fifo_gpfifo_engine_dtor,
  194. .engine_init = gk104_fifo_gpfifo_engine_init,
  195. .engine_fini = gk104_fifo_gpfifo_engine_fini,
  196. };
  197. struct gk104_fifo_chan_func {
  198. u32 engine;
  199. u64 subdev;
  200. };
  201. static int
  202. gk104_fifo_gpfifo_new_(const struct gk104_fifo_chan_func *func,
  203. struct gk104_fifo *fifo, u32 *engmask, u16 *chid,
  204. u64 vm, u64 ioffset, u64 ilength,
  205. const struct nvkm_oclass *oclass,
  206. struct nvkm_object **pobject)
  207. {
  208. struct nvkm_device *device = fifo->base.engine.subdev.device;
  209. struct gk104_fifo_chan *chan;
  210. int runlist = -1, ret = -ENOSYS, i, j;
  211. u32 engines = 0, present = 0;
  212. u64 subdevs = 0;
  213. u64 usermem;
  214. /* Determine which downstream engines are present */
  215. for (i = 0; i < fifo->engine_nr; i++) {
  216. struct nvkm_engine *engine = fifo->engine[i].engine;
  217. if (engine) {
  218. u64 submask = BIT_ULL(engine->subdev.index);
  219. for (j = 0; func[j].subdev; j++) {
  220. if (func[j].subdev & submask) {
  221. present |= func[j].engine;
  222. break;
  223. }
  224. }
  225. if (!func[j].subdev)
  226. continue;
  227. if (runlist < 0 && (*engmask & present))
  228. runlist = fifo->engine[i].runl;
  229. if (runlist == fifo->engine[i].runl) {
  230. engines |= func[j].engine;
  231. subdevs |= func[j].subdev;
  232. }
  233. }
  234. }
  235. /* Just an engine mask query? All done here! */
  236. if (!*engmask) {
  237. *engmask = present;
  238. return nvkm_object_new(oclass, NULL, 0, pobject);
  239. }
  240. /* No runlist? No supported engines. */
  241. *engmask = present;
  242. if (runlist < 0)
  243. return -ENODEV;
  244. *engmask = engines;
  245. /* Allocate the channel. */
  246. if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
  247. return -ENOMEM;
  248. *pobject = &chan->base.object;
  249. chan->fifo = fifo;
  250. chan->runl = runlist;
  251. INIT_LIST_HEAD(&chan->head);
  252. ret = nvkm_fifo_chan_ctor(&gk104_fifo_gpfifo_func, &fifo->base,
  253. 0x1000, 0x1000, true, vm, 0, subdevs,
  254. 1, fifo->user.bar.offset, 0x200,
  255. oclass, &chan->base);
  256. if (ret)
  257. return ret;
  258. *chid = chan->base.chid;
  259. /* Page directory. */
  260. ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &chan->pgd);
  261. if (ret)
  262. return ret;
  263. nvkm_kmap(chan->base.inst);
  264. nvkm_wo32(chan->base.inst, 0x0200, lower_32_bits(chan->pgd->addr));
  265. nvkm_wo32(chan->base.inst, 0x0204, upper_32_bits(chan->pgd->addr));
  266. nvkm_wo32(chan->base.inst, 0x0208, 0xffffffff);
  267. nvkm_wo32(chan->base.inst, 0x020c, 0x000000ff);
  268. nvkm_done(chan->base.inst);
  269. ret = nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd);
  270. if (ret)
  271. return ret;
  272. /* Clear channel control registers. */
  273. usermem = chan->base.chid * 0x200;
  274. ilength = order_base_2(ilength / 8);
  275. nvkm_kmap(fifo->user.mem);
  276. for (i = 0; i < 0x200; i += 4)
  277. nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000);
  278. nvkm_done(fifo->user.mem);
  279. usermem = nvkm_memory_addr(fifo->user.mem) + usermem;
  280. /* RAMFC */
  281. nvkm_kmap(chan->base.inst);
  282. nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem));
  283. nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem));
  284. nvkm_wo32(chan->base.inst, 0x10, 0x0000face);
  285. nvkm_wo32(chan->base.inst, 0x30, 0xfffff902);
  286. nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset));
  287. nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) |
  288. (ilength << 16));
  289. nvkm_wo32(chan->base.inst, 0x84, 0x20400000);
  290. nvkm_wo32(chan->base.inst, 0x94, 0x30000001);
  291. nvkm_wo32(chan->base.inst, 0x9c, 0x00000100);
  292. nvkm_wo32(chan->base.inst, 0xac, 0x0000001f);
  293. nvkm_wo32(chan->base.inst, 0xe8, chan->base.chid);
  294. nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000);
  295. nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */
  296. nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */
  297. nvkm_done(chan->base.inst);
  298. return 0;
  299. }
  300. static const struct gk104_fifo_chan_func
  301. gk104_fifo_gpfifo[] = {
  302. { NVA06F_V0_ENGINE_SW | NVA06F_V0_ENGINE_GR,
  303. BIT_ULL(NVKM_ENGINE_SW) | BIT_ULL(NVKM_ENGINE_GR)
  304. },
  305. { NVA06F_V0_ENGINE_SEC , BIT_ULL(NVKM_ENGINE_SEC ) },
  306. { NVA06F_V0_ENGINE_MSVLD , BIT_ULL(NVKM_ENGINE_MSVLD ) },
  307. { NVA06F_V0_ENGINE_MSPDEC, BIT_ULL(NVKM_ENGINE_MSPDEC) },
  308. { NVA06F_V0_ENGINE_MSPPP , BIT_ULL(NVKM_ENGINE_MSPPP ) },
  309. { NVA06F_V0_ENGINE_MSENC , BIT_ULL(NVKM_ENGINE_MSENC ) },
  310. { NVA06F_V0_ENGINE_VIC , BIT_ULL(NVKM_ENGINE_VIC ) },
  311. { NVA06F_V0_ENGINE_NVDEC , BIT_ULL(NVKM_ENGINE_NVDEC ) },
  312. { NVA06F_V0_ENGINE_NVENC0, BIT_ULL(NVKM_ENGINE_NVENC0) },
  313. { NVA06F_V0_ENGINE_NVENC1, BIT_ULL(NVKM_ENGINE_NVENC1) },
  314. { NVA06F_V0_ENGINE_CE0 , BIT_ULL(NVKM_ENGINE_CE0 ) },
  315. { NVA06F_V0_ENGINE_CE1 , BIT_ULL(NVKM_ENGINE_CE1 ) },
  316. { NVA06F_V0_ENGINE_CE2 , BIT_ULL(NVKM_ENGINE_CE2 ) },
  317. {}
  318. };
  319. int
  320. gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
  321. void *data, u32 size, struct nvkm_object **pobject)
  322. {
  323. struct nvkm_object *parent = oclass->parent;
  324. union {
  325. struct kepler_channel_gpfifo_a_v0 v0;
  326. } *args = data;
  327. struct gk104_fifo *fifo = gk104_fifo(base);
  328. int ret = -ENOSYS;
  329. nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
  330. if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
  331. nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx "
  332. "ioffset %016llx ilength %08x engine %08x\n",
  333. args->v0.version, args->v0.vm, args->v0.ioffset,
  334. args->v0.ilength, args->v0.engines);
  335. return gk104_fifo_gpfifo_new_(gk104_fifo_gpfifo, fifo,
  336. &args->v0.engines,
  337. &args->v0.chid,
  338. args->v0.vm,
  339. args->v0.ioffset,
  340. args->v0.ilength,
  341. oclass, pobject);
  342. }
  343. return ret;
  344. }
  345. const struct nvkm_fifo_chan_oclass
  346. gk104_fifo_gpfifo_oclass = {
  347. .base.oclass = KEPLER_CHANNEL_GPFIFO_A,
  348. .base.minver = 0,
  349. .base.maxver = 0,
  350. .ctor = gk104_fifo_gpfifo_new,
  351. };