Nouveau源码分析(四):NVIDIA设备初始化之nouveau_drm_load (1)

本文深入剖析Nouveau驱动的加载过程,详细解读nouveau_drm_load函数中的核心步骤,包括创建nouveau_drm结构体、初始化nouveau_cli及nvif_client,并逐步分析相关组件的构造和交互。

Nouveau源码分析(四)

probe函数成功返回之后,DRM模块就会调用struct drm_driver的load函数,对应nouveau的nouveau_drm_load.
这个函数虽然看起来不是特别长,但每一个调用的函数展开后就会变得非常长了!

  1. // /drivers/gpu/drm/nouveau/nouveau_drm.c  
  2. 364 static int  
  3. 365 nouveau_drm_load(struct drm_device *dev, unsigned long flags)  
  4. 366 {  
  5. 367         struct pci_dev *pdev = dev->pdev;  
  6. 368         struct nouveau_drm *drm;  
  7. 369         int ret;  
  8. 370   
  9. 371         ret = nouveau_cli_create(nouveau_name(dev), "DRM"sizeof(*drm),  
  10. 372                                  (void **)&drm);  
  11. 373         if (ret)  
  12. 374                 return ret;  
  13. 375   
  14. 376         dev->dev_private = drm;  
  15. 377         drm->dev = dev;  
  16. 378         nvkm_client(&drm->client.base)->debug =  
  17. 379                 nouveau_dbgopt(nouveau_debug, "DRM");  
  18. 380   
  19. 381         INIT_LIST_HEAD(&drm->clients);  
  20. 382         spin_lock_init(&drm->tile.lock);  
  21. 383   
  22. 384         nouveau_get_hdmi_dev(drm);  
  23. 385   
  24. 386         /* make sure AGP controller is in a consistent state before we 
  25. 387          * (possibly) execute vbios init tables (see nouveau_agp.h) 
  26. 388          */  
  27. 389         if (pdev && drm_pci_device_is_agp(dev) && dev->agp) {  
  28. 390                 const u64 enables = NV_DEVICE_V0_DISABLE_IDENTIFY |  
  29. 391                                     NV_DEVICE_V0_DISABLE_MMIO;  
  30. 392                 /* dummy device object, doesn't init anything, but allows 
  31. 393                  * agp code access to registers 
  32. 394                  */  
  33. 395                 ret = nvif_device_init(&drm->client.base.base, NULL,  
  34. 396                                        NVDRM_DEVICE, NV_DEVICE,  
  35. 397                                        &(struct nv_device_v0) {  
  36. 398                                                 .device = ~0,  
  37. 399                                                 .disable = ~enables,  
  38. 400                                                 .debug0 = ~0,  
  39. 401                                        }, sizeof(struct nv_device_v0),  
  40. 402                                        &drm->device);  
  41. 403                 if (ret)  
  42. 404                         goto fail_device;  
  43. 405   
  44. 406                 nouveau_agp_reset(drm);  
  45. 407                 nvif_device_fini(&drm->device);  
  46. 408         }  
  47. 409   
  48. 410         ret = nvif_device_init(&drm->client.base.base, NULL, NVDRM_DEVICE,  
  49. 411                                NV_DEVICE,  
  50. 412                                &(struct nv_device_v0) {  
  51. 413                                         .device = ~0,  
  52. 414                                         .disable = 0,  
  53. 415                                         .debug0 = 0,  
  54. 416                                }, sizeof(struct nv_device_v0),  
  55. 417                                &drm->device);  
  56. 418         if (ret)  
  57. 419                 goto fail_device;  
  58. 420   
  59. 421         dev->irq_enabled = true;  
  60. 422   
  61. 423         /* workaround an odd issue on nvc1 by disabling the device's 
  62. 424          * nosnoop capability.  hopefully won't cause issues until a 
  63. 425          * better fix is found - assuming there is one... 
  64. 426          */  
  65. 427         if (drm->device.info.chipset == 0xc1)  
  66. 428                 nvif_mask(&drm->device, 0x00088080, 0x00000800, 0x00000000);  
  67. 429   
  68. 430         nouveau_vga_init(drm);  
  69. 431         nouveau_agp_init(drm);  
  70. 432   
  71. 433         if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {  
  72. 434                 ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40),  
  73. 435                                      0x1000, &drm->client.vm);  
  74. 436                 if (ret)  
  75. 437                         goto fail_device;  
  76. 438   
  77. 439                 nvkm_client(&drm->client.base)->vm = drm->client.vm;  
  78. 440         }  
  79. 441   
  80. 442         ret = nouveau_ttm_init(drm);  
  81. 443         if (ret)  
  82. 444                 goto fail_ttm;  
  83. 445   
  84. 446         ret = nouveau_bios_init(dev);  
  85. 447         if (ret)  
  86. 448                 goto fail_bios;  
  87. 449   
  88. 450         ret = nouveau_display_create(dev);  
  89. 451         if (ret)  
  90. 452                 goto fail_dispctor;  
  91. 453   
  92. 454         if (dev->mode_config.num_crtc) {  
  93. 455                 ret = nouveau_display_init(dev);  
  94. 456                 if (ret)  
  95. 457                         goto fail_dispinit;  
  96. 458         }  
  97. 459   
  98. 460         nouveau_sysfs_init(dev);  
  99. 461         nouveau_hwmon_init(dev);  
  100. 462         nouveau_accel_init(drm);  
  101. 463         nouveau_fbcon_init(dev);  
  102. 464   
  103. 465         if (nouveau_runtime_pm != 0) {  
  104. 466                 pm_runtime_use_autosuspend(dev->dev);  
  105. 467                 pm_runtime_set_autosuspend_delay(dev->dev, 5000);  
  106. 468                 pm_runtime_set_active(dev->dev);  
  107. 469                 pm_runtime_allow(dev->dev);  
  108. 470                 pm_runtime_mark_last_busy(dev->dev);  
  109. 471                 pm_runtime_put(dev->dev);  
  110. 472         }  
  111. 473         return 0;  
  112. 474   
  113. 475 fail_dispinit:  
  114. 476         nouveau_display_destroy(dev);  
  115. 477 fail_dispctor:  
  116. 478         nouveau_bios_takedown(dev);  
  117. 479 fail_bios:  
  118. 480         nouveau_ttm_fini(drm);  
  119. 481 fail_ttm:  
  120. 482         nouveau_agp_fini(drm);  
  121. 483         nouveau_vga_fini(drm);  
  122. 484 fail_device:  
  123. 485         nvif_device_fini(&drm->device);  
  124. 486         nouveau_cli_destroy(&drm->client);  
  125. 487         return ret;  
  126. 488 }  

