Nouveau源码分析(三):NVIDIA设备初始化之nouveau_drm_probe

本文深入解析Nouveau驱动中的nouveau_drm_probe函数,详述NVIDIA设备初始化过程。从PCI模块扫描、设备匹配到nouveau_drm_probe的调用,探讨NV设备结构体创建、engine和object结构的初始化,以及Bus-Mastering的启用和DRM设备注册等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Nouveau源码分析(三)

向DRM注册了Nouveau驱动之后,内核中的PCI模块就会扫描所有没有对应驱动的设备,然后和nouveau_drm_pci_table对照.

对于匹配的设备,PCI模块就调用对应的probe函数,也就是nouveau_drm_probe.

// /drivers/gpu/drm/nouveau/nouveau_drm.c
281 static int nouveau_drm_probe(struct pci_dev *pdev,
282                              const struct pci_device_id *pent)
283 {
284         struct nouveau_device *device;
285         struct apertures_struct *aper;
286         bool boot = false;
287         int ret;
288 
289         /* remove conflicting drivers (vesafb, efifb etc) */
290         aper = alloc_apertures(3);
291         if (!aper)
292                 return -ENOMEM;
293 
294         aper->ranges[0].base = pci_resource_start(pdev, 1);
295         aper->ranges[0].size = pci_resource_len(pdev, 1);
296         aper->count = 1;
297 
298         if (pci_resource_len(pdev, 2)) {
299                 aper->ranges[aper->count].base = pci_resource_start(pdev, 2);
300                 aper->ranges[aper->count].size = pci_resource_len(pdev, 2);
301                 aper->count++;
302         }
303 
304         if (pci_resource_len(pdev, 3)) {
305                 aper->ranges[aper->count].base = pci_resource_start(pdev, 3);
306                 aper->ranges[aper->count].size = pci_resource_len(pdev, 3);
307                 aper->count++;
308         }
309 
310 #ifdef CONFIG_X86
311         boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
312 #endif
313         if (nouveau_modeset != 2)
314                 remove_conflicting_framebuffers(aper, "nouveaufb", boot);
315         kfree(aper);
316 
317         ret = nouveau_device_create(pdev, NOUVEAU_BUS_PCI,
318                                     nouveau_pci_name(pdev), pci_name(pdev),
319                                     nouveau_config, nouveau_debug, &device);
320         if (ret)
321                 return ret;
322 
323         pci_set_master(pdev);
324 
325         ret = drm_get_pci_dev(pdev, pent, &driver);
326         if (ret) {
327                 nouveau_object_ref(NULL, (struct nouveau_object **)&device);
328                 return ret;
329         }
330 
331         return 0;
332 }

第290~315行,分配了一个aper,把资源位置写进去,调用了remove_conflicting_framebuffer,接着释放这个aper.

一行注释和函数名已经说的很明白,就是移除冲突的framebuffer.


第317行,创建一个NV设备的结构体,这个函数我们要仔细看

// /drivers/gpu/drm/nouveau/core/include/engine/device.h
 13 #define nouveau_device_create(p,t,n,s,c,d,u)                                   \
 14         nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d),           \
 15                                sizeof(**u), (void **)u)
 16 
 17 int  nouveau_device_create_(void *, enum nv_bus_type type, u64 name,
 18                             const char *sname, const char *cfg, const char *dbg,
 19                             int, void **);
想起了什么? 对,就是上一节讲的内容,我们还是先来看结构体.

