nouveau_drm.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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 <linux/module.h>
  25. #include <linux/pci.h>
  26. #include <core/device.h>
  27. #include <core/client.h>
  28. #include <core/class.h>
  29. #include <subdev/device.h>
  30. #include "nouveau_drm.h"
  31. #include "nouveau_agp.h"
  32. int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *);
  33. void nouveau_pci_remove(struct pci_dev *);
  34. int nouveau_pci_suspend(struct pci_dev *, pm_message_t);
  35. int nouveau_pci_resume(struct pci_dev *);
  36. int __init nouveau_init(struct pci_driver *);
  37. void __exit nouveau_exit(struct pci_driver *);
  38. int nouveau_load(struct drm_device *, unsigned long);
  39. int nouveau_unload(struct drm_device *);
  40. void *nouveau_newpriv(struct drm_device *);
  41. MODULE_PARM_DESC(config, "option string to pass to driver core");
  42. static char *nouveau_config;
  43. module_param_named(config, nouveau_config, charp, 0400);
  44. MODULE_PARM_DESC(debug, "debug string to pass to driver core");
  45. static char *nouveau_debug;
  46. module_param_named(debug, nouveau_debug, charp, 0400);
  47. static u64
  48. nouveau_name(struct pci_dev *pdev)
  49. {
  50. u64 name = (u64)pci_domain_nr(pdev->bus) << 32;
  51. name |= pdev->bus->number << 16;
  52. name |= PCI_SLOT(pdev->devfn) << 8;
  53. return name | PCI_FUNC(pdev->devfn);
  54. }
  55. static int
  56. nouveau_cli_create(struct pci_dev *pdev, u32 name, int size, void **pcli)
  57. {
  58. struct nouveau_cli *cli;
  59. int ret;
  60. ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config,
  61. nouveau_debug, size, pcli);
  62. cli = *pcli;
  63. if (ret)
  64. return ret;
  65. mutex_init(&cli->mutex);
  66. return 0;
  67. }
  68. static void
  69. nouveau_cli_destroy(struct nouveau_cli *cli)
  70. {
  71. struct nouveau_object *client = nv_object(cli);
  72. nouveau_client_fini(&cli->base, false);
  73. atomic_set(&client->refcount, 1);
  74. nouveau_object_ref(NULL, &client);
  75. }
  76. static int __devinit
  77. nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent)
  78. {
  79. struct nouveau_device *device;
  80. int ret;
  81. ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev),
  82. nouveau_config, nouveau_debug, &device);
  83. if (ret)
  84. return ret;
  85. pci_set_master(pdev);
  86. ret = nouveau_pci_probe(pdev, pent);
  87. if (ret) {
  88. nouveau_device_destroy(&device);
  89. return ret;
  90. }
  91. return 0;
  92. }
  93. int
  94. nouveau_drm_load(struct drm_device *dev, unsigned long flags)
  95. {
  96. struct pci_dev *pdev = dev->pdev;
  97. struct nouveau_drm *drm;
  98. int ret;
  99. ret = nouveau_cli_create(pdev, 0, sizeof(*drm), (void**)&drm);
  100. dev->dev_private = drm;
  101. if (ret)
  102. return ret;
  103. INIT_LIST_HEAD(&drm->clients);
  104. drm->dev = dev;
  105. /* make sure AGP controller is in a consistent state before we
  106. * (possibly) execute vbios init tables (see nouveau_agp.h)
  107. */
  108. if (drm_pci_device_is_agp(dev) && dev->agp) {
  109. /* dummy device object, doesn't init anything, but allows
  110. * agp code access to registers
  111. */
  112. ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT,
  113. NVDRM_DEVICE, 0x0080,
  114. &(struct nv_device_class) {
  115. .device = ~0,
  116. .disable =
  117. ~(NV_DEVICE_DISABLE_MMIO |
  118. NV_DEVICE_DISABLE_IDENTIFY),
  119. .debug0 = ~0,
  120. }, sizeof(struct nv_device_class),
  121. &drm->device);
  122. if (ret)
  123. return ret;
  124. nouveau_agp_reset(drm);
  125. nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE);
  126. }
  127. ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE,
  128. 0x0080, &(struct nv_device_class) {
  129. .device = ~0,
  130. .disable = 0,
  131. .debug0 = 0,
  132. }, sizeof(struct nv_device_class),
  133. &drm->device);
  134. if (ret)
  135. goto fail_device;
  136. /* initialise AGP */
  137. nouveau_agp_init(drm);
  138. ret = nouveau_load(dev, flags);
  139. if (ret)
  140. goto fail_device;
  141. return 0;
  142. fail_device:
  143. nouveau_cli_destroy(&drm->client);
  144. return ret;
  145. }
  146. int
  147. nouveau_drm_unload(struct drm_device *dev)
  148. {
  149. struct nouveau_drm *drm = nouveau_newpriv(dev);
  150. struct pci_dev *pdev = dev->pdev;
  151. int ret;
  152. ret = nouveau_unload(dev);
  153. if (ret)
  154. return ret;
  155. nouveau_agp_fini(drm);
  156. pci_set_drvdata(pdev, drm->client.base.device);
  157. nouveau_cli_destroy(&drm->client);
  158. return 0;
  159. }
  160. static void
  161. nouveau_drm_remove(struct pci_dev *pdev)
  162. {
  163. struct nouveau_device *device;
  164. nouveau_pci_remove(pdev);
  165. device = pci_get_drvdata(pdev);
  166. nouveau_device_destroy(&device);
  167. }
  168. int
  169. nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state)
  170. {
  171. struct drm_device *dev = pci_get_drvdata(pdev);
  172. struct nouveau_drm *drm = nouveau_newpriv(dev);
  173. struct nouveau_cli *cli;
  174. int ret;
  175. if (dev->switch_power_state == DRM_SWITCH_POWER_OFF ||
  176. pm_state.event == PM_EVENT_PRETHAW)
  177. return 0;
  178. ret = nouveau_pci_suspend(pdev, pm_state);
  179. if (ret)
  180. return ret;
  181. list_for_each_entry(cli, &drm->clients, head) {
  182. ret = nouveau_client_fini(&cli->base, true);
  183. if (ret)
  184. goto fail_client;
  185. }
  186. ret = nouveau_client_fini(&drm->client.base, true);
  187. if (ret)
  188. goto fail_client;
  189. nouveau_agp_fini(drm);
  190. pci_save_state(pdev);
  191. if (pm_state.event == PM_EVENT_SUSPEND) {
  192. pci_disable_device(pdev);
  193. pci_set_power_state(pdev, PCI_D3hot);
  194. }
  195. return 0;
  196. fail_client:
  197. list_for_each_entry_continue_reverse(cli, &drm->clients, head) {
  198. nouveau_client_init(&cli->base);
  199. }
  200. nouveau_pci_resume(pdev);
  201. return ret;
  202. }
  203. int
  204. nouveau_drm_resume(struct pci_dev *pdev)
  205. {
  206. struct drm_device *dev = pci_get_drvdata(pdev);
  207. struct nouveau_drm *drm = nouveau_newpriv(dev);
  208. struct nouveau_cli *cli;
  209. int ret;
  210. if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
  211. return 0;
  212. pci_set_power_state(pdev, PCI_D0);
  213. pci_restore_state(pdev);
  214. ret = pci_enable_device(pdev);
  215. if (ret)
  216. return ret;
  217. pci_set_master(pdev);
  218. nouveau_agp_reset(drm);
  219. nouveau_client_init(&drm->client.base);
  220. list_for_each_entry(cli, &drm->clients, head) {
  221. nouveau_client_init(&cli->base);
  222. }
  223. nouveau_agp_init(drm);
  224. return nouveau_pci_resume(pdev);
  225. }
  226. static struct pci_device_id
  227. nouveau_drm_pci_table[] = {
  228. {
  229. PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
  230. .class = PCI_BASE_CLASS_DISPLAY << 16,
  231. .class_mask = 0xff << 16,
  232. },
  233. {
  234. PCI_DEVICE(PCI_VENDOR_ID_NVIDIA_SGS, PCI_ANY_ID),
  235. .class = PCI_BASE_CLASS_DISPLAY << 16,
  236. .class_mask = 0xff << 16,
  237. },
  238. {}
  239. };
  240. static struct pci_driver
  241. nouveau_drm_pci_driver = {
  242. .name = "nouveau",
  243. .id_table = nouveau_drm_pci_table,
  244. .probe = nouveau_drm_probe,
  245. .remove = nouveau_drm_remove,
  246. .suspend = nouveau_drm_suspend,
  247. .resume = nouveau_drm_resume,
  248. };
  249. static int __init
  250. nouveau_drm_init(void)
  251. {
  252. return nouveau_init(&nouveau_drm_pci_driver);
  253. }
  254. static void __exit
  255. nouveau_drm_exit(void)
  256. {
  257. nouveau_exit(&nouveau_drm_pci_driver);
  258. }
  259. module_init(nouveau_drm_init);
  260. module_exit(nouveau_drm_exit);
  261. MODULE_DEVICE_TABLE(pci, nouveau_drm_pci_table);
  262. MODULE_AUTHOR("Nouveau Project");
  263. MODULE_DESCRIPTION("nVidia Riva/TNT/GeForce/Quadro/Tesla");
  264. MODULE_LICENSE("GPL and additional rights");