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

来源:互联网 发布:屏幕尺寸测量软件 编辑:程序博客网 时间:2024/05/21 21:59

Nouveau源码分析(五)

接着上一篇来,先把nouveau_drm_load再贴出一遍来吧:

// /drivers/gpu/drm/nouveau/nouveau_drm.c364 static int365 nouveau_drm_load(struct drm_device *dev, unsigned long flags)366 {367         struct pci_dev *pdev = dev->pdev;368         struct nouveau_drm *drm;369         int ret;370 371         ret = nouveau_cli_create(nouveau_name(dev), "DRM", sizeof(*drm),372                                  (void **)&drm);373         if (ret)374                 return ret;375 376         dev->dev_private = drm;377         drm->dev = dev;378         nvkm_client(&drm->client.base)->debug =379                 nouveau_dbgopt(nouveau_debug, "DRM");380 381         INIT_LIST_HEAD(&drm->clients);382         spin_lock_init(&drm->tile.lock);383 384         nouveau_get_hdmi_dev(drm);385 386         /* make sure AGP controller is in a consistent state before we387          * (possibly) execute vbios init tables (see nouveau_agp.h)388          */389         if (pdev && drm_pci_device_is_agp(dev) && dev->agp) {390                 const u64 enables = NV_DEVICE_V0_DISABLE_IDENTIFY |391                                     NV_DEVICE_V0_DISABLE_MMIO;392                 /* dummy device object, doesn't init anything, but allows393                  * agp code access to registers394                  */395                 ret = nvif_device_init(&drm->client.base.base, NULL,396                                        NVDRM_DEVICE, NV_DEVICE,397                                        &(struct nv_device_v0) {398                                                 .device = ~0,399                                                 .disable = ~enables,400                                                 .debug0 = ~0,401                                        }, sizeof(struct nv_device_v0),402                                        &drm->device);403                 if (ret)404                         goto fail_device;405 406                 nouveau_agp_reset(drm);407                 nvif_device_fini(&drm->device);408         }409 410         ret = nvif_device_init(&drm->client.base.base, NULL, NVDRM_DEVICE,411                                NV_DEVICE,412                                &(struct nv_device_v0) {413                                         .device = ~0,414                                         .disable = 0,415                                         .debug0 = 0,416                                }, sizeof(struct nv_device_v0),417                                &drm->device);418         if (ret)419                 goto fail_device;420 421         dev->irq_enabled = true;422 423         /* workaround an odd issue on nvc1 by disabling the device's424          * nosnoop capability.  hopefully won't cause issues until a425          * better fix is found - assuming there is one...426          */427         if (drm->device.info.chipset == 0xc1)428                 nvif_mask(&drm->device, 0x00088080, 0x00000800, 0x00000000);429 430         nouveau_vga_init(drm);431         nouveau_agp_init(drm);432 433         if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {434                 ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40),435                                      0x1000, &drm->client.vm);436                 if (ret)437                         goto fail_device;438 439                 nvkm_client(&drm->client.base)->vm = drm->client.vm;440         }441 442         ret = nouveau_ttm_init(drm);443         if (ret)444                 goto fail_ttm;445 446         ret = nouveau_bios_init(dev);447         if (ret)448                 goto fail_bios;449 450         ret = nouveau_display_create(dev);451         if (ret)452                 goto fail_dispctor;453 454         if (dev->mode_config.num_crtc) {455                 ret = nouveau_display_init(dev);456                 if (ret)457                         goto fail_dispinit;458         }459 460         nouveau_sysfs_init(dev);461         nouveau_hwmon_init(dev);462         nouveau_accel_init(drm);463         nouveau_fbcon_init(dev);464 465         if (nouveau_runtime_pm != 0) {466                 pm_runtime_use_autosuspend(dev->dev);467                 pm_runtime_set_autosuspend_delay(dev->dev, 5000);468                 pm_runtime_set_active(dev->dev);469                 pm_runtime_allow(dev->dev);470                 pm_runtime_mark_last_busy(dev->dev);471                 pm_runtime_put(dev->dev);472         }473         return 0;474 475 fail_dispinit:476         nouveau_display_destroy(dev);477 fail_dispctor:478         nouveau_bios_takedown(dev);479 fail_bios:480         nouveau_ttm_fini(drm);481 fail_ttm:482         nouveau_agp_fini(drm);483         nouveau_vga_fini(drm);484 fail_device:485         nvif_device_fini(&drm->device);486         nouveau_cli_destroy(&drm->client);487         return ret;488 }

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

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