第371行,创建一个nouveau_drm结构体. 这里,我们重新梳理一下nouveau中结构体的线索.
第一条线索 struct nouveau_xxx,这个我们在上一篇中已经见到了很多了,比如nouveau_device nouveau_client nouveau_object [以下简称nv结构体/nv对象]
另一条线索 struct nvif_xxx/struct nouveau_cli,这个我们从这一节会碰到,比如nouveau_cli nvif_client nvif_object nvif_device[以下简称nvif结构体/nvif对象]
每一个nvif对象都会有对应一个nv对象,可以通过ioctl来访问. 比如对一个nvif对象执行ioctl_rd32,就可以执行对应nv对象oclass里的rd32方法.
仔细阅读下面这个图片:

方块里的是类型名称,箭头上的是成员名称 [带*号的表示指针].
我们现在要创建的就是处于最顶层的nouveau_drm,可以看到如果要和上一节创建的nouveau_device对应起来,还有一段路要走.

因为nouveau_drm这个结构体成员包含的面很广,从物理显存、虚拟映射显存,到channel,dma,以及硬件加速移动显存,还有显示模式切换都会有所涉及,所以在此处先不分析这个结构体的每一个成员,先跟着代码走下去吧.
因为struct nouveau_drm第一个成员就是struct nouveau_cli client; 所以可以把nouveau_cli看作是它的base,因此,第371行创建一个struct nouveau_cli,大小是sizeof(struct nouveau_drm) .
  1. // /drivers/gpu/drm/nouveau/nouveau_drm.c  
  2. 102 static int  
  3. 103 nouveau_cli_create(u64 name, const char *sname,  
  4. 104                    int size, void **pcli)  
  5. 105 {  
  6. 106         struct nouveau_cli *cli = *pcli = kzalloc(size, GFP_KERNEL);  
  7. 107         if (cli) {  
  8. 108                 int ret = nvif_client_init(NULL, NULL, sname, name,  
  9. 109                                            nouveau_config, nouveau_debug,  
  10. 110                                           &cli->base);  
  11. 111                 if (ret == 0) {  
  12. 112                         mutex_init(&cli->mutex);  
  13. 113                         usif_client_init(cli);  
  14. 114                 }  
  15. 115                 return ret;  
  16. 116         }  
  17. 117         return -ENOMEM;  
  18. 118 }  