// /drivers/gpu/drm/nouveau/core/include/core/device.h
 65 struct nouveau_device {
 66         struct nouveau_engine base;
 67         struct list_head head;
 68 
 69         struct pci_dev *pdev;
 70         struct platform_device *platformdev;
 71         u64 handle;
 72 
 73         struct nvkm_event event;
 74 
 75         const char *cfgopt;
 76         const char *dbgopt;
 77         const char *name;
 78         const char *cname;
 79         u64 disable_mask;
 80 
 81         enum {
 82                 NV_04    = 0x04,
 83                 NV_10    = 0x10,
 84                 NV_11    = 0x11,
 85        
<think>好的,我现在需要帮助用户解决NVIDIA设备PCI I/O区域无效导致的内核探针失败的问题,错误代码是-1。首先,我需要理解这个问题的背景和可能的原因。根据用户提供的引用内容,特别是引用[2]提到的PCI总线枚举过程,当系统尝试访问PCI设备的配置空间时,如果设备没有响应,会返回全1的值,导致系统认为设备不存在。这可能与当前的问题相关。 接下来,我需要分析错误的具体原因。用户提到的“PCI I/O区域无效”可能意味着驱动程序在尝试访问设备的PCI I/O区域时遇到了问题。可能的原因包括硬件连接问题、PCI配置空间损坏、内核模块冲突或驱动兼容性问题。此外,NVIDIA驱动本身的安装问题或内核版本不兼容也可能导致此错误。 然后,我需要根据这些可能的原因,逐步给出解决方案。首先检查硬件连接是否稳固,确保PCIe插槽和显卡接触良好。接着,使用lspci命令查看设备是否被正确识别,确认系统能够检测到NVIDIA显卡。如果设备未被识别,可能需要检查硬件或更换插槽。 如果硬件没有问题,可能需要使用pci=nommconf内核参数来绕过PCI配置空间的某些问题,如引用[2]提到的总线枚举问题。修改GRUB配置后更新并重启系统,观察是否解决问题。 此外,用户可能需要禁用可能导致冲突的内核模块,如nouveau开源驱动。通过黑名单nouveau模块并重建initramfs,可以避免驱动冲突。同时,确保安装的NVIDIA驱动版本与当前内核版本兼容,必要时重新安装或更新驱动。 如果以上步骤无效,尝试手动重新扫描PCI总线或强制重新加载NVIDIA模块。最后,如果所有方法都失败,可能需要检查内核日志以获取更详细的错误信息,或者考虑硬件故障的可能性。 在提供解决方案时,需要确保用户能够按照步骤操作,并注意潜在的风险,如修改内核参数可能影响系统稳定性。同时,引用相关的引用内容,如引用[2]关于PCI枚举的部分,来增强解答的可信度。</think>针对NVIDIA设备PCI I/O区域无效导致的"probe failed error -1"问题,以下是分步解决方案: 1. **硬件状态验证** - 检查PCIe插槽供电和物理连接 - 使用命令查看设备识别状态: ```bash lspci -nn | grep -i nvidia ``` 若输出显示设备ID为`ffffffff`(如引用[2]所述的全1值),说明存在总线枚举失败 2. **内核参数调整** - 在GRUB配置中添加`pci=nommconf`参数: ```bash sudo sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/&pci=nommconf /' /etc/default/grub sudo update-grub ``` 该参数可绕过有问题的MMCONFIG PCI配置空间访问方式[^2] 3. **驱动模块处理** - 强制卸载NVIDIA驱动模块: ```bash sudo rmmod nvidia-drm nvidia-uvm nvidia ``` - 清理残留内核对象: ```bash sudo nvidia-modprobe -c 0 ``` 4. **PCI配置空间重置** - 手动触发PCI设备重枚举: ```bash echo 1 | sudo tee /sys/bus/pci/devices/0000:XX:XX.X/remove echo 1 | sudo tee /sys/bus/pci/rescan ``` (需替换XX:XX.X为实际PCI地址) 5. **IOMMU状态检查** - 验证IOMMU是否错误启用: ```bash dmesg | grep -i iommu ``` 若存在问题可临时禁用: ```bash sudo sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/&iommu=soft /' /etc/default/grub ``` 6. **固件更新** - 升级主板BIOS/UEFI至最新版本 - 更新PCIe固件: ```bash sudo update-pciids ``` 7. **驱动兼容性验证** - 检查内核头文件与驱动版本匹配: ```bash uname -r apt show nvidia-driver-XXX | grep Source ``` 确保两者内核版本一致 8. **深度诊断** - 捕获PCI配置空间原始数据: ```bash sudo lspci -vvv -s XX:XX.X > pci_dump.log ``` 分析BAR寄存器值是否有效 **注意**:操作前建议创建系统快照,部分操作可能导致临时显示异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值