// /drivers/gpu/drm/nouveau/nvif/object.c217 int218 nvif_object_init(struct nvif_object *parent, void (*dtor)(struct nvif_object *),219                  u32 handle, u32 oclass, void *data, u32 size,220                  struct nvif_object *object)221 {222         struct ctor *ctor;223         int ret = 0;224 225         object->parent = NULL;226         object->object = object;227         nvif_object_ref(parent, &object->parent);228         kref_init(&object->refcount);229         object->handle = handle;230         object->oclass = oclass;231         object->data = NULL;232         object->size = 0;233         object->dtor = dtor;234         object->map.ptr = NULL;235         object->map.size = 0;236 237         if (object->parent) {238                 if (!(ctor = kmalloc(sizeof(*ctor) + size, GFP_KERNEL))) {239                         nvif_object_fini(object);240                         return -ENOMEM;241                 }242                 object->data = ctor->new.data;243                 object->size = size;244                 memcpy(object->data, data, size);245 246                 ctor->ioctl.version = 0;247                 ctor->ioctl.type = NVIF_IOCTL_V0_NEW;248                 ctor->new.version = 0;249                 ctor->new.route = NVIF_IOCTL_V0_ROUTE_NVIF;250                 ctor->new.token = (unsigned long)(void *)object;251                 ctor->new.handle = handle;252                 ctor->new.oclass = oclass;253 254                 ret = nvif_object_ioctl(parent, ctor, sizeof(*ctor) +255                                         object->size, &object->priv);256         }257 258         if (ret)259                 nvif_object_fini(object);260         return ret;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函数.

// /drivers/gpu/drm/nouveau/nvif/object.c 30 int 31 nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) 32 { 33         struct nvif_client *client = nvif_client(object); 34         union { 35                 struct nvif_ioctl_v0 v0; 36         } *args = data; 37  38         if (size >= sizeof(*args) && args->v0.version == 0) { 39                 args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY; 40                 args->v0.path_nr = 0; 41                 while (args->v0.path_nr < ARRAY_SIZE(args->v0.path)) { 42                         args->v0.path[args->v0.path_nr++] = object->handle; 43                         if (object->parent == object) 44                                 break; 45                         object = object->parent; 46                 } 47         } else 48                 return -ENOSYS; 49  50         return client->driver->ioctl(client->base.priv, client->super, data, size, hack); 51 }

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

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

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

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

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

// /drivers/gpu/drm/nouveau/core/core/ioctl.c502 int503 nvkm_ioctl(struct nouveau_client *client, bool supervisor,504            void *data, u32 size, void **hack)505 {506         union {507                 struct nvif_ioctl_v0 v0;508         } *args = data;509         int ret;510 511         client->super = supervisor;512         nv_ioctl(client, "size %d\n", size);513 514         if (nvif_unpack(args->v0, 0, 0, true)) {515                 nv_ioctl(client, "vers %d type %02x path %d owner %02x\n",516                          args->v0.version, args->v0.type, args->v0.path_nr,517                          args->v0.owner);518                 ret = nvkm_ioctl_path(client->root, args->v0.type,519                                       args->v0.path_nr, args->v0.path,520                                       data, size, args->v0.owner,521                                      &args->v0.route, &args->v0.token);522         }523 524         nv_ioctl(client, "return %d\n", ret);525         if (hack) {526                 *hack = client->data;527                 client->data = NULL;528         }529         client->super = false;530         return ret;531 }
client->super意义不明,忽略之.

