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

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 }  

第386行到第408行,注释说的很清楚,重置AGP. 好了来看nvif_device_init:

  1. // /drivers/gpu/drm/nouveau/nvif/device.c  
  2.  33 int  
  3.  34 nvif_device_init(struct nvif_object *parent, void (*dtor)(struct nvif_device *),  
  4.  35                  u32 handle, u32 oclass, void *data, u32 size,  
  5.  36                  struct nvif_device *device)  
  6.  37 {  
  7.  38         int ret = nvif_object_init(parent, (void *)dtor, handle, oclass,  
  8.  39                                    data, size, &device->base);  
  9.  40         if (ret == 0) {  
  10.  41                 device->object = &device->base;  
  11.  42                 device->info.version = 0;  
  12.  43                 ret = nvif_object_mthd(&device->base, NV_DEVICE_V0_INFO,  
  13.  44                                        &device->info, sizeof(device->info));  
  14.  45         }  
  15.  46         return ret;  
  16.  47 }  
首先第38行,nvif_object_init,还记得在上一篇中被忽略掉的那部分代码吗? 这里展开说:

  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 }  
第238行,分配一个ctor.

第244行,把传进来的数据复制进去,数据就是:"&(struct nv_device_v0) { .device = ~0, .disable = ~enables, .debug0 = ~0, }"

下面的几个字段简单说一下:

ctor->ioctl.version 貌似是用来校验版本的东西,目前只可能是0.

ctor->ioctl.type 表示ioctl的命令.

ctor->new.version 貌似和上面那个version一样.

ctor->new.route 表示这是nvif. 除了nvif另一种是usif,用户空间用的.

ctor->new.token 此处是储存对应的nvif_object.

ctor->new.handle 此处是储存要创建的nouveau_object的handle.

ctor->new.oclass 此处是储存要创建的nouveau_object的oclass.

第254行,正式调用nvif_object_ioctl函数.

  1. // /drivers/gpu/drm/nouveau/nvif/object.c  
  2.  30 int  
  3.  31 nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)  
  4.  32 {  
  5.  33         struct nvif_client *client = nvif_client(object);  
  6.  34         union {  
  7.  35                 struct nvif_ioctl_v0 v0;  
  8.  36         } *args = data;  
  9.  37   
  10.  38         if (size >= sizeof(*args) && args->v0.version == 0) {  
  11.  39                 args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;  
  12.  40                 args->v0.path_nr = 0;  
  13.  41                 while (args->v0.path_nr < ARRAY_SIZE(args->v0.path)) {  
  14.  42                         args->v0.path[args->v0.path_nr++] = object->handle;  
  15.  43                         if (object->parent == object)  
  16.  44                                 break;  
  17.  45                         object = object->parent;  
  18.  46                 }  
  19.  47         } else  
  20.  48                 return -ENOSYS;  
  21.  49   
  22.  50         return client->driver->ioctl(client->base.priv, client->super, data, size, hack);  
  23.  51 }  

第38行,首先检查version和大小是否正确

第39行,设置一下owner,这个是表示是对nvif还是usif还是any进行ioctl的. 可以防止用户态程序ioctl的时候ioctl到nvif [只能对usif进行ioctl.].

之后第41行一个whlie循环,逐级object = object->parent,然后把handle储存到path里.

第50行,交给client的driver进行处理.

  1. // /drivers/gpu/drm/nouveau/nouveau_nvif.c  
  2.  54 static int  
  3.  55 nvkm_client_ioctl(void *priv, bool super, void *data, u32 size, void **hack)  
  4.  56 {  
  5.  57         return nvkm_ioctl(priv, super, data, size, hack);  
  6.  58 }  