第106行,kzalloc分配内存.
第108行,因为nouveau_cli的base是nvif_client,所以这里调用nvif_client的init函数. 
第112行,如果nvif_client初始化成功的话,就初始化一个mutex .
第113行,初始化usif. 这是个什么东西呢? 其实就是nvif对user空间的一个接口. 让运行在用户态下的程序能创建usif对象,然后进行读写什么的.
这个初始化usif的函数很简单,就是初始化两个链表.
  1. // /drivers/gpu/drm/nouveau/nouveau_usif.c  
  2. 379 void  
  3. 380 usif_client_init(struct nouveau_cli *cli)  
  4. 381 {  
  5. 382         INIT_LIST_HEAD(&cli->objects);  
  6. 383         INIT_LIST_HEAD(&cli->notifys);  
  7. 384 }  

再来看刚才的nvif_client_init函数:
  1. // /drivers/gpu/drm/nouveau/nvif/client.c  
  2.  69 int  
  3.  70 nvif_client_init(void (*dtor)(struct nvif_client *), const char *driver,  
  4.  71                  const char *name, u64 device, const char *cfg, const char *dbg,  
  5.  72                  struct nvif_client *client)  
  6.  73 {  
  7.  74         int ret, i;  
  8.  75   
  9.  76         ret = nvif_object_init(NULL, (void*)dtor, 0, 0, NULL, 0, &client->base);  
  10.  77         if (ret)  
  11.  78                 return ret;  
  12.  79   
  13.  80         client->base.parent = &client->base;  
  14.  81         client->base.handle = ~0;  
  15.  82         client->object = &client->base;  
  16.  83         client->super = true;  
  17.  84   
  18.  85         for (i = 0, ret = -EINVAL; (client->driver = nvif_drivers[i]); i++) {  
  19.  86                 if (!driver || !strcmp(client->driver->name, driver)) {  
  20.  87                         ret = client->driver->init(name, device, cfg, dbg,  
  21.  88                                                   &client->base.priv);  
  22.  89                         if (!ret || driver)  
  23.  90                                 break;  
  24.  91                 }  
  25.  92         }  
  26.  93   
  27.  94         if (ret)  
  28.  95                 nvif_client_fini(client);  
  29.  96         return ret;  
  30.  97 }  