然后第514行,看看nvif_unpack:

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

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

第518行,调用nvkm_ioctl_path.

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

重点看nvkm_ioctl_path:

// /drivers/gpu/drm/nouveau/core/core/ioctl.c459 static int460 nvkm_ioctl_path(struct nouveau_handle *parent, u32 type, u32 nr,461                   u32 *path, void *data, u32 size,462                   u8 owner, u8 *route, u64 *token)463 {464         struct nouveau_handle *handle = parent;465         struct nouveau_namedb *namedb;466         struct nouveau_object *object;467         int ret;468 469         while ((object = parent->object), nr--) {470                 nv_ioctl(object, "path 0x%08x\n", path[nr]);471                 if (!nv_iclass(object, NV_PARENT_CLASS)) {472                         nv_debug(object, "cannot have children (path)\n");473                         return -EINVAL;474                 }475 476                 if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) ||477                     !(handle = nouveau_namedb_get(namedb, path[nr]))) {478                         nv_debug(object, "handle 0x%08x not found\n", path[nr]);479                         return -ENOENT;480                 }481                 nouveau_namedb_put(handle);482                 parent = handle;483         }484 485         if (owner != NVIF_IOCTL_V0_OWNER_ANY &&486             owner != handle->route) {487                 nv_ioctl(object, "object route != owner\n");488                 return -EACCES;489         }490         *route = handle->route;491         *token = handle->token;492 493         if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {494                 if (nvkm_ioctl_v0[type].version == 0) {495                         ret = nvkm_ioctl_v0[type].func(handle, data, size);496                 }497         }498 499         return ret;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函数.

// /drivers/gpu/drm/nouveau/core/core/ioctl.c439 static struct {440         int version;441         int (*func)(struct nouveau_handle *, void *, u32);442 }443 nvkm_ioctl_v0[] = {444         { 0x00, nvkm_ioctl_nop },445         { 0x00, nvkm_ioctl_sclass },446         { 0x00, nvkm_ioctl_new },447         { 0x00, nvkm_ioctl_del },448         { 0x00, nvkm_ioctl_mthd },449         { 0x00, nvkm_ioctl_rd },450         { 0x00, nvkm_ioctl_wr },451         { 0x00, nvkm_ioctl_map },452         { 0x00, nvkm_ioctl_unmap },453         { 0x00, nvkm_ioctl_ntfy_new },454         { 0x00, nvkm_ioctl_ntfy_del },455         { 0x00, nvkm_ioctl_ntfy_get },456         { 0x00, nvkm_ioctl_ntfy_put },457 };
本例当然是nvkm_ioctl_new,来看一下这个函数:

 87 static int 88 nvkm_ioctl_new(struct nouveau_handle *parent, void *data, u32 size) 89 { 90         union { 91                 struct nvif_ioctl_new_v0 v0; 92         } *args = data; 93         struct nouveau_client *client = nouveau_client(parent->object); 94         struct nouveau_object *engctx = NULL; 95         struct nouveau_object *object = NULL; 96         struct nouveau_object *engine; 97         struct nouveau_oclass *oclass; 98         struct nouveau_handle *handle; 99         u32 _handle, _oclass;100         int ret;101 102         nv_ioctl(client, "new size %d\n", size);103         if (nvif_unpack(args->v0, 0, 0, true)) {104                 _handle = args->v0.handle;105                 _oclass = args->v0.oclass;106         } else107                 return ret;108 109         nv_ioctl(client, "new vers %d handle %08x class %08x "110                          "route %02x token %llx\n",111                 args->v0.version, _handle, _oclass,112                 args->v0.route, args->v0.token);113 114         if (!nv_iclass(parent->object, NV_PARENT_CLASS)) {115                 nv_debug(parent->object, "cannot have children (ctor)\n");116                 ret = -ENODEV;117                 goto fail_class;118         }119 120         /* check that parent supports the requested subclass */121         ret = nouveau_parent_sclass(parent->object, _oclass, &engine, &oclass);122         if (ret) {123                 nv_debug(parent->object, "illegal class 0x%04x\n", _oclass);124                 goto fail_class;125         }126 127         /* make sure engine init has been completed *before* any objects128          * it controls are created - the constructors may depend on129          * state calculated at init (ie. default context construction)130          */131         if (engine) {132                 ret = nouveau_object_inc(engine);133                 if (ret)134                         goto fail_class;135         }136 137         /* if engine requires it, create a context object to insert138          * between the parent and its children (eg. PGRAPH context)139          */140         if (engine && nv_engine(engine)->cclass) {141                 ret = nouveau_object_ctor(parent->object, engine,142                                           nv_engine(engine)->cclass,143                                           data, size, &engctx);144                 if (ret)145                         goto fail_engctx;146         } else {147                 nouveau_object_ref(parent->object, &engctx);148         }149 150         /* finally, create new object and bind it to its handle */151         ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);152         client->data = object;153         if (ret)154                 goto fail_ctor;155 156         ret = nouveau_object_inc(object);157         if (ret)158                 goto fail_init;159 160         ret = nouveau_handle_create(parent->object, parent->name,161                                     _handle, object, &handle);162         if (ret)163                 goto fail_handle;164 165         ret = nouveau_handle_init(handle);166         handle->route = args->v0.route;167         handle->token = args->v0.token;168         if (ret)169                 nouveau_handle_destroy(handle);170 171 fail_handle:172         nouveau_object_dec(object, false);173 fail_init:174         nouveau_object_ref(NULL, &object);175 fail_ctor:176         nouveau_object_ref(NULL, &engctx);177 fail_engctx:178         if (engine)179                 nouveau_object_dec(engine, false);180 fail_class:181         return ret;182 }