再交给nvkm_ioctl处理.

  1. // /drivers/gpu/drm/nouveau/core/core/ioctl.c  
  2. 502 int  
  3. 503 nvkm_ioctl(struct nouveau_client *client, bool supervisor,  
  4. 504            void *data, u32 size, void **hack)  
  5. 505 {  
  6. 506         union {  
  7. 507                 struct nvif_ioctl_v0 v0;  
  8. 508         } *args = data;  
  9. 509         int ret;  
  10. 510   
  11. 511         client->super = supervisor;  
  12. 512         nv_ioctl(client, "size %d\n", size);  
  13. 513   
  14. 514         if (nvif_unpack(args->v0, 0, 0, true)) {  
  15. 515                 nv_ioctl(client, "vers %d type %02x path %d owner %02x\n",  
  16. 516                          args->v0.version, args->v0.type, args->v0.path_nr,  
  17. 517                          args->v0.owner);  
  18. 518                 ret = nvkm_ioctl_path(client->root, args->v0.type,  
  19. 519                                       args->v0.path_nr, args->v0.path,  
  20. 520                                       data, size, args->v0.owner,  
  21. 521                                      &args->v0.route, &args->v0.token);  
  22. 522         }  
  23. 523   
  24. 524         nv_ioctl(client, "return %d\n", ret);  
  25. 525         if (hack) {  
  26. 526                 *hack = client->data;  
  27. 527                 client->data = NULL;  
  28. 528         }  
  29. 529         client->super = false;  
  30. 530         return ret;  
  31. 531 }  
client->super意义不明,忽略之.

然后第514行,看看nvif_unpack:

  1. // /drivers/gpu/drm/nouveau/nvif/unpack.h  
  2.   9 #define nvif_unpack(d,vl,vh,m) ({                                              \  
  3.  10         if ((vl) == 0 || ret == -ENOSYS) {                                     \  
  4.  11                 int _size = sizeof(d);                                         \  
  5.  12                 if (_size <= size && (d).version >= (vl) &&                    \  
  6.  13                                      (d).version <= (vh)) {                    \  
  7.  14                         data = (u8 *)data + _size;                             \  
  8.  15                         size = size - _size;                                   \  
  9.  16                         ret = ((m) || !size) ? 0 : -E2BIG;                     \  
  10.  17                 } else {                                                       \  
  11.  18                         ret = -ENOSYS;                                         \  
  12.  19                 }                                                              \  
  13.  20         }                                                                      \  
  14.  21         (ret == 0);                                                            \  
  15.  22 })  

大体上来说就是检查版本是否对应,大小是否正常,然后把data加上header的size,把size减去header的size.

第518行,调用nvkm_ioctl_path.

第526行,把data存到*hack里.

重点看nvkm_ioctl_path:

  1. // /drivers/gpu/drm/nouveau/core/core/ioctl.c  
  2. 459 static int  
  3. 460 nvkm_ioctl_path(struct nouveau_handle *parent, u32 type, u32 nr,  
  4. 461                   u32 *path, void *data, u32 size,  
  5. 462                   u8 owner, u8 *route, u64 *token)  
  6. 463 {  
  7. 464         struct nouveau_handle *handle = parent;  
  8. 465         struct nouveau_namedb *namedb;  
  9. 466         struct nouveau_object *object;  
  10. 467         int ret;  
  11. 468   
  12. 469         while ((object = parent->object), nr--) {  
  13. 470                 nv_ioctl(object, "path 0x%08x\n", path[nr]);  
  14. 471                 if (!nv_iclass(object, NV_PARENT_CLASS)) {  
  15. 472                         nv_debug(object, "cannot have children (path)\n");  
  16. 473                         return -EINVAL;  
  17. 474                 }  
  18. 475   
  19. 476                 if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) ||  
  20. 477                     !(handle = nouveau_namedb_get(namedb, path[nr]))) {  
  21. 478                         nv_debug(object, "handle 0x%08x not found\n", path[nr]);  
  22. 479                         return -ENOENT;  
  23. 480                 }  
  24. 481                 nouveau_namedb_put(handle);  
  25. 482                 parent = handle;  
  26. 483         }  
  27. 484   
  28. 485         if (owner != NVIF_IOCTL_V0_OWNER_ANY &&  
  29. 486             owner != handle->route) {  
  30. 487                 nv_ioctl(object, "object route != owner\n");  
  31. 488                 return -EACCES;  
  32. 489         }  
  33. 490         *route = handle->route;  
  34. 491         *token = handle->token;  
  35. 492   
  36. 493         if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {  
  37. 494                 if (nvkm_ioctl_v0[type].version == 0) {  
  38. 495                         ret = nvkm_ioctl_v0[type].func(handle, data, size);  
  39. 496                 }  
  40. 497         }  
  41. 498   
  42. 499         return ret;  
  43. 500 }  
参数parent是client->root,它对应的object就是它自己client.

