Nouveau源码分析(五)
接着上一篇来,先把nouveau_drm_load再贴出一遍来吧:
- // /drivers/gpu/drm/nouveau/nouveau_drm.c
- 364 static int
- 365 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 we
- 387 * (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 allows
- 393 * agp code access to registers
- 394 */
- 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's
- 424 * nosnoop capability. hopefully won't cause issues until a
- 425 * 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 }
- // /drivers/gpu/drm/nouveau/nvif/object.c
- 217 int
- 218 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 }
第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 }
- // /drivers/gpu/drm/nouveau/core/core/ioctl.c
- 502 int
- 503 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 }
然后第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.c
- 459 static int
- 460 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 }
第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.c
- 439 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 };
- 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 } else
- 107 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 objects
- 128 * it controls are created - the constructors may depend on
- 129 * 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 insert
- 138 * 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 }
第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 }
然后第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.c
- 501 static struct nouveau_oclass
- 502 nouveau_device_sclass[] = {
- 503 { 0x0080, &nouveau_devobj_ofuncs },
- 504 {}
- 505 };
- // /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.c
- 164 int
- 165 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 }
然后第176行,对parent执行inc操作,第185行,对engine执行inc操作. 此处对由于parent和engine都为0,所以并没有执行进这两个if语句.
第193行,执行oclass里的init函数:
- // /drivers/gpu/drm/nouveau/core/engine/device/base.c
- 652 static struct nouveau_oclass
- 653 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.c
- 557 static int
- 558 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 }
接下来第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.c
- 105 int
- 106 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 }
对于这个例子,对应的是"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行,这一篇就先写到这里了.