Nouveau源码分析(六)
上一篇中我们暂时忽略了两个函数,第一个是用于创建nvif_device对应的nouveau_object的ctor函数:
-
- 488 static struct nouveau_ofuncs
- 489 nouveau_devobj_ofuncs = {
- 490 .ctor = nouveau_devobj_ctor,
- 491 .dtor = nouveau_devobj_dtor,
- 492 .init = _nouveau_parent_init,
- 493 .fini = _nouveau_parent_fini,
- 494 .mthd = nouveau_devobj_mthd,
- 495 };
也就是对应的nouveau_devobj_ctor,这个函数的主要功能就是识别NVIDIA设备类型,然后初始化每一个subdev.
-
- 274 static int
- 275 nouveau_devobj_ctor(struct nouveau_object *parent,
- 276 struct nouveau_object *engine,
- 277 struct nouveau_oclass *oclass, void *data, u32 size,
- 278 struct nouveau_object **pobject)
- 279 {
- 280 union {
- 281 struct nv_device_v0 v0;
- 282 } *args = data;
- 283 struct nouveau_client *client = nv_client(parent);
- 284 struct nouveau_device *device;
- 285 struct nouveau_devobj *devobj;
- 286 u32 boot0, strap;
- 287 u64 disable, mmio_base, mmio_size;
- 288 void __iomem *map;
- 289 int ret, i, c;
- 290
- 291 nv_ioctl(parent, "create device size %d\n", size);
- 292 if (nvif_unpack(args->v0, 0, 0, false)) {
- 293 nv_ioctl(parent, "create device v%d device %016llx "
- 294 "disable %016llx debug0 %016llx\n",
- 295 args->v0.version, args->v0.device,
- 296 args->v0.disable, args->v0.debug0);
- 297 } else
- 298 return ret;
- 299
- 300
- 301 if (client->super)
- 302 oclass = &nouveau_devobj_oclass_super;
- 303
- 304
- 305 device = nv_device(client->device);
- 306 if (args->v0.device != ~0) {
- 307 device = nouveau_device_find(args->v0.device);
- 308 if (!device)
- 309 return -ENODEV;
- 310 }
- 311
- 312 ret = nouveau_parent_create(parent, nv_object(device), oclass, 0,
- 313 nouveau_control_oclass,
- 314 (1ULL << NVDEV_ENGINE_DMAOBJ) |
- 315 (1ULL << NVDEV_ENGINE_FIFO) |
- 316 (1ULL << NVDEV_ENGINE_DISP) |
- 317 (1ULL << NVDEV_ENGINE_PERFMON), &devobj);
- 318 *pobject = nv_object(devobj);
- 319 if (ret)
- 320 return ret;
- 321
- 322 mmio_base = nv_device_resource_start(device, 0);
- 323 mmio_size = nv_device_resource_len(device, 0);
- 324
- 325
- 326 disable = args->v0.debug0;
- 327 for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
- 328 if (args->v0.disable & disable_map[i])
- 329 disable |= (1ULL << i);
- 330 }
- 331
- 332
- 333 if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) &&
- 334 !device->card_type) {
- 335 map = ioremap(mmio_base, 0x102000);
- 336 if (map == NULL)
- 337 return -ENOMEM;
- 338
- 339
- 340 #ifndef __BIG_ENDIAN
- 341 if (ioread32_native(map + 0x000004) != 0x00000000)
- 342 #else
- 343 if (ioread32_native(map + 0x000004) == 0x00000000)
- 344 #endif
- 345 iowrite32_native(0x01000001, map + 0x000004);
- 346
- 347
- 348 boot0 = ioread32_native(map + 0x000000);
- 349 strap = ioread32_native(map + 0x101000);
- 350 iounmap(map);
- 351
- 352
- 353 if ((boot0 & 0x1f000000) > 0) {
- 354 device->chipset = (boot0 & 0x1ff00000) >> 20;
- 355 switch (device->chipset & 0x1f0) {
- 356 case 0x010: {
- 357 if (0x461 & (1 << (device->chipset & 0xf)))
- 358 device->card_type = NV_10;
- 359 else
- 360 device->card_type = NV_11;
- 361 break;
- 362 }
- 363 case 0x020: device->card_type = NV_20; break;
- 364 case 0x030: device->card_type = NV_30; break;
- 365 case 0x040:
- 366 case 0x060: device->card_type = NV_40; break;
- 367 case 0x050:
- 368 case 0x080:
- 369 case 0x090:
- 370 case 0x0a0: device->card_type = NV_50; break;
- 371 case 0x0c0:
- 372 case 0x0d0: device->card_type = NV_C0; break;
- 373 case 0x0e0:
- 374 case 0x0f0:
- 375 case 0x100: device->card_type = NV_E0; break;
- 376 case 0x110: device->card_type = GM100; break;
- 377 default:
- 378 break;
- 379 }
- 380 } else
- 381 if ((boot0 & 0xff00fff0) == 0x20004000) {
- 382 if (boot0 & 0x00f00000)
- 383 device->chipset = 0x05;
- 384 else
- 385 device->chipset = 0x04;
- 386 device->card_type = NV_04;
- 387 }
- 388
- 389 switch (device->card_type) {
- 390 case NV_04: ret = nv04_identify(device); break;
- 391 case NV_10:
- 392 case NV_11: ret = nv10_identify(device); break;
- 393 case NV_20: ret = nv20_identify(device); break;
- 394 case NV_30: ret = nv30_identify(device); break;
- 395 case NV_40: ret = nv40_identify(device); break;
- 396 case NV_50: ret = nv50_identify(device); break;
- 397 case NV_C0: ret = nvc0_identify(device); break;
- 398 case NV_E0: ret = nve0_identify(device); break;
- 399 case GM100: ret = gm100_identify(device); break;
- 400 default:
- 401 ret = -EINVAL;
- 402 break;
- 403 }
- 404
- 405 if (ret) {
- 406 nv_error(device, "unknown chipset, 0x%08x\n", boot0);
- 407 return ret;
- 408 }
- 409
- 410 nv_info(device, "BOOT0 : 0x%08x\n", boot0);
- 411 nv_info(device, "Chipset: %s (NV%02X)\n",
- 412 device->cname, device->chipset);
- 413 nv_info(device, "Family : NV%02X\n", device->card_type);
- 414
- 415
- 416 if ( device->card_type <= NV_10 || device->chipset < 0x17 ||
- 417 (device->chipset >= 0x20 && device->chipset < 0x25))
- 418 strap &= 0x00000040;
- 419 else
- 420 strap &= 0x00400040;
- 421
- 422 switch (strap) {
- 423 case 0x00000000: device->crystal = 13500; break;
- 424 case 0x00000040: device->crystal = 14318; break;
- 425 case 0x00400000: device->crystal = 27000; break;
- 426 case 0x00400040: device->crystal = 25000; break;
- 427 }
- 428
- 429 nv_debug(device, "crystal freq: %dKHz\n", device->crystal);
- 430 }
- 431
- 432 if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) &&
- 433 !nv_subdev(device)->mmio) {
- 434 nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size);
- 435 if (!nv_subdev(device)->mmio) {
- 436 nv_error(device, "unable to map device registers\n");
- 437 return -ENOMEM;
- 438 }
- 439 }
- 440
- 441
- 442 for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) {
- 443 if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
- 444 continue;
- 445
- 446 if (device->subdev[i]) {
- 447 nouveau_object_ref(device->subdev[i],
- 448 &devobj->subdev[i]);
- 449 continue;
- 450 }
- 451
- 452 ret = nouveau_object_ctor(nv_object(device), NULL,
- 453 oclass, NULL, i,
- 454 &devobj->subdev[i]);
- 455 if (ret == -ENODEV)
- 456 continue;
- 457 if (ret)
- 458 return ret;
- 459
- 460 device->subdev[i] = devobj->subdev[i];
- 461
- 462
-
-
-
-
-
-
-
-
- 471 while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
- 472 struct nouveau_object *subdev = devobj->subdev[c++];
- 473 if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
- 474 ret = nouveau_object_inc(subdev);
- 475 if (ret)
- 476 return ret;
- 477 atomic_dec(&nv_object(device)->usecount);
- 478 } else
- 479 if (subdev) {
- 480 nouveau_subdev_reset(subdev);
- 481 }
- 482 }
- 483 }
- 484
- 485 return 0;
- 486 }
第292行,首先检查参数的正确性,输出一些调试信息.
第302行,给有特权的client使用nouveau_devobj_oclass_super,这个与默认的nouveau_devobj_oclass的不同就是可以直接进行寄存器读写.
第305行,获取对应的device,如果特别指定了就从链表中查找指定的device.
第312行,创建这个devobj,其中几个参数简单说一下:
nouveau_control_oclass: 这个是作为sclass进去的,和sysfs有关. Nouveau初始化sysfs时候会创建一个nvif_object,这个时候会用到这个sclass.
(1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_FIFO) | (1ULL << NVDEV_ENGINE_DISP) | (1ULL << NVDEV_ENGINE_PERFMON):
这个是作为engcls传送进去的,表示可以用来完成u32 oclass转换的subdev.
第223行,获取NVIDIA的MMIO地址和长度.
第327行,获取禁用的subdev.
-
- 206 static const u64 disable_map[] = {
- 207 [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_V0_DISABLE_VBIOS,
- 208 [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_V0_DISABLE_CORE,
- 209 [NVDEV_SUBDEV_GPIO] = NV_DEVICE_V0_DISABLE_CORE,
- 210 [NVDEV_SUBDEV_I2C] = NV_DEVICE_V0_DISABLE_CORE,
- 211 [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_V0_DISABLE_CORE,
- 212 [NVDEV_SUBDEV_MXM] = NV_DEVICE_V0_DISABLE_CORE,
- 213 [NVDEV_SUBDEV_MC] = NV_DEVICE_V0_DISABLE_CORE,
- 214 [NVDEV_SUBDEV_BUS] = NV_DEVICE_V0_DISABLE_CORE,
- 215 [NVDEV_SUBDEV_TIMER] = NV_DEVICE_V0_DISABLE_CORE,
- 216 [NVDEV_SUBDEV_FB] = NV_DEVICE_V0_DISABLE_CORE,
- 217 [NVDEV_SUBDEV_LTC] = NV_DEVICE_V0_DISABLE_CORE,
- 218 [NVDEV_SUBDEV_IBUS] = NV_DEVICE_V0_DISABLE_CORE,
- 219 [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_V0_DISABLE_CORE,
- 220 [NVDEV_SUBDEV_VM] = NV_DEVICE_V0_DISABLE_CORE,
- 221 [NVDEV_SUBDEV_BAR] = NV_DEVICE_V0_DISABLE_CORE,
- 222 [NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE,
- 223 [NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE,
- 224 [NVDEV_SUBDEV_PWR] = NV_DEVICE_V0_DISABLE_CORE,
- 225 [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE,
- 226 [NVDEV_ENGINE_PERFMON] = NV_DEVICE_V0_DISABLE_CORE,
- 227 [NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO,
- 228 [NVDEV_ENGINE_SW] = NV_DEVICE_V0_DISABLE_FIFO,
- 229 [NVDEV_ENGINE_GR] = NV_DEVICE_V0_DISABLE_GRAPH,
- 230 [NVDEV_ENGINE_MPEG] = NV_DEVICE_V0_DISABLE_MPEG,
- 231 [NVDEV_ENGINE_ME] = NV_DEVICE_V0_DISABLE_ME,
- 232 [NVDEV_ENGINE_VP] = NV_DEVICE_V0_DISABLE_VP,
- 233 [NVDEV_ENGINE_CRYPT] = NV_DEVICE_V0_DISABLE_CRYPT,
- 234 [NVDEV_ENGINE_BSP] = NV_DEVICE_V0_DISABLE_BSP,
- 235 [NVDEV_ENGINE_PPP] = NV_DEVICE_V0_DISABLE_PPP,
- 236 [NVDEV_ENGINE_COPY0] = NV_DEVICE_V0_DISABLE_COPY0,
- 237 [NVDEV_ENGINE_COPY1] = NV_DEVICE_V0_DISABLE_COPY1,
- 238 [NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC,
- 239 [NVDEV_ENGINE_VENC] = NV_DEVICE_V0_DISABLE_VENC,
- 240 [NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP,
- 241 [NVDEV_SUBDEV_NR] = 0,
- 242 };
也就是说把传进来的禁用列表转换成要禁用的具体subdev列表.
第333行,如果没有禁用识别NVIDIA设备类型,而且这个设备还没有被识别过设备类型,那么此处就要进行识别.
第335行,首先映射一下MMIO空间.
第345行,这里可以看注释. 切换MMIO空间的端模式到CPU的端模式. [大端/小端]
第348行和第349行,读取NVIDIA的寄存器. 要是NVIDIA能开放一点的话,或许我们现在可以把spec拿出来看看.
但我们通过读代码还是能知道这两个寄存器的格式以及储存的信息. boot0储存显卡的种类,strap储存晶振频率. [石英晶体谐振器]
第350行,把MMIO空间取消映射.
第353到387行,从boot0中获取显卡的Chipset和Family,没什么好说的.
接下来,第389行到403行,调用对应显卡Family的identity函数,因为我的显卡是NVD9,对应的family是NVC0,所以以后就拿这个来分析具体与设备相关的东西了.
-
- 56 int
- 57 nvc0_identify(struct nouveau_device *device)
- 58 {
- 59 switch (device->chipset) {
-
- 282 case 0xd9:
- 283 device->cname = "GF119";
- 284 device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- 285 device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass;
- 286 device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
- 287 device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- 288 device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- 289 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- 290 device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- 291 device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- 292 device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- 293 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- 294 device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- 295 device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- 296 device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- 297 device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- 298 device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- 299 device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- 300 device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass;
- 301 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- 302 device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- 303 device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- 304 device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- 305 device->oclass[NVDEV_ENGINE_GR ] = nvd9_graph_oclass;
- 306 device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- 307 device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- 308 device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- 309 device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- 310 device->oclass[NVDEV_ENGINE_DISP ] = nvd0_disp_oclass;
- 311 device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- 312 break;
-
- 342 default:
- 343 nv_fatal(device, "unknown Fermi chipset\n");
- 344 return -EINVAL;
- 345 }
- 346
- 347 return 0;
- 348 }
- 349
对于每一个chipset都有这么一堆赋值函数,所以不再都列出来,只关心NVD9这个例子.
很明显这个函数的作用是初始化device->oclass,等会就会对每一个oclass使用nouveau_object_ctor创建一个object,并储存到devobj->subdev和device->subdev里.
回到nouveau_devobj_ctor,下面先检查ret,然后打印调试信息.
第416行,根据设备类型适当mask刚刚读取的strap.
第422行,根据strap的值,确定石英晶体谐振器的频率,并储存到device的一个字段里.
紧接着退出识别设备类型的if语句,下面第434行,初始化device的mmio空间.
然后第442行,初始化每一个subdev. 这个for循环本身并不大,但它会执行刚刚在identity函数里初始化的所有oclass的ctor和init函数,所以.......
第443行,首先检查这个subdev是否已经被禁用了,或者根本没有对应的oclass,如果这样的话直接进行下一次循环.
第446行,检查这个subdev是否已经被创建过,如果这样的话直接把它ref一遍就行了.
第452行,使用nouveau_object_ctor创建这个subdev,也就是调用这个oclass的ctor函数指针.
第460行,本来这个地方是要使用nouveau_object_inc来调用oclass里的init函数指针的,但是为什么要这样写呢?
首先,这里有一个名叫DEVINIT的subdev,这个subdev的init函数将会使用两个[在NVDEV_SUBDEV_DEVINIT和NVDEV_SUBDEV_DEVINIT_LAST之间的]必须被创建,但又不能被提前init的subdev.
如果此处直接执行这个subdev的init函数,那么就不可能出现一个已经被创建但没有被init的subdev了.
所以这个while循环,保证先创建但不init所有NVDEV_SUBDEV_DEVINIT_LAST之前的subdev,等到已经过了这个NVDEV_SUBDEV_DEVINIT_LAST后,再init所有之前创建过的subdev. 当然对于之后的subdev,则都是创建了立即init的.
[建议参考此处的注释,/drivers/gpu/drm/nouveau/core/include/core/device.h里的注释,以及具体代码来理解.]
由于这些ctor/init函数加起来实在太长,可能要连续说几篇才能说完,所以暂且先来看上一篇中我们忽略的另一个函数吧. 调用的位置:
-
- 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 }
第43行,使用mthd获取设备的基本信息,并储存到device->info里.
-
- 115 int
- 116 nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
- 117 {
- 118 struct {
- 119 struct nvif_ioctl_v0 ioctl;
- 120 struct nvif_ioctl_mthd_v0 mthd;
- 121 } *args;
- 122 u8 stack[128];
- 123 int ret;
- 124
- 125 if (sizeof(*args) + size > sizeof(stack)) {
- 126 if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
- 127 return -ENOMEM;
- 128 } else {
- 129 args = (void *)stack;
- 130 }
- 131 args->ioctl.version = 0;
- 132 args->ioctl.type = NVIF_IOCTL_V0_MTHD;
- 133 args->mthd.version = 0;
- 134 args->mthd.method = mthd;
- 135
- 136 memcpy(args->mthd.data, data, size);
- 137 ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
- 138 memcpy(data, args->mthd.data, size);
- 139 if (args != (void *)stack)
- 140 kfree(args);
- 141 return ret;
- 142 }
首先检查需要的空间,如果在一定范围之内就使用栈里的,不然kmalloc分配内存.
第131行到第134行,初始化几个字段,主要描述了请求的版本信息和请求的类型种类.
第136行和第138行是对称的,前者把data复制进args->mthd.data,后者则把args->mthd.data复制到data里去.
中间夹着的137行就是核心代码了,这个nvif_object_ioctl我们以前分析过,这里直接看:
-
- 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 };
只看函数名就能得出结论,我们最终会调用nvkm_ioctl_mthd:
-
- 203 static int
- 204 nvkm_ioctl_mthd(struct nouveau_handle *handle, void *data, u32 size)
- 205 {
- 206 struct nouveau_object *object = handle->object;
- 207 struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
- 208 union {
- 209 struct nvif_ioctl_mthd_v0 v0;
- 210 } *args = data;
- 211 int ret;
- 212
- 213 nv_ioctl(object, "mthd size %d\n", size);
- 214 if (nvif_unpack(args->v0, 0, 0, true)) {
- 215 nv_ioctl(object, "mthd vers %d mthd %02x\n",
- 216 args->v0.version, args->v0.method);
- 217 if (ret = -ENODEV, ofuncs->mthd)
- 218 ret = ofuncs->mthd(object, args->v0.method, data, size);
- 219 }
- 220
- 221 return ret;
- 222 }
第213行是打印调试信息的,无视之.
第214行,检查参数的正确性.
第218行,调用nvif_object对应的nouveau_object的ofuncs里的mthd.
这里毫无疑问,nvif_device对应的就是刚才我们看的devobj,直接去看它的mthd函数:
-
- 148 static int
- 149 nouveau_devobj_mthd(struct nouveau_object *object, u32 mthd,
- 150 void *data, u32 size)
- 151 {
- 152 switch (mthd) {
- 153 case NV_DEVICE_V0_INFO:
- 154 return nouveau_devobj_info(object, data, size);
- 155 default:
- 156 break;
- 157 }
- 158 return -EINVAL;
- 159 }
一个switch语句判断类型,任务交给nouveau_devobj_info来完成.
-
- 79 static int
- 80 nouveau_devobj_info(struct nouveau_object *object, void *data, u32 size)
- 81 {
- 82 struct nouveau_device *device = nv_device(object);
- 83 struct nouveau_fb *pfb = nouveau_fb(device);
- 84 struct nouveau_instmem *imem = nouveau_instmem(device);
- 85 union {
- 86 struct nv_device_info_v0 v0;
- 87 } *args = data;
- 88 int ret;
- 89
- 90 nv_ioctl(object, "device info size %d\n", size);
- 91 if (nvif_unpack(args->v0, 0, 0, false)) {
- 92 nv_ioctl(object, "device info vers %d\n", args->v0.version);
- 93 } else
- 94 return ret;
- 95
- 96 switch (device->chipset) {
- 97 case 0x01a:
- 98 case 0x01f:
- 99 case 0x04c:
- 100 case 0x04e:
- 101 case 0x063:
- 102 case 0x067:
- 103 case 0x068:
- 104 case 0x0aa:
- 105 case 0x0ac:
- 106 case 0x0af:
- 107 args->v0.platform = NV_DEVICE_INFO_V0_IGP;
- 108 break;
- 109 default:
- 110 if (device->pdev) {
- 111 if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP))
- 112 args->v0.platform = NV_DEVICE_INFO_V0_AGP;
- 113 else
- 114 if (pci_is_pcie(device->pdev))
- 115 args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
- 116 else
- 117 args->v0.platform = NV_DEVICE_INFO_V0_PCI;
- 118 } else {
- 119 args->v0.platform = NV_DEVICE_INFO_V0_SOC;
- 120 }
- 121 break;
- 122 }
- 123
- 124 switch (device->card_type) {
- 125 case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
- 126 case NV_10:
- 127 case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
- 128 case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
- 129 case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
- 130 case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
- 131 case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
- 132 case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
- 133 case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
- 134 case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
- 135 default:
- 136 args->v0.family = 0;
- 137 break;
- 138 }
- 139
- 140 args->v0.chipset = device->chipset;
- 141 args->v0.revision = device->chipset >= 0x10 ? nv_rd32(device, 0) : 0x00;
- 142 if (pfb) args->v0.ram_size = args->v0.ram_user = pfb->ram->size;
- 143 else args->v0.ram_size = args->v0.ram_user = 0;
- 144 if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved;
- 145 return 0;
- 146 }
第91行,照例校验参数,打印调试信息.
第96行的一个大switch语句,其实就是获得设备的platform.
第124行,把设备的family转化为更加文字化的构架名.
第140行,貌似是顺便把设备的chipset和boot0寄存器的值放到info里?
之后的那三行是获取显卡内存大小的,因为那些subdev/engine的初始化还没展开,所以可能不理解. 以后会说到的.
下面先来简单介绍一下各个subdev/engine的作用功能把[按初始化的顺序来]:
NV_ENGINE_DEVICE: 这个早就创建和初始化了....
NV_SUBDEV_VBIOS: 识别并分析NVIDIA的BIOS,这里面储存这很多东西,比如NVIDA设备初始化表格,显示器的链接状态,HDMI信息等.
NV_SUBDEV_DEVINIT: 执行BIOS中的NVIDIA设备初始化表格,当然有时候BIOS已经执行好了,那么啥事没干.
NV_SUBDEV_GPIO: 一种总线,比较底层的一个SUBDEV,其他SUBDEV/ENGINE依赖.
NV_SUBDEV_I2C: 另一种总线,作用同上.
NV_SUBDEV_MXM: 根据MXMS信息来修正VBIOS中的数据,MXMS信息是从I2C中得到的.
NV_SUBDEV_MC: 管理NVIDIA设备中断分发给各个SUBDEV.
NV_SUBDEV_BUS: 接受处理BUS的中断,还包括hwsq接口,其他SUBDEV/ENGINE会用到.
NV_SUBDEV_TIMER: 定时器,到时间会发出中断.
NV_SUBDEV_FB: 这可不是FrameBuffer的缩写,只是一个得到显卡内存信息、管理显卡内存的东西.
NV_SUBDEV_LTC: 有一个zbc color的功能,还没仔细看,意义不明;另一个是压缩显卡内存的功能. [不是增大容量,是节省带宽.]
NV_SUBDEV_IBUS: 只有一个中断处理函数.
NV_SUBDEV_INSTMEN: 也是有关显卡物理内存管理的东西. 比NV_SUBDEV_PFB高一层,有了访问的接口.
NV_SUBDEV_VM: 显卡虚拟内存管理. 虚拟内存有三块,两块是PCI里的两个BAR,还有一块是nouveau_channel,但最终都是在这里管理的.
NV_SUBDEV_BAR: 如上所述,PCI里的两个BAR的虚拟内存映射.
NV_SUBDEV_PWR: 应该是一个处理器.
NV_SUBDEV_VOLT: 电压读取和设置.
NV_SUBDEV_THERM: 读取显卡温度,读取和设置显卡风扇转速.
NV_SUBDEV_CLOCK: 显卡时钟频率的读取、设置.
NV_ENGINE_DMAOBJ:显然是和DMA有关的,比如系统内存中的数据交给显卡处理.
NV_ENGINE_IFB: 没有具体的oclass,只是在中断中充当了一个case语句.
NV_ENGINE_FIFO: 这个是nouveau_channl用的.
NV_ENGINE_SW: 其中一个功能是当更换framebuffer完成时,硬件通知软件.
NV_ENGINE_GR: 图形处理相关.
NV_ENGINE_MPEG: NV50之前有效,不分析.
NV_ENGINE_ME: 意义不明,貌似和NV_ENGINE_IFB差不多.
NV_ENGINE_VP: 应该也是一个处理器.
NV_ENGINE_CRYPT: 只在NV50有效.
NV_ENGINE_BSP: 貌似还是一个处理器.
NV_ENGINE_PPP: video post-processing engine,意义不明.
NV_ENGINE_COPY0/COPY1/COPY2: 大概还是处理器把.
NV_ENGINE_VIC: 应该和NV_ENGINE_IFB差不多,意义不明.
NV_ENGINE_VENC: 同上.
NV_ENGINE_DISP: 有关显示模式设定,以及切换framebuffer,vblank之类的东西.
NV_ENGINE_PERFMON: 对于NVC0,是一个目前还没有做好的东西. 里面几个空数组.
等具体说的时候争取尽量附上envytools的链接,里面有一些对ENGINE/SUBDEV简介很不错.
这么多东西又不知道得写到猴年马月了......
0 0