nouveau_abi16.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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. */
  23. #include <nvif/client.h>
  24. #include <nvif/driver.h>
  25. #include <nvif/ioctl.h>
  26. #include <nvif/class.h>
  27. #include "nouveau_drm.h"
  28. #include "nouveau_dma.h"
  29. #include "nouveau_gem.h"
  30. #include "nouveau_chan.h"
  31. #include "nouveau_abi16.h"
  32. struct nouveau_abi16 *
  33. nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev)
  34. {
  35. struct nouveau_cli *cli = nouveau_cli(file_priv);
  36. mutex_lock(&cli->mutex);
  37. if (!cli->abi16) {
  38. struct nouveau_abi16 *abi16;
  39. cli->abi16 = abi16 = kzalloc(sizeof(*abi16), GFP_KERNEL);
  40. if (cli->abi16) {
  41. struct nv_device_v0 args = {
  42. .device = ~0ULL,
  43. };
  44. INIT_LIST_HEAD(&abi16->channels);
  45. /* allocate device object targeting client's default
  46. * device (ie. the one that belongs to the fd it
  47. * opened)
  48. */
  49. if (nvif_device_init(&cli->base.base, NULL,
  50. NOUVEAU_ABI16_DEVICE, NV_DEVICE,
  51. &args, sizeof(args),
  52. &abi16->device) == 0)
  53. return cli->abi16;
  54. kfree(cli->abi16);
  55. cli->abi16 = NULL;
  56. }
  57. mutex_unlock(&cli->mutex);
  58. }
  59. return cli->abi16;
  60. }
  61. int
  62. nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret)
  63. {
  64. struct nouveau_cli *cli = (void *)nvif_client(&abi16->device.base);
  65. mutex_unlock(&cli->mutex);
  66. return ret;
  67. }
  68. u16
  69. nouveau_abi16_swclass(struct nouveau_drm *drm)
  70. {
  71. switch (drm->device.info.family) {
  72. case NV_DEVICE_INFO_V0_TNT:
  73. return 0x006e;
  74. case NV_DEVICE_INFO_V0_CELSIUS:
  75. case NV_DEVICE_INFO_V0_KELVIN:
  76. case NV_DEVICE_INFO_V0_RANKINE:
  77. case NV_DEVICE_INFO_V0_CURIE:
  78. return 0x016e;
  79. case NV_DEVICE_INFO_V0_TESLA:
  80. return 0x506e;
  81. case NV_DEVICE_INFO_V0_FERMI:
  82. case NV_DEVICE_INFO_V0_KEPLER:
  83. case NV_DEVICE_INFO_V0_MAXWELL:
  84. return 0x906e;
  85. }
  86. return 0x0000;
  87. }
  88. static void
  89. nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
  90. struct nouveau_abi16_ntfy *ntfy)
  91. {
  92. nouveau_mm_free(&chan->heap, &ntfy->node);
  93. list_del(&ntfy->head);
  94. kfree(ntfy);
  95. }
  96. static void
  97. nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
  98. struct nouveau_abi16_chan *chan)
  99. {
  100. struct nouveau_abi16_ntfy *ntfy, *temp;
  101. /* wait for all activity to stop before releasing notify object, which
  102. * may be still in use */
  103. if (chan->chan && chan->ntfy)
  104. nouveau_channel_idle(chan->chan);
  105. /* cleanup notifier state */
  106. list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) {
  107. nouveau_abi16_ntfy_fini(chan, ntfy);
  108. }
  109. if (chan->ntfy) {
  110. nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma);
  111. nouveau_bo_unpin(chan->ntfy);
  112. drm_gem_object_unreference_unlocked(&chan->ntfy->gem);
  113. }
  114. if (chan->heap.block_size)
  115. nouveau_mm_fini(&chan->heap);
  116. /* destroy channel object, all children will be killed too */
  117. if (chan->chan) {
  118. abi16->handles &= ~(1ULL << (chan->chan->object->handle & 0xffff));
  119. nouveau_channel_del(&chan->chan);
  120. }
  121. list_del(&chan->head);
  122. kfree(chan);
  123. }
  124. void
  125. nouveau_abi16_fini(struct nouveau_abi16 *abi16)
  126. {
  127. struct nouveau_cli *cli = (void *)nvif_client(&abi16->device.base);
  128. struct nouveau_abi16_chan *chan, *temp;
  129. /* cleanup channels */
  130. list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
  131. nouveau_abi16_chan_fini(abi16, chan);
  132. }
  133. /* destroy the device object */
  134. nvif_device_fini(&abi16->device);
  135. kfree(cli->abi16);
  136. cli->abi16 = NULL;
  137. }
  138. int
  139. nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
  140. {
  141. struct nouveau_cli *cli = nouveau_cli(file_priv);
  142. struct nouveau_drm *drm = nouveau_drm(dev);
  143. struct nvif_device *device = &drm->device;
  144. struct nouveau_timer *ptimer = nvkm_timer(device);
  145. struct nouveau_graph *graph = nvkm_gr(device);
  146. struct drm_nouveau_getparam *getparam = data;
  147. switch (getparam->param) {
  148. case NOUVEAU_GETPARAM_CHIPSET_ID:
  149. getparam->value = device->info.chipset;
  150. break;
  151. case NOUVEAU_GETPARAM_PCI_VENDOR:
  152. if (nv_device_is_pci(nvkm_device(device)))
  153. getparam->value = dev->pdev->vendor;
  154. else
  155. getparam->value = 0;
  156. break;
  157. case NOUVEAU_GETPARAM_PCI_DEVICE:
  158. if (nv_device_is_pci(nvkm_device(device)))
  159. getparam->value = dev->pdev->device;
  160. else
  161. getparam->value = 0;
  162. break;
  163. case NOUVEAU_GETPARAM_BUS_TYPE:
  164. if (!nv_device_is_pci(nvkm_device(device)))
  165. getparam->value = 3;
  166. else
  167. if (drm_pci_device_is_agp(dev))
  168. getparam->value = 0;
  169. else
  170. if (!pci_is_pcie(dev->pdev))
  171. getparam->value = 1;
  172. else
  173. getparam->value = 2;
  174. break;
  175. case NOUVEAU_GETPARAM_FB_SIZE:
  176. getparam->value = drm->gem.vram_available;
  177. break;
  178. case NOUVEAU_GETPARAM_AGP_SIZE:
  179. getparam->value = drm->gem.gart_available;
  180. break;
  181. case NOUVEAU_GETPARAM_VM_VRAM_BASE:
  182. getparam->value = 0; /* deprecated */
  183. break;
  184. case NOUVEAU_GETPARAM_PTIMER_TIME:
  185. getparam->value = ptimer->read(ptimer);
  186. break;
  187. case NOUVEAU_GETPARAM_HAS_BO_USAGE:
  188. getparam->value = 1;
  189. break;
  190. case NOUVEAU_GETPARAM_HAS_PAGEFLIP:
  191. getparam->value = 1;
  192. break;
  193. case NOUVEAU_GETPARAM_GRAPH_UNITS:
  194. getparam->value = graph->units ? graph->units(graph) : 0;
  195. break;
  196. default:
  197. NV_PRINTK(debug, cli, "unknown parameter %lld\n", getparam->param);
  198. return -EINVAL;
  199. }
  200. return 0;
  201. }
  202. int
  203. nouveau_abi16_ioctl_setparam(ABI16_IOCTL_ARGS)
  204. {
  205. return -EINVAL;
  206. }
  207. int
  208. nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
  209. {
  210. struct drm_nouveau_channel_alloc *init = data;
  211. struct nouveau_cli *cli = nouveau_cli(file_priv);
  212. struct nouveau_drm *drm = nouveau_drm(dev);
  213. struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
  214. struct nouveau_abi16_chan *chan;
  215. struct nvif_device *device;
  216. int ret;
  217. if (unlikely(!abi16))
  218. return -ENOMEM;
  219. if (!drm->channel)
  220. return nouveau_abi16_put(abi16, -ENODEV);
  221. device = &abi16->device;
  222. /* hack to allow channel engine type specification on kepler */
  223. if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
  224. if (init->fb_ctxdma_handle != ~0)
  225. init->fb_ctxdma_handle = KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR;
  226. else
  227. init->fb_ctxdma_handle = init->tt_ctxdma_handle;
  228. /* allow flips to be executed if this is a graphics channel */
  229. init->tt_ctxdma_handle = 0;
  230. if (init->fb_ctxdma_handle == KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR)
  231. init->tt_ctxdma_handle = 1;
  232. }
  233. if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
  234. return nouveau_abi16_put(abi16, -EINVAL);
  235. /* allocate "abi16 channel" data and make up a handle for it */
  236. init->channel = __ffs64(~abi16->handles);
  237. if (~abi16->handles == 0)
  238. return nouveau_abi16_put(abi16, -ENOSPC);
  239. chan = kzalloc(sizeof(*chan), GFP_KERNEL);
  240. if (!chan)
  241. return nouveau_abi16_put(abi16, -ENOMEM);
  242. INIT_LIST_HEAD(&chan->notifiers);
  243. list_add(&chan->head, &abi16->channels);
  244. abi16->handles |= (1ULL << init->channel);
  245. /* create channel object and initialise dma and fence management */
  246. ret = nouveau_channel_new(drm, device,
  247. NOUVEAU_ABI16_CHAN(init->channel),
  248. init->fb_ctxdma_handle,
  249. init->tt_ctxdma_handle, &chan->chan);
  250. if (ret)
  251. goto done;
  252. if (device->info.family >= NV_DEVICE_INFO_V0_TESLA)
  253. init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
  254. NOUVEAU_GEM_DOMAIN_GART;
  255. else
  256. if (chan->chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM)
  257. init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
  258. else
  259. init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
  260. if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
  261. init->subchan[0].handle = 0x00000000;
  262. init->subchan[0].grclass = 0x0000;
  263. init->subchan[1].handle = chan->chan->nvsw.handle;
  264. init->subchan[1].grclass = 0x506e;
  265. init->nr_subchan = 2;
  266. }
  267. /* Named memory object area */
  268. ret = nouveau_gem_new(dev, PAGE_SIZE, 0, NOUVEAU_GEM_DOMAIN_GART,
  269. 0, 0, &chan->ntfy);
  270. if (ret == 0)
  271. ret = nouveau_bo_pin(chan->ntfy, TTM_PL_FLAG_TT, false);
  272. if (ret)
  273. goto done;
  274. if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
  275. ret = nouveau_bo_vma_add(chan->ntfy, cli->vm,
  276. &chan->ntfy_vma);
  277. if (ret)
  278. goto done;
  279. }
  280. ret = drm_gem_handle_create(file_priv, &chan->ntfy->gem,
  281. &init->notifier_handle);
  282. if (ret)
  283. goto done;
  284. ret = nouveau_mm_init(&chan->heap, 0, PAGE_SIZE, 1);
  285. done:
  286. if (ret)
  287. nouveau_abi16_chan_fini(abi16, chan);
  288. return nouveau_abi16_put(abi16, ret);
  289. }
  290. static struct nouveau_abi16_chan *
  291. nouveau_abi16_chan(struct nouveau_abi16 *abi16, int channel)
  292. {
  293. struct nouveau_abi16_chan *chan;
  294. list_for_each_entry(chan, &abi16->channels, head) {
  295. if (chan->chan->object->handle == NOUVEAU_ABI16_CHAN(channel))
  296. return chan;
  297. }
  298. return NULL;
  299. }
  300. int
  301. nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)
  302. {
  303. struct drm_nouveau_channel_free *req = data;
  304. struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
  305. struct nouveau_abi16_chan *chan;
  306. if (unlikely(!abi16))
  307. return -ENOMEM;
  308. chan = nouveau_abi16_chan(abi16, req->channel);
  309. if (!chan)
  310. return nouveau_abi16_put(abi16, -ENOENT);
  311. nouveau_abi16_chan_fini(abi16, chan);
  312. return nouveau_abi16_put(abi16, 0);
  313. }
  314. int
  315. nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
  316. {
  317. struct drm_nouveau_grobj_alloc *init = data;
  318. struct {
  319. struct nvif_ioctl_v0 ioctl;
  320. struct nvif_ioctl_new_v0 new;
  321. } args = {
  322. .ioctl.owner = NVIF_IOCTL_V0_OWNER_ANY,
  323. .ioctl.type = NVIF_IOCTL_V0_NEW,
  324. .ioctl.path_nr = 3,
  325. .ioctl.path[2] = NOUVEAU_ABI16_CLIENT,
  326. .ioctl.path[1] = NOUVEAU_ABI16_DEVICE,
  327. .ioctl.path[0] = NOUVEAU_ABI16_CHAN(init->channel),
  328. .new.route = NVDRM_OBJECT_ABI16,
  329. .new.handle = init->handle,
  330. .new.oclass = init->class,
  331. };
  332. struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
  333. struct nouveau_drm *drm = nouveau_drm(dev);
  334. struct nvif_client *client;
  335. int ret;
  336. if (unlikely(!abi16))
  337. return -ENOMEM;
  338. if (init->handle == ~0)
  339. return nouveau_abi16_put(abi16, -EINVAL);
  340. client = nvif_client(nvif_object(&abi16->device));
  341. /* compatibility with userspace that assumes 506e for all chipsets */
  342. if (init->class == 0x506e) {
  343. init->class = nouveau_abi16_swclass(drm);
  344. if (init->class == 0x906e)
  345. return nouveau_abi16_put(abi16, 0);
  346. }
  347. ret = nvif_client_ioctl(client, &args, sizeof(args));
  348. return nouveau_abi16_put(abi16, ret);
  349. }
  350. int
  351. nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
  352. {
  353. struct drm_nouveau_notifierobj_alloc *info = data;
  354. struct {
  355. struct nvif_ioctl_v0 ioctl;
  356. struct nvif_ioctl_new_v0 new;
  357. struct nv_dma_v0 ctxdma;
  358. } args = {
  359. .ioctl.owner = NVIF_IOCTL_V0_OWNER_ANY,
  360. .ioctl.type = NVIF_IOCTL_V0_NEW,
  361. .ioctl.path_nr = 3,
  362. .ioctl.path[2] = NOUVEAU_ABI16_CLIENT,
  363. .ioctl.path[1] = NOUVEAU_ABI16_DEVICE,
  364. .ioctl.path[0] = NOUVEAU_ABI16_CHAN(info->channel),
  365. .new.route = NVDRM_OBJECT_ABI16,
  366. .new.handle = info->handle,
  367. .new.oclass = NV_DMA_IN_MEMORY,
  368. };
  369. struct nouveau_drm *drm = nouveau_drm(dev);
  370. struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
  371. struct nouveau_abi16_chan *chan;
  372. struct nouveau_abi16_ntfy *ntfy;
  373. struct nvif_device *device = &abi16->device;
  374. struct nvif_client *client;
  375. int ret;
  376. if (unlikely(!abi16))
  377. return -ENOMEM;
  378. /* completely unnecessary for these chipsets... */
  379. if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI))
  380. return nouveau_abi16_put(abi16, -EINVAL);
  381. client = nvif_client(nvif_object(&abi16->device));
  382. chan = nouveau_abi16_chan(abi16, info->channel);
  383. if (!chan)
  384. return nouveau_abi16_put(abi16, -ENOENT);
  385. ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL);
  386. if (!ntfy)
  387. return nouveau_abi16_put(abi16, -ENOMEM);
  388. list_add(&ntfy->head, &chan->notifiers);
  389. ntfy->handle = info->handle;
  390. ret = nouveau_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
  391. &ntfy->node);
  392. if (ret)
  393. goto done;
  394. args.ctxdma.start = ntfy->node->offset;
  395. args.ctxdma.limit = ntfy->node->offset + ntfy->node->length - 1;
  396. if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
  397. args.ctxdma.target = NV_DMA_V0_TARGET_VM;
  398. args.ctxdma.access = NV_DMA_V0_ACCESS_VM;
  399. args.ctxdma.start += chan->ntfy_vma.offset;
  400. args.ctxdma.limit += chan->ntfy_vma.offset;
  401. } else
  402. if (drm->agp.stat == ENABLED) {
  403. args.ctxdma.target = NV_DMA_V0_TARGET_AGP;
  404. args.ctxdma.access = NV_DMA_V0_ACCESS_RDWR;
  405. args.ctxdma.start += drm->agp.base + chan->ntfy->bo.offset;
  406. args.ctxdma.limit += drm->agp.base + chan->ntfy->bo.offset;
  407. client->super = true;
  408. } else {
  409. args.ctxdma.target = NV_DMA_V0_TARGET_VM;
  410. args.ctxdma.access = NV_DMA_V0_ACCESS_RDWR;
  411. args.ctxdma.start += chan->ntfy->bo.offset;
  412. args.ctxdma.limit += chan->ntfy->bo.offset;
  413. }
  414. ret = nvif_client_ioctl(client, &args, sizeof(args));
  415. client->super = false;
  416. if (ret)
  417. goto done;
  418. info->offset = ntfy->node->offset;
  419. done:
  420. if (ret)
  421. nouveau_abi16_ntfy_fini(chan, ntfy);
  422. return nouveau_abi16_put(abi16, ret);
  423. }
  424. int
  425. nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
  426. {
  427. struct drm_nouveau_gpuobj_free *fini = data;
  428. struct {
  429. struct nvif_ioctl_v0 ioctl;
  430. struct nvif_ioctl_del del;
  431. } args = {
  432. .ioctl.owner = NVDRM_OBJECT_ABI16,
  433. .ioctl.type = NVIF_IOCTL_V0_DEL,
  434. .ioctl.path_nr = 4,
  435. .ioctl.path[3] = NOUVEAU_ABI16_CLIENT,
  436. .ioctl.path[2] = NOUVEAU_ABI16_DEVICE,
  437. .ioctl.path[1] = NOUVEAU_ABI16_CHAN(fini->channel),
  438. .ioctl.path[0] = fini->handle,
  439. };
  440. struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
  441. struct nouveau_abi16_chan *chan;
  442. struct nouveau_abi16_ntfy *ntfy;
  443. struct nvif_client *client;
  444. int ret;
  445. if (unlikely(!abi16))
  446. return -ENOMEM;
  447. chan = nouveau_abi16_chan(abi16, fini->channel);
  448. if (!chan)
  449. return nouveau_abi16_put(abi16, -ENOENT);
  450. client = nvif_client(nvif_object(&abi16->device));
  451. /* synchronize with the user channel and destroy the gpu object */
  452. nouveau_channel_idle(chan->chan);
  453. ret = nvif_client_ioctl(client, &args, sizeof(args));
  454. if (ret)
  455. return nouveau_abi16_put(abi16, ret);
  456. /* cleanup extra state if this object was a notifier */
  457. list_for_each_entry(ntfy, &chan->notifiers, head) {
  458. if (ntfy->handle == fini->handle) {
  459. nouveau_mm_free(&chan->heap, &ntfy->node);
  460. list_del(&ntfy->head);
  461. break;
  462. }
  463. }
  464. return nouveau_abi16_put(abi16, 0);
  465. }