第76行,首先初始化nvif_object:
  1. // /drivers/gpu/drm/nouveau/nvif/object.c  
  2. 217 int  
  3. 218 nvif_object_init(struct nvif_object *parent, void (*dtor)(struct nvif_object *),  
  4. 219                  u32 handle, u32 oclass, void *data, u32 size,  
  5. 220                  struct nvif_object *object)  
  6. 221 {  
  7. 222         struct ctor *ctor;  
  8. 223         int ret = 0;  
  9. 224   
  10. 225         object->parent = NULL;  
  11. 226         object->object = object;  
  12. 227         nvif_object_ref(parent, &object->parent);  
  13. 228         kref_init(&object->refcount);  
  14. 229         object->handle = handle;  
  15. 230         object->oclass = oclass;  
  16. 231         object->data = NULL;  
  17. 232         object->size = 0;  
  18. 233         object->dtor = dtor;  
  19. 234         object->map.ptr = NULL;  
  20. 235         object->map.size = 0;  
  21. 236   
  22. 237         if (object->parent) {  
  23. 238                 if (!(ctor = kmalloc(sizeof(*ctor) + size, GFP_KERNEL))) {  
  24. 239                         nvif_object_fini(object);  
  25. 240                         return -ENOMEM;  
  26. 241                 }  
  27. 242                 object->data = ctor->new.data;  
  28. 243                 object->size = size;  
  29. 244                 memcpy(object->data, data, size);  
  30. 245   
  31. 246                 ctor->ioctl.version = 0;  
  32. 247                 ctor->ioctl.type = NVIF_IOCTL_V0_NEW;  
  33. 248                 ctor->new.version = 0;  
  34. 249                 ctor->new.route = NVIF_IOCTL_V0_ROUTE_NVIF;  
  35. 250                 ctor->new.token = (unsigned long)(void *)object;  
  36. 251                 ctor->new.handle = handle;  
  37. 252                 ctor->new.oclass = oclass;  
  38. 253   
  39. 254                 ret = nvif_object_ioctl(parent, ctor, sizeof(*ctor) +  
  40. 255                                         object->size, &object->priv);  
  41. 256         }  
  42. 257   
  43. 258         if (ret)  
  44. 259                 nvif_object_fini(object);  
  45. 260         return ret;  
  46. 261 }  
首先各种填充字段: 
这里的oclass是创建nouveau_object的时候用的.
这里的handle是nouveau_object和nvif_object一一对应用的.
然后dtor是析构函数指针,object是nvif_object()用的,其实就是nvif对象间的转换.
  1. // /drivers/gpu/drm/nouveau/nvif/object.h  
  2.  37 #define nvif_object(a) (a)->object  

前面说过,每一个nvif_object会对应一个nouveau_object,但对于这个例子来说,创建nouveau_object的代码实际上在第254行,由于object->parent为0,根本执行不到,所以并不会使用这个oclass和handle. [当然,这个nvif_object还是有对应的nouveau_object对象的,只不过不在这里创建了,等会儿会讲到.]
那个if语句的代码也暂时不展开,等到以后真正执行到再回来说. 于是这个函数就这么返回了.

先回到nvif_client_init,下面还有一个循环语句,遍历nvif_drivers:
  1. // /drivers/gpu/drm/nouveau/nvif/client.c  
  2.  58 const struct nvif_driver *  
  3.  59 nvif_drivers[] = {  
  4.  60 #ifdef __KERNEL__  
  5.  61         &nvif_driver_nvkm,  
  6.  62 #else  
  7.  63         &nvif_driver_drm,  
  8.  64         &nvif_driver_lib,  
  9.  65 #endif  
  10.  66         NULL  
  11.  67 };  