第469行的while语句,逐个把path[--nr]取出来,从后往前,也就是从parent到children,在namedb中查找.

这样一来,最后的handle就是path[0]所对应的nouveau_handle. 也就是当初调用nvif_object_init第一个参数nvif_object *object对应的nouveau_object *object对应的nouveau_handle *handle! 对于这个例子就是nouveau_client *client的root字段.

接下来第485行,检查owner和handle->route是否匹配,作用前面提到了.

第490行.把handle->route和handle->token储存到*route和*token中,再调用真正的ioctl函数.

  1. // /drivers/gpu/drm/nouveau/core/core/ioctl.c  
  2. 439 static struct {  
  3. 440         int version;  
  4. 441         int (*func)(struct nouveau_handle *, void *, u32);  
  5. 442 }  
  6. 443 nvkm_ioctl_v0[] = {  
  7. 444         { 0x00, nvkm_ioctl_nop },  
  8. 445         { 0x00, nvkm_ioctl_sclass },  
  9. 446         { 0x00, nvkm_ioctl_new },  
  10. 447         { 0x00, nvkm_ioctl_del },  
  11. 448         { 0x00, nvkm_ioctl_mthd },  
  12. 449         { 0x00, nvkm_ioctl_rd },  
  13. 450         { 0x00, nvkm_ioctl_wr },  
  14. 451         { 0x00, nvkm_ioctl_map },  
  15. 452         { 0x00, nvkm_ioctl_unmap },  
  16. 453         { 0x00, nvkm_ioctl_ntfy_new },  
  17. 454         { 0x00, nvkm_ioctl_ntfy_del },  
  18. 455         { 0x00, nvkm_ioctl_ntfy_get },  
  19. 456         { 0x00, nvkm_ioctl_ntfy_put },  
  20. 457 };  
本例当然是nvkm_ioctl_new,来看一下这个函数:

  1.  87 static int  
  2.  88 nvkm_ioctl_new(struct nouveau_handle *parent, void *data, u32 size)  
  3.  89 {  
  4.  90         union {  
  5.  91                 struct nvif_ioctl_new_v0 v0;  
  6.  92         } *args = data;  
  7.  93         struct nouveau_client *client = nouveau_client(parent->object);  
  8.  94         struct nouveau_object *engctx = NULL;  
  9.  95         struct nouveau_object *object = NULL;  
  10.  96         struct nouveau_object *engine;  
  11.  97         struct nouveau_oclass *oclass;  
  12.  98         struct nouveau_handle *handle;  
  13.  99         u32 _handle, _oclass;  
  14. 100         int ret;  
  15. 101   
  16. 102         nv_ioctl(client, "new size %d\n", size);  
  17. 103         if (nvif_unpack(args->v0, 0, 0, true)) {  
  18. 104                 _handle = args->v0.handle;  
  19. 105                 _oclass = args->v0.oclass;  
  20. 106         } else  
  21. 107                 return ret;  
  22. 108   
  23. 109         nv_ioctl(client, "new vers %d handle %08x class %08x "  
  24. 110                          "route %02x token %llx\n",  
  25. 111                 args->v0.version, _handle, _oclass,  
  26. 112                 args->v0.route, args->v0.token);  
  27. 113   
  28. 114         if (!nv_iclass(parent->object, NV_PARENT_CLASS)) {  
  29. 115                 nv_debug(parent->object, "cannot have children (ctor)\n");  
  30. 116                 ret = -ENODEV;  
  31. 117                 goto fail_class;  
  32. 118         }  
  33. 119   
  34. 120         /* check that parent supports the requested subclass */  
  35. 121         ret = nouveau_parent_sclass(parent->object, _oclass, &engine, &oclass);  
  36. 122         if (ret) {  
  37. 123                 nv_debug(parent->object, "illegal class 0x%04x\n", _oclass);  
  38. 124                 goto fail_class;  
  39. 125         }  
  40. 126   
  41. 127         /* make sure engine init has been completed *before* any objects 
  42. 128          * it controls are created - the constructors may depend on 
  43. 129          * state calculated at init (ie. default context construction) 
  44. 130          */  
  45. 131         if (engine) {  
  46. 132                 ret = nouveau_object_inc(engine);  
  47. 133                 if (ret)  
  48. 134                         goto fail_class;  
  49. 135         }  
  50. 136   
  51. 137         /* if engine requires it, create a context object to insert 
  52. 138          * between the parent and its children (eg. PGRAPH context) 
  53. 139          */  
  54. 140         if (engine && nv_engine(engine)->cclass) {  
  55. 141                 ret = nouveau_object_ctor(parent->object, engine,  
  56. 142                                           nv_engine(engine)->cclass,  
  57. 143                                           data, size, &engctx);  
  58. 144                 if (ret)  
  59. 145                         goto fail_engctx;  
  60. 146         } else {  
  61. 147                 nouveau_object_ref(parent->object, &engctx);  
  62. 148         }  
  63. 149   
  64. 150         /* finally, create new object and bind it to its handle */  
  65. 151         ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);  
  66. 152         client->data = object;  
  67. 153         if (ret)  
  68. 154                 goto fail_ctor;  
  69. 155   
  70. 156         ret = nouveau_object_inc(object);  
  71. 157         if (ret)  
  72. 158                 goto fail_init;  
  73. 159   
  74. 160         ret = nouveau_handle_create(parent->object, parent->name,  
  75. 161                                     _handle, object, &handle);  
  76. 162         if (ret)  
  77. 163                 goto fail_handle;  
  78. 164   
  79. 165         ret = nouveau_handle_init(handle);  
  80. 166         handle->route = args->v0.route;  
  81. 167         handle->token = args->v0.token;  
  82. 168         if (ret)  
  83. 169                 nouveau_handle_destroy(handle);  
  84. 170   
  85. 171 fail_handle:  
  86. 172         nouveau_object_dec(object, false);  
  87. 173 fail_init:  
  88. 174         nouveau_object_ref(NULL, &object);  
  89. 175 fail_ctor:  
  90. 176         nouveau_object_ref(NULL, &engctx);  
  91. 177 fail_engctx:  
  92. 178         if (engine)  
  93. 179                 nouveau_object_dec(engine, false);  
  94. 180 fail_class:  
  95. 181         return ret;  
  96. 182 }  
