标签:linux nouveau nvidia 源码分析 驱动
// /drivers/gpu/drm/nouveau/core/engine/device/base.c 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.
// /drivers/gpu/drm/nouveau/core/engine/device/base.c 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 /* give priviledged clients register access */ 301 if (client->super) 302 oclass = &nouveau_devobj_oclass_super; 303 304 /* find the device subdev that matches what the client requested */ 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 /* translate api disable mask into internal mapping */ 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 /* identify the chipset, and determine classes of subdev/engines */ 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 /* switch mmio to cpu's native endianness */ 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 /* read boot0 and strapping information */ 348 boot0 = ioread32_native(map + 0x000000); 349 strap = ioread32_native(map + 0x101000); 350 iounmap(map); 351 352 /* determine chipset and derive architecture from it */ 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 /* determine frequency of timing crystal */ 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 /* ensure requested subsystems are available for use */ 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 /* note: can't init *any* subdevs until devinit has been run 463 * due to not knowing exactly what the vbios init tables will 464 * mess with. devinit also can't be run until all of its 465 * dependencies have been created. 466 * 467 * this code delays init of any subdev until all of devinit's 468 * dependencies have been created, and then initialises each 469 * subdev in turn as they're created. 470 */ 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行,首先检查参数的正确性,输出一些调试信息.
// /drivers/gpu/drm/nouveau/core/engine/device/base.c 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列表.
// /drivers/gpu/drm/nouveau/core/engine/device/nvc0.c 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这个例子.
// /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 }第43行,使用mthd获取设备的基本信息,并储存到device->info里.
// /drivers/gpu/drm/nouveau/nvif/object.c 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分配内存.
// /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 };只看函数名就能得出结论,我们最终会调用nvkm_ioctl_mthd:
// /drivers/gpu/drm/nouveau/core/core/ioctl.c 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行是打印调试信息的,无视之.
// /drivers/gpu/drm/nouveau/core/engine/device/base.c 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来完成.
// /drivers/gpu/drm/nouveau/core/engine/device/base.c 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行,照例校验参数,打印调试信息.
Nouveau源码分析(六):NVIDIA设备初始化之nouveau_drm_load (3)
标签:linux nouveau nvidia 源码分析 驱动
原文地址:http://blog.csdn.net/goodqt/article/details/41207163