很明显这是内核里的代码,因此只存在一个nvif_driver,那就是nvif_driver_nvkm.
再看看这个for循环,很明显我们将会调用nvif_driver_nvkm.init():
  1. // /drivers/gpu/drm/nouveau/nouveau_nvif.c  
  2. 125 const struct nvif_driver  
  3. 126 nvif_driver_nvkm = {  
  4. 127         .name = "nvkm",  
  5. 128         .init = nvkm_client_init,  
  6. 129         .fini = nvkm_client_fini,  
  7. 130         .suspend = nvkm_client_suspend,  
  8. 131         .resume = nvkm_client_resume,  
  9. 132         .ioctl = nvkm_client_ioctl,  
  10. 133         .map = nvkm_client_map,  
  11. 134         .unmap = nvkm_client_unmap,  
  12. 135         .keep = false,  
  13. 136 };  
  1. // /drivers/gpu/drm/nouveau/nouveau_nvif.c  
  2. 109 static int  
  3. 110 nvkm_client_init(const char *name, u64 device, const char *cfg,  
  4. 111                  const char *dbg, void **ppriv)  
  5. 112 {  
  6. 113         struct nouveau_client *client;  
  7. 114         int ret;  
  8. 115   
  9. 116         ret = nouveau_client_create(name, device, cfg, dbg, &client);  
  10. 117         *ppriv = client;  
  11. 118         if (ret)  
  12. 119                 return ret;  
  13. 120   
  14. 121         client->ntfy = nvkm_client_ntfy;  
  15. 122         return 0;  
  16. 123 }  
首先创建一个nouveau_client,这个其实就是一个nouveau_object,也就是说在这里创建了这个nvif_object对应的nouveau_object .
第121行,一个有关notify的函数. notify貌似是一个回调工具,创建一个里面包含函数指针,数据什么的;当发生某个条件后,可以触发这个notify,然后就会调用里面的函数.
再来看nouveau_client_create:
  1. // /drivers/gpu/drm/nouveau/core/include/core/client.h  
  2.  39 #define nouveau_client_create(n,c,oc,od,d)                                     \  
  3.  40         nouveau_client_create_((n), (c), (oc), (od), sizeof(**d), (void **)d)  
  4.  41   
  5.  42 int  nouveau_client_create_(const char *name, u64 device, const char *cfg,  
  6.  43                             const char *dbg, intvoid **);  
又一次见到了这个东西,直接去看nouveau_client_create_
  1. // /drivers/gpu/drm/nouveau/core/core/client.c  
  2. 203 int  
  3. 204 nouveau_client_create_(const char *name, u64 devname, const char *cfg,  
  4. 205                        const char *dbg, int length, void **pobject)  
  5. 206 {  
  6. 207         struct nouveau_object *device;  
  7. 208         struct nouveau_client *client;  
  8. 209         int ret;  
  9. 210   
  10. 211         device = (void *)nouveau_device_find(devname);  
  11. 212         if (!device)  
  12. 213                 return -ENODEV;  
  13. 214   
  14. 215         ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass,  
  15. 216                                      NV_CLIENT_CLASS, NULL,  
  16. 217                                      (1ULL << NVDEV_ENGINE_DEVICE),  
  17. 218                                      length, pobject);  
  18. 219         client = *pobject;  
  19. 220         if (ret)  
  20. 221                 return ret;  
  21. 222   
  22. 223         ret = nouveau_handle_create(nv_object(client), ~0, ~0,  
  23. 224                                     nv_object(client), &client->root);  
  24. 225         if (ret)  
  25. 226                 return ret;  
  26. 227   
  27. 228         /* prevent init/fini being called, os in in charge of this */  
  28. 229         atomic_set(&nv_object(client)->usecount, 2);  
  29. 230   
  30. 231         nouveau_object_ref(device, &client->device);  
  31. 232         snprintf(client->name, sizeof(client->name), "%s", name);  
  32. 233         client->debug = nouveau_dbgopt(dbg, "CLIENT");  
  33. 234         return 0;  
  34. 235 }  