第103行,再次使用nvif_unpack检查参数的正确性.

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

// /drivers/gpu/drm/nouveau/core/core/parent.c 29 int 30 nouveau_parent_sclass(struct nouveau_object *parent, u16 handle, 31                       struct nouveau_object **pengine, 32                       struct nouveau_oclass **poclass) 33 { 34         struct nouveau_sclass *sclass; 35         struct nouveau_engine *engine; 36         struct nouveau_oclass *oclass; 37         u64 mask; 38  39         sclass = nv_parent(parent)->sclass; 40         while (sclass) { 41                 if ((sclass->oclass->handle & 0xffff) == handle) { 42                         *pengine = parent->engine; 43                         *poclass = sclass->oclass; 44                         return 0; 45                 } 46  47                 sclass = sclass->sclass; 48         } 49  50         mask = nv_parent(parent)->engine; 51         while (mask) { 52                 int i = __ffs64(mask); 53  54                 if (nv_iclass(parent, NV_CLIENT_CLASS)) 55                         engine = nv_engine(nv_client(parent)->device); 56                 else 57                         engine = nouveau_engine(parent, i); 58  59                 if (engine) { 60                         oclass = engine->sclass; 61                         while (oclass->ofuncs) { 62                                 if ((oclass->handle & 0xffff) == handle) { 63                                         *pengine = nv_object(engine); 64                                         *poclass = oclass; 65                                         return 0; 66                                 } 67                                 oclass++; 68                         } 69                 } 70  71                 mask &= ~(1ULL << i); 72         } 73  74         return -EINVAL; 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是什么吗?

// /drivers/gpu/drm/nouveau/core/engine/device/base.c501 static struct nouveau_oclass502 nouveau_device_sclass[] = {503         { 0x0080, &nouveau_devobj_ofuncs },504         {}505 };
看看我们现在的这个oclass是什么:

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

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

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