第103行,再次使用nvif_unpack检查参数的正确性.

第121行,这就是u32 oclass到nouveau_oclass *oclass的转换了.

  1. // /drivers/gpu/drm/nouveau/core/core/parent.c  
  2.  29 int  
  3.  30 nouveau_parent_sclass(struct nouveau_object *parent, u16 handle,  
  4.  31                       struct nouveau_object **pengine,  
  5.  32                       struct nouveau_oclass **poclass)  
  6.  33 {  
  7.  34         struct nouveau_sclass *sclass;  
  8.  35         struct nouveau_engine *engine;  
  9.  36         struct nouveau_oclass *oclass;  
  10.  37         u64 mask;  
  11.  38   
  12.  39         sclass = nv_parent(parent)->sclass;  
  13.  40         while (sclass) {  
  14.  41                 if ((sclass->oclass->handle & 0xffff) == handle) {  
  15.  42                         *pengine = parent->engine;  
  16.  43                         *poclass = sclass->oclass;  
  17.  44                         return 0;  
  18.  45                 }  
  19.  46   
  20.  47                 sclass = sclass->sclass;  
  21.  48         }  
  22.  49   
  23.  50         mask = nv_parent(parent)->engine;  
  24.  51         while (mask) {  
  25.  52                 int i = __ffs64(mask);  
  26.  53   
  27.  54                 if (nv_iclass(parent, NV_CLIENT_CLASS))  
  28.  55                         engine = nv_engine(nv_client(parent)->device);  
  29.  56                 else  
  30.  57                         engine = nouveau_engine(parent, i);  
  31.  58   
  32.  59                 if (engine) {  
  33.  60                         oclass = engine->sclass;  
  34.  61                         while (oclass->ofuncs) {  
  35.  62                                 if ((oclass->handle & 0xffff) == handle) {  
  36.  63                                         *pengine = nv_object(engine);  
  37.  64                                         *poclass = oclass;  
  38.  65                                         return 0;  
  39.  66                                 }  
  40.  67                                 oclass++;  
  41.  68                         }  
  42.  69                 }  
  43.  70   
  44.  71                 mask &= ~(1ULL << i);  
  45.  72         }  
  46.  73   
  47.  74         return -EINVAL;  
  48.  75 }  