第211行,首先寻找对应的nouveau_device.
第215行,创建namedb,通过看最开始的结构体,应该也能想象出是个什么东西:
  1. // /drivers/gpu/drm/nouveau/core/core/namedb.c  
  2. 166 int  
  3. 167 nouveau_namedb_create_(struct nouveau_object *parent,  
  4. 168                        struct nouveau_object *engine,  
  5. 169                        struct nouveau_oclass *oclass, u32 pclass,  
  6. 170                        struct nouveau_oclass *sclass, u64 engcls,  
  7. 171                        int length, void **pobject)  
  8. 172 {  
  9. 173         struct nouveau_namedb *namedb;  
  10. 174         int ret;  
  11. 175   
  12. 176         ret = nouveau_parent_create_(parent, engine, oclass, pclass |  
  13. 177                                      NV_NAMEDB_CLASS, sclass, engcls,  
  14. 178                                      length, pobject);  
  15. 179         namedb = *pobject;  
  16. 180         if (ret)  
  17. 181                 return ret;  
  18. 182   
  19. 183         rwlock_init(&namedb->lock);  
  20. 184         INIT_LIST_HEAD(&namedb->list);  
  21. 185         return 0;  
  22. 186 }  
先创建一个nouveau_parent,这个结构体和nouveau_engine都能把u32 oclass转换成对应的nouveau_oclass *oclass .
接下来初始化namedb的list链表,这个链表和nouveau_handle的node链表相连,表示储存在namedb里的nouveau_handle对象 .
  1. // /drivers/gpu/drm/nouveau/core/core/parent.c  
  2. 110 int  
  3. 111 nouveau_parent_create_(struct nouveau_object *parent,  
  4. 112                        struct nouveau_object *engine,  
  5. 113                        struct nouveau_oclass *oclass, u32 pclass,  
  6. 114                        struct nouveau_oclass *sclass, u64 engcls,  
  7. 115                        int size, void **pobject)  
  8. 116 {  
  9. 117         struct nouveau_parent *object;  
  10. 118         struct nouveau_sclass *nclass;  
  11. 119         int ret;  
  12. 120   
  13. 121         ret = nouveau_object_create_(parent, engine, oclass, pclass |  
  14. 122                                      NV_PARENT_CLASS, size, pobject);  
  15. 123         object = *pobject;  
  16. 124         if (ret)  
  17. 125                 return ret;  
  18. 126   
  19. 127         while (sclass && sclass->ofuncs) {  
  20. 128                 nclass = kzalloc(sizeof(*nclass), GFP_KERNEL);  
  21. 129                 if (!nclass)  
  22. 130                         return -ENOMEM;  
  23. 131   
  24. 132                 nclass->sclass = object->sclass;  
  25. 133                 object->sclass = nclass;  
  26. 134                 nclass->engine = engine ? nv_engine(engine) : NULL;  
  27. 135                 nclass->oclass = sclass;  
  28. 136                 sclass++;  
  29. 137         }  
  30. 138   
  31. 139         object->engine = engcls;  
  32. 140         return 0;  
  33. 141 }  
首先创建一个nouveau_object对象.
然后下面这个while语句,把sclass连成了一个链表放在了object->sclass中.
然后engcls表示可以用来完成u32 oclass转换的engines.
如果要通过一个nouveau_parent对象来完成u32 oclass的转换,会先从object->sclass中查找.
如果没找到,那么就查看object->engine中指示可用的engine,再从这些engine中查找.
此处的sclass实际上是0,所以object->sclass为0. 而且因为这个结构体实际上是nouveau_client,转换u32 oclass的时候还有一个特别的处理,会直接使用client->device,也就是nouveau_device,到时候再具体说.

