天天看点

Nouveau源码分析(一):从module_init开始Nouveau源码分析(一)

Nouveau源码分析(一)

// /drivers/gpu/drm/nouveau/nouveau_drm.c
1089 module_init(nouveau_drm_init);
1090 module_exit(nouveau_drm_exit);
           

相信只要看过linux源码的都会知道这意味着什么,Nouveau被加载后第一个执行的函数和Nouveau被卸载前最后一个执行的函数.

显然,我们需要查看nouveau_drm_init

// /drivers/gpu/drm/nouveau/nouveau_drm.c
1062 static int __init
1063 nouveau_drm_init(void)
1064 {
1065         if (nouveau_modeset == -1) {
1066 #ifdef CONFIG_VGA_CONSOLE
1067                 if (vgacon_text_force())
1068                         nouveau_modeset = 0;
1069 #endif
1070         }
1071 
1072         if (!nouveau_modeset)
1073                 return 0;
1074 
1075         nouveau_register_dsm_handler();
1076         return drm_pci_init(&driver, &nouveau_drm_pci_driver);
1077 }
           

1065行,nouveau_modset,这是什么东西? 虽然我们完全可以跳过这段代码不看,但还是多了解一下吧.

// /drivers/gpu/drm/nouveau/nouveau_drm.c
 67 MODULE_PARM_DESC(modeset, "enable driver (default: auto, "
 68                           "0 = disabled, 1 = enabled, 2 = headless)");
 69 int nouveau_modeset = -1;
 70 module_param_named(modeset, nouveau_modeset, int, 0400);
           

嗯,一个指示Nouveau禁用或启用的变量,如果被设置成0[disabled]就会直接在1073行返回

1075行,nouveau_register_dsm_handler()

这个函数貌似是关于电源管理以及双显卡切换的,暂且忽略,以后再来看

1076行,最关键的一行代码出现了,通过drm_pci_init接口注册Nouveau驱动,所有的东西全都是由传入的两个结构体中的函数指针引发的

先看nouveau_drm_pci_driver吧:

// /drivers/gpu/drm/nouveau/nouveau_drm.c
1017 static struct pci_driver
1018 nouveau_drm_pci_driver = {
1019         .name = "nouveau",
1020         .id_table = nouveau_drm_pci_table,
1021         .probe = nouveau_drm_probe,
1022         .remove = nouveau_drm_remove,
1023         .driver.pm = &nouveau_pm_ops,
1024 };
           

这个的主要功能就是匹配pci中的Nvidia设备,先匹配id_table,符合id_table中的规则的调用probe,成功则Nouveau正式管理了这个Nvidia设备.

当然这里还有移除时调用的remove函数,和电源管理的pm部分.

// /drivers/gpu/drm/nouveau/nouveau_drm.c
893 static struct pci_device_id
894 nouveau_drm_pci_table[] = {
895         {
896                 PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
897                 .class = PCI_BASE_CLASS_DISPLAY << 16,
898                 .class_mask  = 0xff << 16,
899         },
900         {
901                 PCI_DEVICE(PCI_VENDOR_ID_NVIDIA_SGS, PCI_ANY_ID),
902                 .class = PCI_BASE_CLASS_DISPLAY << 16,
903                 .class_mask  = 0xff << 16,
904         },
905         {}
906 };
           

pci设备的匹配规则,相信大部分人都能看懂.

然后我们来看driver:

// /drivers/gpu/drm/nouveau/nouveau_drm.c
833 static struct drm_driver
834 driver = {
835         .driver_features =
836                 DRIVER_USE_AGP |
837                 DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER,
838 
839         .load = nouveau_drm_load,
840         .unload = nouveau_drm_unload,
841         .open = nouveau_drm_open,
842         .preclose = nouveau_drm_preclose,
843         .postclose = nouveau_drm_postclose,
844         .lastclose = nouveau_vga_lastclose,
845 
846 #if defined(CONFIG_DEBUG_FS)
847         .debugfs_init = nouveau_debugfs_init,
848         .debugfs_cleanup = nouveau_debugfs_takedown,
849 #endif
850 
851         .get_vblank_counter = drm_vblank_count,
852         .enable_vblank = nouveau_display_vblank_enable,
853         .disable_vblank = nouveau_display_vblank_disable,
854         .get_scanout_position = nouveau_display_scanoutpos,
855         .get_vblank_timestamp = nouveau_display_vblstamp,
856 
857         .ioctls = nouveau_ioctls,
858         .num_ioctls = ARRAY_SIZE(nouveau_ioctls),
859         .fops = &nouveau_driver_fops,
860 
861         .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
862         .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
863         .gem_prime_export = drm_gem_prime_export,
864         .gem_prime_import = drm_gem_prime_import,
865         .gem_prime_pin = nouveau_gem_prime_pin,
866         .gem_prime_res_obj = nouveau_gem_prime_res_obj,
867         .gem_prime_unpin = nouveau_gem_prime_unpin,
868         .gem_prime_get_sg_table = nouveau_gem_prime_get_sg_table,
869         .gem_prime_import_sg_table = nouveau_gem_prime_import_sg_table,
870         .gem_prime_vmap = nouveau_gem_prime_vmap,
871         .gem_prime_vunmap = nouveau_gem_prime_vunmap,
872 
873         .gem_free_object = nouveau_gem_object_del,
874         .gem_open_object = nouveau_gem_object_open,
875         .gem_close_object = nouveau_gem_object_close,
876 
877         .dumb_create = nouveau_display_dumb_create,
878         .dumb_map_offset = nouveau_display_dumb_map_offset,
879         .dumb_destroy = drm_gem_dumb_destroy,
880 
881         .name = DRIVER_NAME,
882         .desc = DRIVER_DESC,
883 #ifdef GIT_REVISION
884         .date = GIT_REVISION,
885 #else
886         .date = DRIVER_DATE,
887 #endif
888         .major = DRIVER_MAJOR,
889         .minor = DRIVER_MINOR,
890         .patchlevel = DRIVER_PATCHLEVEL,
891 };
           

看起来相当复杂,这就是Nouveau和外界的接口,注意一下初始化部分: ".load = nouveau_drm_load,"

至此nouveau_drm_init完成了它的任务------注册Nouveau驱动,下面就进入到了Nouveau针对具体Nvidia设备的初始化阶段------nouveau_drm_probe和nouveau_drm_load.

继续阅读