首先第40行的while语句,直接在parent->sclass中寻找,这个东西可以看作是一个单向链表. 对于这个例子,parent->sclass为0,故不存在这种可能性.

然后第52行,从((nouveau_parent *)parent)->engine指示的subdev中寻找. __ffs64返回的是二进制中第一个为1的位是第几位. 比如0b1返回0 ,0b1000返回3.

如果parent不是一个nouveau_client对象,那么就先向上获取一个nouveau_device对象,然后返回device->subdev[i] .

如果parent是一个nouveau_client对象,那么直接使用client->device.

对于本例当然是后者,也就是直接使用我们在第三篇中用nouveau_device_create创建的那个nouveau_device *device. (此处需要注意nouveau_parent::sclass是个单向链表,但nouveau_device::sclass是个数组.)

还记得当初传递进去的sclass是什么吗?

  1. // /drivers/gpu/drm/nouveau/core/engine/device/base.c  
  2. 501 static struct nouveau_oclass  
  3. 502 nouveau_device_sclass[] = {  
  4. 503         { 0x0080, &nouveau_devobj_ofuncs },  
  5. 504         {}  
  6. 505 };  
看看我们现在的这个oclass是什么:

  1. // /drivers/gpu/drm/nouveau/core/include/nvif/class.h  
  2.   9 #define NV_DEVICE                                                    0x00000080  

匹配成功! 于是对pengine和poclass进行赋值操作,返回.

第132行,对engine执行nouveau_object_inc函数:

  1. // /drivers/gpu/drm/nouveau/core/core/object.c  
  2. 164 int  
  3. 165 nouveau_object_inc(struct nouveau_object *object)  
  4. 166 {  
  5. 167         int ref = atomic_add_return(1, &object->usecount);  
  6. 168         int ret;  
  7. 169   
  8. 170         nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));  
  9. 171         if (ref != 1)  
  10. 172                 return 0;  
  11. 173   
  12. 174         nv_trace(object, "initialising...\n");  
  13. 175         if (object->parent) {  
  14. 176                 ret = nouveau_object_inc(object->parent);  
  15. 177                 if (ret) {  
  16. 178                         nv_error(object, "parent failed, %d\n", ret);  
  17. 179                         goto fail_parent;  
  18. 180                 }  
  19. 181         }  
  20. 182   
  21. 183         if (object->engine) {  
  22. 184                 mutex_lock(&nv_subdev(object->engine)->mutex);  
  23. 185                 ret = nouveau_object_inc(object->engine);  
  24. 186                 mutex_unlock(&nv_subdev(object->engine)->mutex);  
  25. 187                 if (ret) {  
  26. 188                         nv_error(object, "engine failed, %d\n", ret);  
  27. 189                         goto fail_engine;  
  28. 190                 }  
  29. 191         }  
  30. 192   
  31. 193         ret = nv_ofuncs(object)->init(object);  
  32. 194         atomic_set(&object->usecount, 1);  
  33. 195         if (ret) {  
  34. 196                 nv_error(object, "init failed, %d\n", ret);  
  35. 197                 goto fail_self;  
  36. 198         }  
  37. 199   
  38. 200         nv_trace(object, "initialised\n");  
  39. 201         return 0;  
  40. 202   
  41. 203 fail_self:  
  42. 204         if (object->engine) {  
  43. 205                 mutex_lock(&nv_subdev(object->engine)->mutex);  
  44. 206                 nouveau_object_dec(object->engine, false);  
  45. 207                 mutex_unlock(&nv_subdev(object->engine)->mutex);  
  46. 208         }  
  47. 209 fail_engine:  
  48. 210         if (object->parent)  
  49. 211                  nouveau_object_dec(object->parent, false);  
  50. 212 fail_parent:  
  51. 213         atomic_dec(&object->usecount);  
  52. 214         return ret;  
  53. 215 }  
因此这是第一次执行nouveau_object_inc函数,所以第171行并没有返回.

然后第176行,对parent执行inc操作,第185行,对engine执行inc操作. 此处对由于parent和engine都为0,所以并没有执行进这两个if语句.