回到nouveau_client_create_,接下来创建一个nouveau_handle *root.
  1. // /drivers/gpu/drm/nouveau/core/core/handle.c  
  2.  99 int  
  3. 100 nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,  
  4. 101                       struct nouveau_object *object,  
  5. 102                       struct nouveau_handle **phandle)  
  6. 103 {  
  7. 104         struct nouveau_object *namedb;  
  8. 105         struct nouveau_handle *handle;  
  9. 106         int ret;  
  10. 107   
  11. 108         namedb = parent;  
  12. 109         while (!nv_iclass(namedb, NV_NAMEDB_CLASS))  
  13. 110                 namedb = namedb->parent;  
  14. 111   
  15. 112         handle = kzalloc(sizeof(*handle), GFP_KERNEL);  
  16. 113         if (!handle)  
  17. 114                 return -ENOMEM;  
  18. 115   
  19. 116         INIT_LIST_HEAD(&handle->head);  
  20. 117         INIT_LIST_HEAD(&handle->tree);  
  21. 118         handle->name = _handle;  
  22. 119         handle->priv = ~0;  
  23. 120   
  24. 121         ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle);  
  25. 122         if (ret) {  
  26. 123                 kfree(handle);  
  27. 124                 return ret;  
  28. 125         }  
  29. 126   
  30. 127         if (nv_parent(parent)->object_attach) {  
  31. 128                 ret = nv_parent(parent)->object_attach(parent, object, _handle);  
  32. 129                 if (ret < 0) {  
  33. 130                         nouveau_handle_destroy(handle);  
  34. 131                         return ret;  
  35. 132                 }  
  36. 133   
  37. 134                 handle->priv = ret;  
  38. 135         }  
  39. 136   
  40. 137         if (object != namedb) {  
  41. 138                 while (!nv_iclass(namedb, NV_CLIENT_CLASS))  
  42. 139                         namedb = namedb->parent;  
  43. 140   
  44. 141                 handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent);  
  45. 142                 if (handle->parent) {  
  46. 143                         list_add(&handle->head, &handle->parent->tree);  
  47. 144                         nouveau_namedb_put(handle->parent);  
  48. 145                 }  
  49. 146         }  
  50. 147   
  51. 148         hprintk(handle, TRACE, "created\n");  
  52. 149         *phandle = handle;  
  53. 150         return 0;  
  54. 151 }  
首先把parent向上查找,直到找到一个nouveau_namedb,对于这个例子,parent本来就是一个nouveau_namedb,所以parent == namedb.
接着初始化handle的一些字段,紧接着使用nouveau_namedb_insert把这个插入到namedb中. handle的node链表和namedb的list链表相连.
  1. // /drivers/gpu/drm/nouveau/core/core/namedb.c  
  2.  87 int  
  3.  88 nouveau_namedb_insert(struct nouveau_namedb *namedb, u32 name,  
  4.  89                       struct nouveau_object *object,  
  5.  90                       struct nouveau_handle *handle)  
  6.  91 {  
  7.  92         int ret = -EEXIST;  
  8.  93         write_lock_irq(&namedb->lock);  
  9.  94         if (!nouveau_namedb_lookup(namedb, name)) {  
  10.  95                 nouveau_object_ref(object, &handle->object);  
  11.  96                 handle->namedb = namedb;  
  12.  97                 list_add(&handle->node, &namedb->list);  
  13.  98                 ret = 0;  
  14.  99         }  
  15. 100         write_unlock_irq(&namedb->lock);  
  16. 101         return ret;  
  17. 102 }  
