gpfifogk104.c 12 KB

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