nouveau.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  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 <stdio.h>
  25. #include <stdlib.h>
  26. #include <stdint.h>
  27. #include <string.h>
  28. #include <strings.h>
  29. #include <stdbool.h>
  30. #include <assert.h>
  31. #include <errno.h>
  32. #include <fcntl.h>
  33. #include <xf86drm.h>
  34. #include <xf86atomic.h>
  35. #include "libdrm_macros.h"
  36. #include "libdrm_lists.h"
  37. #include "nouveau_drm.h"
  38. #include "nouveau.h"
  39. #include "private.h"
  40. #include "nvif/class.h"
  41. #include "nvif/cl0080.h"
  42. #include "nvif/ioctl.h"
  43. #include "nvif/unpack.h"
  44. drm_private FILE *nouveau_out = NULL;
  45. drm_private uint32_t nouveau_debug = 0;
  46. static void
  47. debug_init(void)
  48. {
  49. static bool once = false;
  50. char *debug, *out;
  51. if (once)
  52. return;
  53. once = true;
  54. debug = getenv("NOUVEAU_LIBDRM_DEBUG");
  55. if (debug) {
  56. int n = strtol(debug, NULL, 0);
  57. if (n >= 0)
  58. nouveau_debug = n;
  59. }
  60. nouveau_out = stderr;
  61. out = getenv("NOUVEAU_LIBDRM_OUT");
  62. if (out) {
  63. FILE *fout = fopen(out, "w");
  64. if (fout)
  65. nouveau_out = fout;
  66. }
  67. }
  68. static int
  69. nouveau_object_ioctl(struct nouveau_object *obj, void *data, uint32_t size)
  70. {
  71. struct nouveau_drm *drm = nouveau_drm(obj);
  72. union {
  73. struct nvif_ioctl_v0 v0;
  74. } *args = data;
  75. uint32_t argc = size;
  76. int ret = -ENOSYS;
  77. if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
  78. if (!obj->length) {
  79. if (obj != &drm->client)
  80. args->v0.object = (unsigned long)(void *)obj;
  81. else
  82. args->v0.object = 0;
  83. args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
  84. args->v0.route = 0x00;
  85. } else {
  86. args->v0.route = 0xff;
  87. args->v0.token = obj->handle;
  88. }
  89. } else
  90. return ret;
  91. return drmCommandWriteRead(drm->fd, DRM_NOUVEAU_NVIF, args, argc);
  92. }
  93. drm_public int
  94. nouveau_object_mthd(struct nouveau_object *obj,
  95. uint32_t mthd, void *data, uint32_t size)
  96. {
  97. struct nouveau_drm *drm = nouveau_drm(obj);
  98. struct {
  99. struct nvif_ioctl_v0 ioctl;
  100. struct nvif_ioctl_mthd_v0 mthd;
  101. } *args;
  102. uint32_t argc = sizeof(*args) + size;
  103. uint8_t stack[128];
  104. int ret;
  105. if (!drm->nvif)
  106. return -ENOSYS;
  107. if (argc > sizeof(stack)) {
  108. if (!(args = malloc(argc)))
  109. return -ENOMEM;
  110. } else {
  111. args = (void *)stack;
  112. }
  113. args->ioctl.version = 0;
  114. args->ioctl.type = NVIF_IOCTL_V0_MTHD;
  115. args->mthd.version = 0;
  116. args->mthd.method = mthd;
  117. memcpy(args->mthd.data, data, size);
  118. ret = nouveau_object_ioctl(obj, args, argc);
  119. memcpy(data, args->mthd.data, size);
  120. if (args != (void *)stack)
  121. free(args);
  122. return ret;
  123. }
  124. drm_public void
  125. nouveau_object_sclass_put(struct nouveau_sclass **psclass)
  126. {
  127. free(*psclass);
  128. *psclass = NULL;
  129. }
  130. drm_public int
  131. nouveau_object_sclass_get(struct nouveau_object *obj,
  132. struct nouveau_sclass **psclass)
  133. {
  134. struct nouveau_drm *drm = nouveau_drm(obj);
  135. struct {
  136. struct nvif_ioctl_v0 ioctl;
  137. struct nvif_ioctl_sclass_v0 sclass;
  138. } *args = NULL;
  139. struct nouveau_sclass *sclass;
  140. int ret, cnt = 0, i;
  141. uint32_t size;
  142. if (!drm->nvif)
  143. return abi16_sclass(obj, psclass);
  144. while (1) {
  145. size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
  146. if (!(args = malloc(size)))
  147. return -ENOMEM;
  148. args->ioctl.version = 0;
  149. args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
  150. args->sclass.version = 0;
  151. args->sclass.count = cnt;
  152. ret = nouveau_object_ioctl(obj, args, size);
  153. if (ret == 0 && args->sclass.count <= cnt)
  154. break;
  155. cnt = args->sclass.count;
  156. free(args);
  157. if (ret != 0)
  158. return ret;
  159. }
  160. if ((sclass = calloc(args->sclass.count, sizeof(*sclass)))) {
  161. for (i = 0; i < args->sclass.count; i++) {
  162. sclass[i].oclass = args->sclass.oclass[i].oclass;
  163. sclass[i].minver = args->sclass.oclass[i].minver;
  164. sclass[i].maxver = args->sclass.oclass[i].maxver;
  165. }
  166. *psclass = sclass;
  167. ret = args->sclass.count;
  168. } else {
  169. ret = -ENOMEM;
  170. }
  171. free(args);
  172. return ret;
  173. }
  174. drm_public int
  175. nouveau_object_mclass(struct nouveau_object *obj,
  176. const struct nouveau_mclass *mclass)
  177. {
  178. struct nouveau_sclass *sclass;
  179. int ret = -ENODEV;
  180. int cnt, i, j;
  181. cnt = nouveau_object_sclass_get(obj, &sclass);
  182. if (cnt < 0)
  183. return cnt;
  184. for (i = 0; ret < 0 && mclass[i].oclass; i++) {
  185. for (j = 0; j < cnt; j++) {
  186. if (mclass[i].oclass == sclass[j].oclass &&
  187. mclass[i].version >= sclass[j].minver &&
  188. mclass[i].version <= sclass[j].maxver) {
  189. ret = i;
  190. break;
  191. }
  192. }
  193. }
  194. nouveau_object_sclass_put(&sclass);
  195. return ret;
  196. }
  197. static void
  198. nouveau_object_fini(struct nouveau_object *obj)
  199. {
  200. struct {
  201. struct nvif_ioctl_v0 ioctl;
  202. struct nvif_ioctl_del del;
  203. } args = {
  204. .ioctl.type = NVIF_IOCTL_V0_DEL,
  205. };
  206. if (obj->data) {
  207. abi16_delete(obj);
  208. free(obj->data);
  209. obj->data = NULL;
  210. return;
  211. }
  212. nouveau_object_ioctl(obj, &args, sizeof(args));
  213. }
  214. static int
  215. nouveau_object_init(struct nouveau_object *parent, uint32_t handle,
  216. int32_t oclass, void *data, uint32_t size,
  217. struct nouveau_object *obj)
  218. {
  219. struct nouveau_drm *drm = nouveau_drm(parent);
  220. struct {
  221. struct nvif_ioctl_v0 ioctl;
  222. struct nvif_ioctl_new_v0 new;
  223. } *args;
  224. uint32_t argc = sizeof(*args) + size;
  225. int (*func)(struct nouveau_object *);
  226. int ret = -ENOSYS;
  227. obj->parent = parent;
  228. obj->handle = handle;
  229. obj->oclass = oclass;
  230. obj->length = 0;
  231. obj->data = NULL;
  232. if (!abi16_object(obj, &func) && drm->nvif) {
  233. if (!(args = malloc(argc)))
  234. return -ENOMEM;
  235. args->ioctl.version = 0;
  236. args->ioctl.type = NVIF_IOCTL_V0_NEW;
  237. args->new.version = 0;
  238. args->new.route = NVIF_IOCTL_V0_ROUTE_NVIF;
  239. args->new.token = (unsigned long)(void *)obj;
  240. args->new.object = (unsigned long)(void *)obj;
  241. args->new.handle = handle;
  242. args->new.oclass = oclass;
  243. memcpy(args->new.data, data, size);
  244. ret = nouveau_object_ioctl(parent, args, argc);
  245. memcpy(data, args->new.data, size);
  246. free(args);
  247. } else
  248. if (func) {
  249. obj->length = size ? size : sizeof(struct nouveau_object *);
  250. if (!(obj->data = malloc(obj->length)))
  251. return -ENOMEM;
  252. if (data)
  253. memcpy(obj->data, data, obj->length);
  254. *(struct nouveau_object **)obj->data = obj;
  255. ret = func(obj);
  256. }
  257. if (ret) {
  258. nouveau_object_fini(obj);
  259. return ret;
  260. }
  261. return 0;
  262. }
  263. drm_public int
  264. nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
  265. uint32_t oclass, void *data, uint32_t length,
  266. struct nouveau_object **pobj)
  267. {
  268. struct nouveau_object *obj;
  269. int ret;
  270. if (!(obj = malloc(sizeof(*obj))))
  271. return -ENOMEM;
  272. ret = nouveau_object_init(parent, handle, oclass, data, length, obj);
  273. if (ret) {
  274. free(obj);
  275. return ret;
  276. }
  277. *pobj = obj;
  278. return 0;
  279. }
  280. drm_public void
  281. nouveau_object_del(struct nouveau_object **pobj)
  282. {
  283. struct nouveau_object *obj = *pobj;
  284. if (obj) {
  285. nouveau_object_fini(obj);
  286. free(obj);
  287. *pobj = NULL;
  288. }
  289. }
  290. drm_public void
  291. nouveau_drm_del(struct nouveau_drm **pdrm)
  292. {
  293. free(*pdrm);
  294. *pdrm = NULL;
  295. }
  296. drm_public int
  297. nouveau_drm_new(int fd, struct nouveau_drm **pdrm)
  298. {
  299. struct nouveau_drm *drm;
  300. drmVersionPtr ver;
  301. debug_init();
  302. if (!(drm = calloc(1, sizeof(*drm))))
  303. return -ENOMEM;
  304. drm->fd = fd;
  305. if (!(ver = drmGetVersion(fd))) {
  306. nouveau_drm_del(&drm);
  307. return -EINVAL;
  308. }
  309. *pdrm = drm;
  310. drm->version = (ver->version_major << 24) |
  311. (ver->version_minor << 8) |
  312. ver->version_patchlevel;
  313. drm->nvif = (drm->version >= 0x01000301);
  314. drmFreeVersion(ver);
  315. return 0;
  316. }
  317. /* this is the old libdrm's version of nouveau_device_wrap(), the symbol
  318. * is kept here to prevent AIGLX from crashing if the DDX is linked against
  319. * the new libdrm, but the DRI driver against the old
  320. */
  321. drm_public int
  322. nouveau_device_open_existing(struct nouveau_device **pdev, int close, int fd,
  323. drm_context_t ctx)
  324. {
  325. return -EACCES;
  326. }
  327. drm_public int
  328. nouveau_device_new(struct nouveau_object *parent, int32_t oclass,
  329. void *data, uint32_t size, struct nouveau_device **pdev)
  330. {
  331. struct nv_device_info_v0 info = {};
  332. union {
  333. struct nv_device_v0 v0;
  334. } *args = data;
  335. uint32_t argc = size;
  336. struct nouveau_drm *drm = nouveau_drm(parent);
  337. struct nouveau_device_priv *nvdev;
  338. struct nouveau_device *dev;
  339. uint64_t v;
  340. char *tmp;
  341. int ret = -ENOSYS;
  342. if (oclass != NV_DEVICE ||
  343. nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))
  344. return ret;
  345. if (!(nvdev = calloc(1, sizeof(*nvdev))))
  346. return -ENOMEM;
  347. dev = *pdev = &nvdev->base;
  348. dev->fd = -1;
  349. if (drm->nvif) {
  350. ret = nouveau_object_init(parent, 0, oclass, args, argc,
  351. &dev->object);
  352. if (ret)
  353. goto done;
  354. info.version = 0;
  355. ret = nouveau_object_mthd(&dev->object, NV_DEVICE_V0_INFO,
  356. &info, sizeof(info));
  357. if (ret)
  358. goto done;
  359. nvdev->base.chipset = info.chipset;
  360. nvdev->have_bo_usage = true;
  361. } else
  362. if (args->v0.device == ~0ULL) {
  363. nvdev->base.object.parent = &drm->client;
  364. nvdev->base.object.handle = ~0ULL;
  365. nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS;
  366. nvdev->base.object.length = ~0;
  367. ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &v);
  368. if (ret)
  369. goto done;
  370. nvdev->base.chipset = v;
  371. ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &v);
  372. if (ret == 0)
  373. nvdev->have_bo_usage = (v != 0);
  374. } else
  375. return -ENOSYS;
  376. ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &v);
  377. if (ret)
  378. goto done;
  379. nvdev->base.vram_size = v;
  380. ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &v);
  381. if (ret)
  382. goto done;
  383. nvdev->base.gart_size = v;
  384. tmp = getenv("NOUVEAU_LIBDRM_VRAM_LIMIT_PERCENT");
  385. if (tmp)
  386. nvdev->vram_limit_percent = atoi(tmp);
  387. else
  388. nvdev->vram_limit_percent = 80;
  389. nvdev->base.vram_limit =
  390. (nvdev->base.vram_size * nvdev->vram_limit_percent) / 100;
  391. tmp = getenv("NOUVEAU_LIBDRM_GART_LIMIT_PERCENT");
  392. if (tmp)
  393. nvdev->gart_limit_percent = atoi(tmp);
  394. else
  395. nvdev->gart_limit_percent = 80;
  396. nvdev->base.gart_limit =
  397. (nvdev->base.gart_size * nvdev->gart_limit_percent) / 100;
  398. ret = pthread_mutex_init(&nvdev->lock, NULL);
  399. DRMINITLISTHEAD(&nvdev->bo_list);
  400. done:
  401. if (ret)
  402. nouveau_device_del(pdev);
  403. return ret;
  404. }
  405. drm_public int
  406. nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
  407. {
  408. struct nouveau_drm *drm;
  409. struct nouveau_device_priv *nvdev;
  410. int ret;
  411. ret = nouveau_drm_new(fd, &drm);
  412. if (ret)
  413. return ret;
  414. drm->nvif = false;
  415. ret = nouveau_device_new(&drm->client, NV_DEVICE,
  416. &(struct nv_device_v0) {
  417. .device = ~0ULL,
  418. }, sizeof(struct nv_device_v0), pdev);
  419. if (ret) {
  420. nouveau_drm_del(&drm);
  421. return ret;
  422. }
  423. nvdev = nouveau_device(*pdev);
  424. nvdev->base.fd = drm->fd;
  425. nvdev->base.drm_version = drm->version;
  426. nvdev->close = close;
  427. return 0;
  428. }
  429. drm_public int
  430. nouveau_device_open(const char *busid, struct nouveau_device **pdev)
  431. {
  432. int ret = -ENODEV, fd = drmOpen("nouveau", busid);
  433. if (fd >= 0) {
  434. ret = nouveau_device_wrap(fd, 1, pdev);
  435. if (ret)
  436. drmClose(fd);
  437. }
  438. return ret;
  439. }
  440. drm_public void
  441. nouveau_device_del(struct nouveau_device **pdev)
  442. {
  443. struct nouveau_device_priv *nvdev = nouveau_device(*pdev);
  444. if (nvdev) {
  445. free(nvdev->client);
  446. pthread_mutex_destroy(&nvdev->lock);
  447. if (nvdev->base.fd >= 0) {
  448. struct nouveau_drm *drm =
  449. nouveau_drm(&nvdev->base.object);
  450. nouveau_drm_del(&drm);
  451. if (nvdev->close)
  452. drmClose(nvdev->base.fd);
  453. }
  454. free(nvdev);
  455. *pdev = NULL;
  456. }
  457. }
  458. drm_public int
  459. nouveau_getparam(struct nouveau_device *dev, uint64_t param, uint64_t *value)
  460. {
  461. struct nouveau_drm *drm = nouveau_drm(&dev->object);
  462. struct drm_nouveau_getparam r = { .param = param };
  463. int fd = drm->fd, ret =
  464. drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r));
  465. *value = r.value;
  466. return ret;
  467. }
  468. drm_public int
  469. nouveau_setparam(struct nouveau_device *dev, uint64_t param, uint64_t value)
  470. {
  471. struct nouveau_drm *drm = nouveau_drm(&dev->object);
  472. struct drm_nouveau_setparam r = { .param = param, .value = value };
  473. return drmCommandWrite(drm->fd, DRM_NOUVEAU_SETPARAM, &r, sizeof(r));
  474. }
  475. drm_public int
  476. nouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient)
  477. {
  478. struct nouveau_device_priv *nvdev = nouveau_device(dev);
  479. struct nouveau_client_priv *pcli;
  480. int id = 0, i, ret = -ENOMEM;
  481. uint32_t *clients;
  482. pthread_mutex_lock(&nvdev->lock);
  483. for (i = 0; i < nvdev->nr_client; i++) {
  484. id = ffs(nvdev->client[i]) - 1;
  485. if (id >= 0)
  486. goto out;
  487. }
  488. clients = realloc(nvdev->client, sizeof(uint32_t) * (i + 1));
  489. if (!clients)
  490. goto unlock;
  491. nvdev->client = clients;
  492. nvdev->client[i] = 0;
  493. nvdev->nr_client++;
  494. out:
  495. pcli = calloc(1, sizeof(*pcli));
  496. if (pcli) {
  497. nvdev->client[i] |= (1 << id);
  498. pcli->base.device = dev;
  499. pcli->base.id = (i * 32) + id;
  500. ret = 0;
  501. }
  502. *pclient = &pcli->base;
  503. unlock:
  504. pthread_mutex_unlock(&nvdev->lock);
  505. return ret;
  506. }
  507. drm_public void
  508. nouveau_client_del(struct nouveau_client **pclient)
  509. {
  510. struct nouveau_client_priv *pcli = nouveau_client(*pclient);
  511. struct nouveau_device_priv *nvdev;
  512. if (pcli) {
  513. int id = pcli->base.id;
  514. nvdev = nouveau_device(pcli->base.device);
  515. pthread_mutex_lock(&nvdev->lock);
  516. nvdev->client[id / 32] &= ~(1 << (id % 32));
  517. pthread_mutex_unlock(&nvdev->lock);
  518. free(pcli->kref);
  519. free(pcli);
  520. }
  521. }
  522. static void
  523. nouveau_bo_del(struct nouveau_bo *bo)
  524. {
  525. struct nouveau_drm *drm = nouveau_drm(&bo->device->object);
  526. struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
  527. struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
  528. if (nvbo->head.next) {
  529. pthread_mutex_lock(&nvdev->lock);
  530. if (atomic_read(&nvbo->refcnt) == 0) {
  531. DRMLISTDEL(&nvbo->head);
  532. /*
  533. * This bo has to be closed with the lock held because
  534. * gem handles are not refcounted. If a shared bo is
  535. * closed and re-opened in another thread a race
  536. * against DRM_IOCTL_GEM_OPEN or drmPrimeFDToHandle
  537. * might cause the bo to be closed accidentally while
  538. * re-importing.
  539. */
  540. drmCloseBufferHandle(drm->fd, bo->handle);
  541. }
  542. pthread_mutex_unlock(&nvdev->lock);
  543. } else {
  544. drmCloseBufferHandle(drm->fd, bo->handle);
  545. }
  546. if (bo->map)
  547. drm_munmap(bo->map, bo->size);
  548. free(nvbo);
  549. }
  550. drm_public int
  551. nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, uint32_t align,
  552. uint64_t size, union nouveau_bo_config *config,
  553. struct nouveau_bo **pbo)
  554. {
  555. struct nouveau_bo_priv *nvbo = calloc(1, sizeof(*nvbo));
  556. struct nouveau_bo *bo = &nvbo->base;
  557. int ret;
  558. if (!nvbo)
  559. return -ENOMEM;
  560. atomic_set(&nvbo->refcnt, 1);
  561. bo->device = dev;
  562. bo->flags = flags;
  563. bo->size = size;
  564. ret = abi16_bo_init(bo, align, config);
  565. if (ret) {
  566. free(nvbo);
  567. return ret;
  568. }
  569. *pbo = bo;
  570. return 0;
  571. }
  572. static int
  573. nouveau_bo_wrap_locked(struct nouveau_device *dev, uint32_t handle,
  574. struct nouveau_bo **pbo, int name)
  575. {
  576. struct nouveau_drm *drm = nouveau_drm(&dev->object);
  577. struct nouveau_device_priv *nvdev = nouveau_device(dev);
  578. struct drm_nouveau_gem_info req = { .handle = handle };
  579. struct nouveau_bo_priv *nvbo;
  580. int ret;
  581. DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) {
  582. if (nvbo->base.handle == handle) {
  583. if (atomic_inc_return(&nvbo->refcnt) == 1) {
  584. /*
  585. * Uh oh, this bo is dead and someone else
  586. * will free it, but because refcnt is
  587. * now non-zero fortunately they won't
  588. * call the ioctl to close the bo.
  589. *
  590. * Remove this bo from the list so other
  591. * calls to nouveau_bo_wrap_locked will
  592. * see our replacement nvbo.
  593. */
  594. DRMLISTDEL(&nvbo->head);
  595. if (!name)
  596. name = nvbo->name;
  597. break;
  598. }
  599. *pbo = &nvbo->base;
  600. return 0;
  601. }
  602. }
  603. ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_GEM_INFO,
  604. &req, sizeof(req));
  605. if (ret)
  606. return ret;
  607. nvbo = calloc(1, sizeof(*nvbo));
  608. if (nvbo) {
  609. atomic_set(&nvbo->refcnt, 1);
  610. nvbo->base.device = dev;
  611. abi16_bo_info(&nvbo->base, &req);
  612. nvbo->name = name;
  613. DRMLISTADD(&nvbo->head, &nvdev->bo_list);
  614. *pbo = &nvbo->base;
  615. return 0;
  616. }
  617. return -ENOMEM;
  618. }
  619. static void
  620. nouveau_nvbo_make_global(struct nouveau_bo_priv *nvbo)
  621. {
  622. if (!nvbo->head.next) {
  623. struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
  624. pthread_mutex_lock(&nvdev->lock);
  625. if (!nvbo->head.next)
  626. DRMLISTADD(&nvbo->head, &nvdev->bo_list);
  627. pthread_mutex_unlock(&nvdev->lock);
  628. }
  629. }
  630. drm_public void
  631. nouveau_bo_make_global(struct nouveau_bo *bo)
  632. {
  633. struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
  634. nouveau_nvbo_make_global(nvbo);
  635. }
  636. drm_public int
  637. nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle,
  638. struct nouveau_bo **pbo)
  639. {
  640. struct nouveau_device_priv *nvdev = nouveau_device(dev);
  641. int ret;
  642. pthread_mutex_lock(&nvdev->lock);
  643. ret = nouveau_bo_wrap_locked(dev, handle, pbo, 0);
  644. pthread_mutex_unlock(&nvdev->lock);
  645. return ret;
  646. }
  647. drm_public int
  648. nouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name,
  649. struct nouveau_bo **pbo)
  650. {
  651. struct nouveau_drm *drm = nouveau_drm(&dev->object);
  652. struct nouveau_device_priv *nvdev = nouveau_device(dev);
  653. struct nouveau_bo_priv *nvbo;
  654. struct drm_gem_open req = { .name = name };
  655. int ret;
  656. pthread_mutex_lock(&nvdev->lock);
  657. DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) {
  658. if (nvbo->name == name) {
  659. ret = nouveau_bo_wrap_locked(dev, nvbo->base.handle,
  660. pbo, name);
  661. pthread_mutex_unlock(&nvdev->lock);
  662. return ret;
  663. }
  664. }
  665. ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &req);
  666. if (ret == 0) {
  667. ret = nouveau_bo_wrap_locked(dev, req.handle, pbo, name);
  668. }
  669. pthread_mutex_unlock(&nvdev->lock);
  670. return ret;
  671. }
  672. drm_public int
  673. nouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name)
  674. {
  675. struct drm_gem_flink req = { .handle = bo->handle };
  676. struct nouveau_drm *drm = nouveau_drm(&bo->device->object);
  677. struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
  678. *name = nvbo->name;
  679. if (!*name) {
  680. int ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_FLINK, &req);
  681. if (ret) {
  682. *name = 0;
  683. return ret;
  684. }
  685. nvbo->name = *name = req.name;
  686. nouveau_nvbo_make_global(nvbo);
  687. }
  688. return 0;
  689. }
  690. drm_public void
  691. nouveau_bo_ref(struct nouveau_bo *bo, struct nouveau_bo **pref)
  692. {
  693. struct nouveau_bo *ref = *pref;
  694. if (bo) {
  695. atomic_inc(&nouveau_bo(bo)->refcnt);
  696. }
  697. if (ref) {
  698. if (atomic_dec_and_test(&nouveau_bo(ref)->refcnt))
  699. nouveau_bo_del(ref);
  700. }
  701. *pref = bo;
  702. }
  703. drm_public int
  704. nouveau_bo_prime_handle_ref(struct nouveau_device *dev, int prime_fd,
  705. struct nouveau_bo **bo)
  706. {
  707. struct nouveau_drm *drm = nouveau_drm(&dev->object);
  708. struct nouveau_device_priv *nvdev = nouveau_device(dev);
  709. int ret;
  710. unsigned int handle;
  711. nouveau_bo_ref(NULL, bo);
  712. pthread_mutex_lock(&nvdev->lock);
  713. ret = drmPrimeFDToHandle(drm->fd, prime_fd, &handle);
  714. if (ret == 0) {
  715. ret = nouveau_bo_wrap_locked(dev, handle, bo, 0);
  716. }
  717. pthread_mutex_unlock(&nvdev->lock);
  718. return ret;
  719. }
  720. drm_public int
  721. nouveau_bo_set_prime(struct nouveau_bo *bo, int *prime_fd)
  722. {
  723. struct nouveau_drm *drm = nouveau_drm(&bo->device->object);
  724. struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
  725. int ret;
  726. ret = drmPrimeHandleToFD(drm->fd, nvbo->base.handle, DRM_CLOEXEC, prime_fd);
  727. if (ret)
  728. return ret;
  729. nouveau_nvbo_make_global(nvbo);
  730. return 0;
  731. }
  732. drm_public int
  733. nouveau_bo_wait(struct nouveau_bo *bo, uint32_t access,
  734. struct nouveau_client *client)
  735. {
  736. struct nouveau_drm *drm = nouveau_drm(&bo->device->object);
  737. struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
  738. struct drm_nouveau_gem_cpu_prep req;
  739. struct nouveau_pushbuf *push;
  740. int ret = 0;
  741. if (!(access & NOUVEAU_BO_RDWR))
  742. return 0;
  743. push = cli_push_get(client, bo);
  744. if (push && push->channel)
  745. nouveau_pushbuf_kick(push, push->channel);
  746. if (!nvbo->head.next && !(nvbo->access & NOUVEAU_BO_WR) &&
  747. !(access & NOUVEAU_BO_WR))
  748. return 0;
  749. req.handle = bo->handle;
  750. req.flags = 0;
  751. if (access & NOUVEAU_BO_WR)
  752. req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE;
  753. if (access & NOUVEAU_BO_NOBLOCK)
  754. req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT;
  755. ret = drmCommandWrite(drm->fd, DRM_NOUVEAU_GEM_CPU_PREP,
  756. &req, sizeof(req));
  757. if (ret == 0)
  758. nvbo->access = 0;
  759. return ret;
  760. }
  761. drm_public int
  762. nouveau_bo_map(struct nouveau_bo *bo, uint32_t access,
  763. struct nouveau_client *client)
  764. {
  765. struct nouveau_drm *drm = nouveau_drm(&bo->device->object);
  766. struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
  767. if (bo->map == NULL) {
  768. bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE,
  769. MAP_SHARED, drm->fd, nvbo->map_handle);
  770. if (bo->map == MAP_FAILED) {
  771. bo->map = NULL;
  772. return -errno;
  773. }
  774. }
  775. return nouveau_bo_wait(bo, access, client);
  776. }