Nouveau源码分析(六)
上一篇中我们暂时忽略了两个函数,第一个是用于创建nvif_device对应的nouveau_object的ctor函数:
// /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