标签:驱动 源码分析 nvidia nouveau linux
// /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 }
// /drivers/gpu/drm/nouveau/nouveau_drm.c 102 static int 103 nouveau_cli_create(u64 name, const char *sname, 104 int size, void **pcli) 105 { 106 struct nouveau_cli *cli = *pcli = kzalloc(size, GFP_KERNEL); 107 if (cli) { 108 int ret = nvif_client_init(NULL, NULL, sname, name, 109 nouveau_config, nouveau_debug, 110 &cli->base); 111 if (ret == 0) { 112 mutex_init(&cli->mutex); 113 usif_client_init(cli); 114 } 115 return ret; 116 } 117 return -ENOMEM; 118 }第106行,kzalloc分配内存.
// /drivers/gpu/drm/nouveau/nouveau_usif.c 379 void 380 usif_client_init(struct nouveau_cli *cli) 381 { 382 INIT_LIST_HEAD(&cli->objects); 383 INIT_LIST_HEAD(&cli->notifys); 384 }
// /drivers/gpu/drm/nouveau/nvif/client.c 69 int 70 nvif_client_init(void (*dtor)(struct nvif_client *), const char *driver, 71 const char *name, u64 device, const char *cfg, const char *dbg, 72 struct nvif_client *client) 73 { 74 int ret, i; 75 76 ret = nvif_object_init(NULL, (void*)dtor, 0, 0, NULL, 0, &client->base); 77 if (ret) 78 return ret; 79 80 client->base.parent = &client->base; 81 client->base.handle = ~0; 82 client->object = &client->base; 83 client->super = true; 84 85 for (i = 0, ret = -EINVAL; (client->driver = nvif_drivers[i]); i++) { 86 if (!driver || !strcmp(client->driver->name, driver)) { 87 ret = client->driver->init(name, device, cfg, dbg, 88 &client->base.priv); 89 if (!ret || driver) 90 break; 91 } 92 } 93 94 if (ret) 95 nvif_client_fini(client); 96 return ret; 97 }第76行,首先初始化nvif_object:
// /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 }首先各种填充字段:
// /drivers/gpu/drm/nouveau/nvif/object.h 37 #define nvif_object(a) (a)->object
// /drivers/gpu/drm/nouveau/nvif/client.c 58 const struct nvif_driver * 59 nvif_drivers[] = { 60 #ifdef __KERNEL__ 61 &nvif_driver_nvkm, 62 #else 63 &nvif_driver_drm, 64 &nvif_driver_lib, 65 #endif 66 NULL 67 };很明显这是内核里的代码,因此只存在一个nvif_driver,那就是nvif_driver_nvkm.
// /drivers/gpu/drm/nouveau/nouveau_nvif.c 125 const struct nvif_driver 126 nvif_driver_nvkm = { 127 .name = "nvkm", 128 .init = nvkm_client_init, 129 .fini = nvkm_client_fini, 130 .suspend = nvkm_client_suspend, 131 .resume = nvkm_client_resume, 132 .ioctl = nvkm_client_ioctl, 133 .map = nvkm_client_map, 134 .unmap = nvkm_client_unmap, 135 .keep = false, 136 };
// /drivers/gpu/drm/nouveau/nouveau_nvif.c 109 static int 110 nvkm_client_init(const char *name, u64 device, const char *cfg, 111 const char *dbg, void **ppriv) 112 { 113 struct nouveau_client *client; 114 int ret; 115 116 ret = nouveau_client_create(name, device, cfg, dbg, &client); 117 *ppriv = client; 118 if (ret) 119 return ret; 120 121 client->ntfy = nvkm_client_ntfy; 122 return 0; 123 }首先创建一个nouveau_client,这个其实就是一个nouveau_object,也就是说在这里创建了这个nvif_object对应的nouveau_object .
// /drivers/gpu/drm/nouveau/core/include/core/client.h 39 #define nouveau_client_create(n,c,oc,od,d) 40 nouveau_client_create_((n), (c), (oc), (od), sizeof(**d), (void **)d) 41 42 int nouveau_client_create_(const char *name, u64 device, const char *cfg, 43 const char *dbg, int, void **);又一次见到了这个东西,直接去看nouveau_client_create_
// /drivers/gpu/drm/nouveau/core/core/client.c 203 int 204 nouveau_client_create_(const char *name, u64 devname, const char *cfg, 205 const char *dbg, int length, void **pobject) 206 { 207 struct nouveau_object *device; 208 struct nouveau_client *client; 209 int ret; 210 211 device = (void *)nouveau_device_find(devname); 212 if (!device) 213 return -ENODEV; 214 215 ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass, 216 NV_CLIENT_CLASS, NULL, 217 (1ULL << NVDEV_ENGINE_DEVICE), 218 length, pobject); 219 client = *pobject; 220 if (ret) 221 return ret; 222 223 ret = nouveau_handle_create(nv_object(client), ~0, ~0, 224 nv_object(client), &client->root); 225 if (ret) 226 return ret; 227 228 /* prevent init/fini being called, os in in charge of this */ 229 atomic_set(&nv_object(client)->usecount, 2); 230 231 nouveau_object_ref(device, &client->device); 232 snprintf(client->name, sizeof(client->name), "%s", name); 233 client->debug = nouveau_dbgopt(dbg, "CLIENT"); 234 return 0; 235 }第211行,首先寻找对应的nouveau_device.
// /drivers/gpu/drm/nouveau/core/core/namedb.c 166 int 167 nouveau_namedb_create_(struct nouveau_object *parent, 168 struct nouveau_object *engine, 169 struct nouveau_oclass *oclass, u32 pclass, 170 struct nouveau_oclass *sclass, u64 engcls, 171 int length, void **pobject) 172 { 173 struct nouveau_namedb *namedb; 174 int ret; 175 176 ret = nouveau_parent_create_(parent, engine, oclass, pclass | 177 NV_NAMEDB_CLASS, sclass, engcls, 178 length, pobject); 179 namedb = *pobject; 180 if (ret) 181 return ret; 182 183 rwlock_init(&namedb->lock); 184 INIT_LIST_HEAD(&namedb->list); 185 return 0; 186 }先创建一个nouveau_parent,这个结构体和nouveau_engine都能把u32 oclass转换成对应的nouveau_oclass *oclass .
// /drivers/gpu/drm/nouveau/core/core/parent.c 110 int 111 nouveau_parent_create_(struct nouveau_object *parent, 112 struct nouveau_object *engine, 113 struct nouveau_oclass *oclass, u32 pclass, 114 struct nouveau_oclass *sclass, u64 engcls, 115 int size, void **pobject) 116 { 117 struct nouveau_parent *object; 118 struct nouveau_sclass *nclass; 119 int ret; 120 121 ret = nouveau_object_create_(parent, engine, oclass, pclass | 122 NV_PARENT_CLASS, size, pobject); 123 object = *pobject; 124 if (ret) 125 return ret; 126 127 while (sclass && sclass->ofuncs) { 128 nclass = kzalloc(sizeof(*nclass), GFP_KERNEL); 129 if (!nclass) 130 return -ENOMEM; 131 132 nclass->sclass = object->sclass; 133 object->sclass = nclass; 134 nclass->engine = engine ? nv_engine(engine) : NULL; 135 nclass->oclass = sclass; 136 sclass++; 137 } 138 139 object->engine = engcls; 140 return 0; 141 }首先创建一个nouveau_object对象.
// /drivers/gpu/drm/nouveau/core/core/handle.c 99 int 100 nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle, 101 struct nouveau_object *object, 102 struct nouveau_handle **phandle) 103 { 104 struct nouveau_object *namedb; 105 struct nouveau_handle *handle; 106 int ret; 107 108 namedb = parent; 109 while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) 110 namedb = namedb->parent; 111 112 handle = kzalloc(sizeof(*handle), GFP_KERNEL); 113 if (!handle) 114 return -ENOMEM; 115 116 INIT_LIST_HEAD(&handle->head); 117 INIT_LIST_HEAD(&handle->tree); 118 handle->name = _handle; 119 handle->priv = ~0; 120 121 ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle); 122 if (ret) { 123 kfree(handle); 124 return ret; 125 } 126 127 if (nv_parent(parent)->object_attach) { 128 ret = nv_parent(parent)->object_attach(parent, object, _handle); 129 if (ret < 0) { 130 nouveau_handle_destroy(handle); 131 return ret; 132 } 133 134 handle->priv = ret; 135 } 136 137 if (object != namedb) { 138 while (!nv_iclass(namedb, NV_CLIENT_CLASS)) 139 namedb = namedb->parent; 140 141 handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent); 142 if (handle->parent) { 143 list_add(&handle->head, &handle->parent->tree); 144 nouveau_namedb_put(handle->parent); 145 } 146 } 147 148 hprintk(handle, TRACE, "created\n"); 149 *phandle = handle; 150 return 0; 151 }首先把parent向上查找,直到找到一个nouveau_namedb,对于这个例子,parent本来就是一个nouveau_namedb,所以parent == namedb.
// /drivers/gpu/drm/nouveau/core/core/namedb.c 87 int 88 nouveau_namedb_insert(struct nouveau_namedb *namedb, u32 name, 89 struct nouveau_object *object, 90 struct nouveau_handle *handle) 91 { 92 int ret = -EEXIST; 93 write_lock_irq(&namedb->lock); 94 if (!nouveau_namedb_lookup(namedb, name)) { 95 nouveau_object_ref(object, &handle->object); 96 handle->namedb = namedb; 97 list_add(&handle->node, &namedb->list); 98 ret = 0; 99 } 100 write_unlock_irq(&namedb->lock); 101 return ret; 102 }这个insert函数首先查找是否有重复的,有就返回-EEXIST,然后用链表连起来,返回.
// /drivers/gpu/drm/nouveau/core/core/namedb.c 115 struct nouveau_handle * 116 nouveau_namedb_get(struct nouveau_namedb *namedb, u32 name) 117 { 118 struct nouveau_handle *handle; 119 read_lock(&namedb->lock); 120 handle = nouveau_namedb_lookup(namedb, name); 121 if (handle == NULL) 122 read_unlock(&namedb->lock); 123 return handle; 124 }
// /drivers/gpu/drm/nouveau/core/core/namedb.c 159 void 160 nouveau_namedb_put(struct nouveau_handle *handle) 161 { 162 if (handle) 163 read_unlock(&handle->namedb->lock); 164 }
// /drivers/gpu/drm/nouveau/core/core/namedb.c 30 static struct nouveau_handle * 31 nouveau_namedb_lookup(struct nouveau_namedb *namedb, u32 name) 32 { 33 struct nouveau_handle *handle; 34 35 list_for_each_entry(handle, &namedb->list, node) { 36 if (handle->name == name) 37 return handle; 38 } 39 40 return NULL; 41 }代码都很容易理解,自己尝试阅读一下,不多说了. 回到刚才那个函数:
// /drivers/gpu/drm/nouveau/nouveau_drm.c 336 static void 337 nouveau_get_hdmi_dev(struct nouveau_drm *drm) 338 { 339 struct pci_dev *pdev = drm->dev->pdev; 340 341 if (!pdev) { 342 DRM_INFO("not a PCI device; no HDMI\n"); 343 drm->hdmi_device = NULL; 344 return; 345 } 346 347 /* subfunction one is a hdmi audio device? */ 348 drm->hdmi_device = pci_get_bus_and_slot((unsigned int)pdev->bus->number, 349 PCI_DEVFN(PCI_SLOT(pdev->devfn), 1)); 350 351 if (!drm->hdmi_device) { 352 NV_DEBUG(drm, "hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1); 353 return; 354 } 355 356 if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) { 357 NV_DEBUG(drm, "possible hdmi device not audio %d\n", drm->hdmi_device->class); 358 pci_dev_put(drm->hdmi_device); 359 drm->hdmi_device = NULL; 360 return; 361 } 362 }第341行,检查是否是PCI设备.
Nouveau源码分析(四):NVIDIA设备初始化之nouveau_drm_load (1)
标签:驱动 源码分析 nvidia nouveau linux
原文地址:http://blog.csdn.net/goodqt/article/details/40979051