// /drivers/gpu/drm/nouveau/core/core/object.c164 int165 nouveau_object_inc(struct nouveau_object *object)166 {167         int ref = atomic_add_return(1, &object->usecount);168         int ret;169 170         nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));171         if (ref != 1)172                 return 0;173 174         nv_trace(object, "initialising...\n");175         if (object->parent) {176                 ret = nouveau_object_inc(object->parent);177                 if (ret) {178                         nv_error(object, "parent failed, %d\n", ret);179                         goto fail_parent;180                 }181         }182 183         if (object->engine) {184                 mutex_lock(&nv_subdev(object->engine)->mutex);185                 ret = nouveau_object_inc(object->engine);186                 mutex_unlock(&nv_subdev(object->engine)->mutex);187                 if (ret) {188                         nv_error(object, "engine failed, %d\n", ret);189                         goto fail_engine;190                 }191         }192 193         ret = nv_ofuncs(object)->init(object);194         atomic_set(&object->usecount, 1);195         if (ret) {196                 nv_error(object, "init failed, %d\n", ret);197                 goto fail_self;198         }199 200         nv_trace(object, "initialised\n");201         return 0;202 203 fail_self:204         if (object->engine) {205                 mutex_lock(&nv_subdev(object->engine)->mutex);206                 nouveau_object_dec(object->engine, false);207                 mutex_unlock(&nv_subdev(object->engine)->mutex);208         }209 fail_engine:210         if (object->parent)211                  nouveau_object_dec(object->parent, false);212 fail_parent:213         atomic_dec(&object->usecount);214         return ret;215 }
因此这是第一次执行nouveau_object_inc函数,所以第171行并没有返回.

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

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

// /drivers/gpu/drm/nouveau/core/engine/device/base.c652 static struct nouveau_oclass653 nouveau_device_oclass = {654         .handle = NV_ENGINE(DEVICE, 0x00),655         .ofuncs = &(struct nouveau_ofuncs) {656                 .dtor = nouveau_device_dtor,657                 .init = nouveau_device_init,658                 .fini = nouveau_device_fini,659         },660 };
// /drivers/gpu/drm/nouveau/core/engine/device/base.c557 static int558 nouveau_device_init(struct nouveau_object *object)559 {560         struct nouveau_device *device = (void *)object;561         struct nouveau_object *subdev;562         int ret, i = 0;563 564         ret = nvkm_acpi_init(device);565         if (ret)566                 goto fail;567 568         for (i = 0; i < NVDEV_SUBDEV_NR; i++) {569                 if ((subdev = device->subdev[i])) {570                         if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {571                                 ret = nouveau_object_inc(subdev);572                                 if (ret)573                                         goto fail;574                         } else {575                                 nouveau_subdev_reset(subdev);576                         }577                 }578         }579 580         ret = 0;581 fail:582         for (--i; ret && i >= 0; i--) {583                 if ((subdev = device->subdev[i])) {584                         if (!nv_iclass(subdev, NV_ENGINE_CLASS))585                                 nouveau_object_dec(subdev, false);586                 }587         }588 589         if (ret)590                 nvkm_acpi_fini(device, false);591         return ret;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:

// /drivers/gpu/drm/nouveau/core/core/object.c105 int106 nouveau_object_ctor(struct nouveau_object *parent,107                     struct nouveau_object *engine,108                     struct nouveau_oclass *oclass, void *data, u32 size,109                     struct nouveau_object **pobject)110 {111         struct nouveau_ofuncs *ofuncs = oclass->ofuncs;112         struct nouveau_object *object = NULL;113         int ret;114 115         ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);116         *pobject = object;117         if (ret < 0) {118                 if (ret != -ENODEV) {119                         nv_error(parent, "failed to create 0x%08x, %d\n",120                                  oclass->handle, ret);121                 }122 123                 if (object) {124                         ofuncs->dtor(object);125                         *pobject = NULL;126                 }127 128                 return ret;129         }130 131         if (ret == 0) {132                 nv_trace(object, "created\n");133                 atomic_set(&object->refcount, 1);134         }135 136         return 0;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行,这一篇就先写到这里了.

1 0
原创粉丝点击