这个insert函数首先查找是否有重复的,有就返回-EEXIST,然后用链表连起来,返回.
第127行,检查parent有没有一个关联handle和object的函数,对于这个例子,内存用kzalloc分配,之后也没有对这个进行初始化. 所以不会进入这个if语句.
第137行,如果object和namedb不一样,那么寻找_parent对应的handle,然后把当前handle的head链表加入到parent handle的tree链表中.
对于这个例子object和namedb相等,因此不会执行进去.
这个地方可以顺便看一下nouveau_namedb_get和nouveau_namedb_put:
  1. // /drivers/gpu/drm/nouveau/core/core/namedb.c  
  2. 115 struct nouveau_handle *  
  3. 116 nouveau_namedb_get(struct nouveau_namedb *namedb, u32 name)  
  4. 117 {  
  5. 118         struct nouveau_handle *handle;  
  6. 119         read_lock(&namedb->lock);  
  7. 120         handle = nouveau_namedb_lookup(namedb, name);  
  8. 121         if (handle == NULL)  
  9. 122                 read_unlock(&namedb->lock);  
  10. 123         return handle;  
  11. 124 }  
  1. // /drivers/gpu/drm/nouveau/core/core/namedb.c  
  2. 159 void  
  3. 160 nouveau_namedb_put(struct nouveau_handle *handle)  
  4. 161 {  
  5. 162         if (handle)  
  6. 163                 read_unlock(&handle->namedb->lock);  
  7. 164 }  
  1. // /drivers/gpu/drm/nouveau/core/core/namedb.c  
  2.  30 static struct nouveau_handle *  
  3.  31 nouveau_namedb_lookup(struct nouveau_namedb *namedb, u32 name)  
  4.  32 {  
  5.  33         struct nouveau_handle *handle;  
  6.  34   
  7.  35         list_for_each_entry(handle, &namedb->list, node) {  
  8.  36                 if (handle->name == name)  
  9.  37                         return handle;  
  10.  38         }  
  11.  39   
  12.  40         return NULL;  
  13.  41 }  
代码都很容易理解,自己尝试阅读一下,不多说了. 回到刚才那个函数:

第149行,把phandle赋值为handle,返回.
回到nouveau_client_create_,第229行,初始化几个字段,比如把device字段储存上对应的nouveau_device,这个也就是我们在上一篇中用nouveau_device_create创建的那个.
返回! 至此我们终于可以回到nouveau_drm_load了!

第376行,把新创建的nouveau_drm放进drm提供的结构体里.
第377行,把drm的结构体放进nouveau_drm里.
第378行,一个debug配置信息. 这里的nvkm_xxx就是获得nvif_object所对应的nouveau_object,并把它转换成nouveau_xxx .
第381行,初始化clients链表. 对nouveau设备文件进行open操作时就会创建一个nouveau_cli并加入这个链表. 里面包含的是每个文件特有的东西,比如前面提到的usif .
第384行,获取hdmi设备. 不知道hdmi是什么的可以去百度谷歌一下.
  1. // /drivers/gpu/drm/nouveau/nouveau_drm.c  
  2. 336 static void  
  3. 337 nouveau_get_hdmi_dev(struct nouveau_drm *drm)  
  4. 338 {  
  5. 339         struct pci_dev *pdev = drm->dev->pdev;  
  6. 340   
  7. 341         if (!pdev) {  
  8. 342                 DRM_INFO("not a PCI device; no HDMI\n");  
  9. 343                 drm->hdmi_device = NULL;  
  10. 344                 return;  
  11. 345         }  
  12. 346   
  13. 347         /* subfunction one is a hdmi audio device? */  
  14. 348         drm->hdmi_device = pci_get_bus_and_slot((unsigned int)pdev->bus->number,  
  15. 349                                                 PCI_DEVFN(PCI_SLOT(pdev->devfn), 1));  
  16. 350   
  17. 351         if (!drm->hdmi_device) {  
  18. 352                 NV_DEBUG(drm, "hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1);  
  19. 353                 return;  
  20. 354         }  
  21. 355   
  22. 356         if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) {  
  23. 357                 NV_DEBUG(drm, "possible hdmi device not audio %d\n", drm->hdmi_device->class);  
  24. 358                 pci_dev_put(drm->hdmi_device);  
  25. 359                 drm->hdmi_device = NULL;  
  26. 360                 return;  
  27. 361         }  
  28. 362 }  
第341行,检查是否是PCI设备.
第348行,使用PCI模块的函数获取HDMI对应的PCI设备.
第356行,检查获取的HDMI设备的class信息.

接下来的nvif_device_init又是一个大函数,暂且先到这. 下一篇再讨论nvif_device_init函数.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值