第193行,执行oclass里的init函数:

  1. // /drivers/gpu/drm/nouveau/core/engine/device/base.c  
  2. 652 static struct nouveau_oclass  
  3. 653 nouveau_device_oclass = {  
  4. 654         .handle = NV_ENGINE(DEVICE, 0x00),  
  5. 655         .ofuncs = &(struct nouveau_ofuncs) {  
  6. 656                 .dtor = nouveau_device_dtor,  
  7. 657                 .init = nouveau_device_init,  
  8. 658                 .fini = nouveau_device_fini,  
  9. 659         },  
  10. 660 };  
  1. // /drivers/gpu/drm/nouveau/core/engine/device/base.c  
  2. 557 static int  
  3. 558 nouveau_device_init(struct nouveau_object *object)  
  4. 559 {  
  5. 560         struct nouveau_device *device = (void *)object;  
  6. 561         struct nouveau_object *subdev;  
  7. 562         int ret, i = 0;  
  8. 563   
  9. 564         ret = nvkm_acpi_init(device);  
  10. 565         if (ret)  
  11. 566                 goto fail;  
  12. 567   
  13. 568         for (i = 0; i < NVDEV_SUBDEV_NR; i++) {  
  14. 569                 if ((subdev = device->subdev[i])) {  
  15. 570                         if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {  
  16. 571                                 ret = nouveau_object_inc(subdev);  
  17. 572                                 if (ret)  
  18. 573                                         goto fail;  
  19. 574                         } else {  
  20. 575                                 nouveau_subdev_reset(subdev);  
  21. 576                         }  
  22. 577                 }  
  23. 578         }  
  24. 579   
  25. 580         ret = 0;  
  26. 581 fail:  
  27. 582         for (--i; ret && i >= 0; i--) {  
  28. 583                 if ((subdev = device->subdev[i])) {  
  29. 584                         if (!nv_iclass(subdev, NV_ENGINE_CLASS))  
  30. 585                                 nouveau_object_dec(subdev, false);  
  31. 586                 }  
  32. 587         }  
  33. 588   
  34. 589         if (ret)  
  35. 590                 nvkm_acpi_fini(device, false);  
  36. 591         return ret;  
  37. 592 }  
首先第564行执行nvkm_acpi_init,这个函数对ACPI模块注册了一个回调函数,当AC Adapter发出事件时就触发device->event,然后这个事件会在clock中被受理. 暂时不展开说了.

接下来第568行的for语句,遍历一下device->subdev,执行nouveau_object_inc或者nouveau_subdev_reset. 

然后第582行的for语句,再遍历一遍执行nouveau_object_dec. 前面执行一次inc,这里再执行一次dec,也就相当于reset了. 所以这段代码的作用就是reset所有subdev..

但现在subdev还没有被初始化,因此所有if语句都不会进入,所以啥也没做直接返回.

回到nvkm_ioctl_new,第141行,检查engine有没有cclass,有的话创建一个context object,对于这个例子没有.

第151行,创建一个nvif_object对应的nouveau_object:

  1. // /drivers/gpu/drm/nouveau/core/core/object.c  
  2. 105 int  
  3. 106 nouveau_object_ctor(struct nouveau_object *parent,  
  4. 107                     struct nouveau_object *engine,  
  5. 108                     struct nouveau_oclass *oclass, void *data, u32 size,  
  6. 109                     struct nouveau_object **pobject)  
  7. 110 {  
  8. 111         struct nouveau_ofuncs *ofuncs = oclass->ofuncs;  
  9. 112         struct nouveau_object *object = NULL;  
  10. 113         int ret;  
  11. 114   
  12. 115         ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);  
  13. 116         *pobject = object;  
  14. 117         if (ret < 0) {  
  15. 118                 if (ret != -ENODEV) {  
  16. 119                         nv_error(parent, "failed to create 0x%08x, %d\n",  
  17. 120                                  oclass->handle, ret);  
  18. 121                 }  
  19. 122   
  20. 123                 if (object) {  
  21. 124                         ofuncs->dtor(object);  
  22. 125                         *pobject = NULL;  
  23. 126                 }  
  24. 127   
  25. 128                 return ret;  
  26. 129         }  
  27. 130   
  28. 131         if (ret == 0) {  
  29. 132                 nv_trace(object, "created\n");  
  30. 133                 atomic_set(&object->refcount, 1);  
  31. 134         }  
  32. 135   
  33. 136         return 0;  
  34. 137 }  
这个函数就是调用了一下oclass里的ctor函数,然后进行错误检查,出错就销毁一下. 第133行,再初始化一下refcount,返回.

对于这个例子,对应的是"nouveau_devobj_init",这又是一个超级长的函数,所以决定下一篇单独描述这个函数,现在只需要知道它对设备的类型进行了检测,然后初始化了各个subdev就可以了.

再看nvkm_ioctl_new的第156行,对新创建的nouveau_object执行nouveau_object_inc操作,将会调用它的oclass里对应的init函数,对于这个例子是个空函数,无视.

第160行,创建一个nouveau_handle,它将会被自动加入到对应的namedb中,下一次我们就能从namedb中找到这个nouveau_object了.

第165行,执行一个nouveau_handle_init函数,这个函数首先执行nouveau_object_inc(handle->object); 然后对handle->tree链表里储存的所有children进行nouveau_handle_init操作.

然后第166行,把route和token储存到handle里.

最后第171行到第181行,进行一些清理操作,返回. [这些清理操作绝对不会执行任何对象的析构函数,或者导致内存释放. 因为这些对象均已经在其他地方被引用. (除非是出错之后用goto跳过来的,那种情况另说.)]

于是我们一路回到了nvif_device_init, 第43行,发送一个mthd ioctl,作用是获取设备信息储存到device->info里,这个同样留到下一篇在说.

然后我们回到了nouveau_drm_load的第395行,这一篇就先写到这里了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: nouveau 0000:01:00.0 是一种开源 NVIDIA 驱动程序,它通过 Linux 内核中的 DRM 框架与 NVIDIA 显卡进行交互。这个编号表示它正在使用第 1 个 PCI 总线上的第 0 个设备,也就是显卡。 ### 回答2: nouveau 0000:01:00.0 是一个Linux内核中的驱动程序,它用来支持NVIDIA的图形处理器。这个驱动程序是开源的,由社区开发和维护。在Linux系统中,它提供了对NVIDIA显卡的开源支持,使得用户可以在Linux系统中使用NVIDIA显卡进行图形计算、游戏和其他图形相关的任务。 0000:01:00.0 是NVIDIA显卡在计算机系统中的物理地址。在计算机硬件中,每个设备都有一个唯一的物理地址,用来标识它在计算机总线上的位置。0000:01:00.0 表示该显卡位于PCI总线上的第一个插槽,也就是编号为0x01的插槽。 通过nouveau 0000:01:00.0 驱动程序,Linux系统可以与这个NVIDIA显卡进行通信,并运行相关的应用程序。这个驱动程序提供了图形加速、视频解码、显示输出等核心功能,保证了NVIDIA显卡在Linux系统中的正常工作。 nouveau驱动程序是由社区团队开发和维护的,因此它通常与操作系统的发行版本捆绑在一起。用户在安装Linux操作系统后,通常会自动获取、安装和配置nouveau驱动程序。然而,有时用户也可以选择手动下载和安装最新版本的驱动程序,以获取更好的性能和支持。 总之,nouveau 0000:01:00.0 是一个Linux系统中用来支持NVIDIA显卡的开源驱动程序。它提供了对显卡的核心功能支持,使得用户可以在Linux系统中充分利用NVIDIA显卡的图形处理能力。 ### 回答3: nouveau是一个开源的显卡驱动程序,用于支持NVIDIA的显卡。0000:01:00.0则代表着PCI总线上的一个设备地址,用于唯一标识一块显卡。 在计算机中,显卡是用于处理和呈现图形的硬件设备。而NVIDIA是一个著名的显卡制造商,其产品在高性能计算、游戏和数据处理等领域广泛使用。nouveau则是为NVIDIA显卡开发的一个开源驱动程序,它的目的是提供一种免费的、开放源代码的解决方案,取代NVIDIA官方闭源驱动。 而0000:01:00.0这个地址则是唯一标识一块显卡的方式之一,它采用PCI总线的寻址方式。在计算机系统中,每个设备都会有一个唯一的地址,这使得操作系统能够准确地找到设备并与其进行通信。因此,0000:01:00.0可以被看作是一块显卡在计算机中的身份证明。 总而言之,nouveau 0000:01:00.0代表着一块使用开源驱动的NVIDIA显卡,在计算机中具有唯一的地址,并且可以通过该地址进行准确的通信和操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值