跳过正文
  1. Notes/

NVIDIA显卡驱动安装与修复

loading · loading · ·
Linux Configuration
目录
“NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.”问题分析与解决

前言
#

今天在运行 vscode 代码时,报错 RuntimeError: No CUDA GPUs are available ,令人差异,遂进入命令行检查,发现似乎掉显卡驱动了。(注:本文出乎意料的包含但不限于重装显卡驱动,重装WIFI驱动,修改Linux内核版本等问题的解决,如果此过程仍未解决你的问题,欢迎留言讨论)

问题描述
#

1.命令行输入:

nvidia-smi

输出:

NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

2.此时检查 cuda,输入:

nvcc -V

意外的输出:

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2022 NVIDIA Corporation
Built on Wed_Sep_21_10:33:58_PDT_2022
Cuda compilation tools, release 11.8, V11.8.89
Build cuda_11.8.r11.8/compiler.31833905_0

说明驱动存在。

3.输入

ls /usr/src | grep nvidia

可以得到当前的驱动版本号:nvidia-535.183.01

解决办法
#

1.
#

根据网上的解决办法,首先尝试:

sudo apt-get install dkms
sudo dkms install -m nvidia -v 535.183.01

其中第 2 行 535.183.01 表示的是驱动版本号,应该替换为自己的驱动版本号)

可是结果却是:

Module nvidia/535.183.01 already installed on kernel 6.8.0-48-generic (x86_64).

再次输入 nvidia-smi 依然报错。

2.
#

尝试另一种办法,在 ubuntu 开机启动项中选择 advanced 模式,其中选择版本号不同的上一内核启动,依然无效。

经过询问,猜测可能是内核版本自动更新过高,导致装不上驱动(本机内核版本为 6.8.0-48-generic),于是开始搜索如何安装低版本内核。

3.
#

安装低版本内核,这里以 5.15.0-25-generic 举例。首先查看 grub 版本:

grub-install --version

结果是:grub-install (GRUB) 2.06-2ubuntu7.2

其中版本很重要,我的是 2.06 ,大于 2.00,若是小于 2.00 的在下面的步骤中有区别。

接下来查看自己现有的内核版本(在Ubuntu启动项页面,查看advance项也能看到),输入:

grep 'menuentry' /boot/grub/grub.cfg

可以得到如下结果:(7-10行就是 linux 内核)

if [ x"${feature_menuentry_id}" = xy ]; then
  menuentry_id_option="--id"
  menuentry_id_option=""
export menuentry_id_option
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-81fae8c4-e902-410a-a709-dd3d57a11e8b' {
submenu 'Advanced options for Ubuntu' $menuentry_id_option 'gnulinux-advanced-81fae8c4-e902-410a-a709-dd3d57a11e8b' {
	menuentry 'Ubuntu, with Linux 6.8.0-48-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-6.8.0-48-generic-advanced-81fae8c4-e902-410a-a709-dd3d57a11e8b' {
	menuentry 'Ubuntu, with Linux 6.8.0-48-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-6.8.0-48-generic-recovery-81fae8c4-e902-410a-a709-dd3d57a11e8b' {
	menuentry 'Ubuntu, with Linux 6.8.0-47-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-6.8.0-47-generic-advanced-81fae8c4-e902-410a-a709-dd3d57a11e8b' {
	menuentry 'Ubuntu, with Linux 6.8.0-47-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-6.8.0-47-generic-recovery-81fae8c4-e902-410a-a709-dd3d57a11e8b' {
menuentry 'Windows Boot Manager (on /dev/nvme0n1p1)' --class windows --class os $menuentry_id_option 'osprober-efi-BE9A-11EB' {
menuentry 'UEFI Firmware Settings' $menuentry_id_option 'uefi-firmware' {

接下来安装想要的旧版本,输入:

sudo apt install linux-image-5.15.0-25-generic

之后修改 /etc/default/grub 文件,输入:

sudo gedit /etc/default/grub

GRUB_DEFAULT=0 的 0 替换为一段文本:这里与前面的 grub 版本有关:

  • 如果是小于2的版本,先复制上面第6行的 submenu 后面的句子 Advanced options for Ubuntu,接下来输入一个 >,接下来复制上面第7行 menuentry 后面的句子,并把版本改为上面新下载的版本 Ubuntu, with Linux 5.15.0-25-generic。最终结果为 GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 5.15.0-25-generic"
  • 如果是大于2的版本,先复制上面第6行的 $menuentry_id_option 后面的句子 gnulinux-advanced-81fae8c4-e902-410a-a709-dd3d57a11e8b,接下来输入一个 >,接下来复制上面第7行 $menuentry_id_option 后面的句子,并把版本改为上面新下载的版本 gnulinux-5.15.0-25-generic-advanced-81fae8c4-e902-410a-a709-dd3d57a11e8b 。最终结果为 GRUB_DEFAULT="gnulinux-advanced-81fae8c4-e902-410a-a709-dd3d57a11e8b>gnulinux-5.15.0-25-generic-advanced-81fae8c4-e902-410a-a709-dd3d57a11e8b"
  • 值得注意的是,GRUB_DEFAULT= 后面的文本要带有双引号,中间的大于号不要忘了。
  • 对于 ubuntu22.04 系统,还需要在末尾加入一段 GRUB_DISABLE_OS_PROBER=false

最后执行更新命令:

sudo update-grub

为避免出现 kernel headers are incomplete 的问题,直接将 kernel header 装一下:

sudo apt-get install linux-headers-5.15.0-25-generic

接下来重启,结果在启动Ubuntu时,载入内核时报错:Shim签名无效

无奈只能解决签名无效的问题。

4.
#

经过搜索,最简单的方法是在 bios 中将安全启动关闭,尝试有效,输入:

uname -r

输出:5.15.0-25-generic

处于崩溃边缘的我看到了一丝希望,这时重新安装驱动,诶?我wifi图标去哪了?

使用 iwconfig 命令,结果是:lo no wireless extensions.。并且发现使用原来的 6.8.0-48-generic 内核启动,可以正常连 wifi。???,去官网得知最新的版本驱动只支持内核版本 6.1 以上的,推测是内核改动导致驱动不识别,需要找一个适合内核版本的驱动。

5.
#

首先查看网卡型号(可以使用能联网的内核启动查看),我的型号是 Intel AX211 Wi-Fi6,在能联网的内核启动,执行:

sudo apt install flex bison
git clone https://github.com/intel/backport-iwlwifi.git

接下来到无驱动的内核,输入:

cd backport-iwlwifi
cd iwlwifi-stack-dev
sudo make defconfig-iwlwifi-public
sudo make
sudo make install

接下来重启,wifi图标回来了。

6.
#

回到我们的正题,安装显卡驱动,首先在官网下载驱动安装包。

接下来先禁用 nouveau:

sudo gedit /etc/modprobe.d/blacklist-nouveau.conf

在文件中加入两行:

blacklist nouveau
options nouveau modeset=0

更新一下:

sudo update-initramfs -u

之后重启,重启之后验证一下是否禁用成功:

lsmod | grep nouveau

如果无输出,则禁用成功。

接下来开始驱动安装,首先找到驱动文件(通常在主目录下的 Downloads 目录),进入目录:

cd Downloads

这里以我下载的 NVIDIA-Linux-x86_64-535.154.05.run 举例。

卸载原有驱动,并给新下载的 .run 文件赋予执行权限(第3行的 -no-opengl-files 意思是只安装驱动文件,不安装 OpenGL 文件):

sudo apt-get remove nvidia-*
sudo chmod a+x NVIDIA-Linux-x86_64-535.154.05.run
sudo ./NVIDIA-Linux-x86_64-535.154.05.run -no-opengl-files

一路 Enter,最后挂载驱动:

sudo modprobe nvidia

最后的最后,我们检查一下驱动安装情况:

nvidia-smi

成功显示!但是这里我又遇到了问题,虽然成功显示了 nvidia-smi 界面,但显卡栏并未读出来显卡,反而显示无显卡设备,代码也依然跑不起来。

7.
#

换一种安装方法吧,这里换成用PPA方法命令行安装。

首先先将上面的所有驱动全部删除(前3行是删除命令行安装的驱动;4-7行是卸载用 .run 文件安装的驱动):

sudo apt-get --purge remove nvidia*
sudo apt-get --purge remove "*nvidia*"
sudo apt-get remove --purge nvidia-*(/nvidia*)
cd /usr/bin
ls nvidia-*
sudo nvidia-uninstall
sudo /usr/bin/nvidia-uninstall

全部尝试过后,查看一下是否卸载干净:

ls /usr/src | grep nvidia

接下来添加PPA镜像源,开始安装:

sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt-get update
ubuntu-drivers devices

会出现许多推荐的驱动版本,没有我们想要的也没关系。(我的显示如下)

== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
modalias : pci:v000010DEd00002783sv00001B4Csd000018CAbc03sc00i00
vendor   : NVIDIA Corporation
manual_install: True
driver   : nvidia-driver-560-open - third-party non-free
driver   : nvidia-driver-550-server - distro non-free
driver   : nvidia-driver-550-open - third-party non-free
driver   : nvidia-driver-550 - third-party non-free
driver   : nvidia-driver-560 - third-party non-free recommended
driver   : nvidia-driver-555 - third-party non-free
driver   : nvidia-driver-550-server-open - distro non-free
driver   : nvidia-driver-555-open - third-party non-free
driver   : xserver-xorg-video-nouveau - distro free builtin

但是这里我们想安装 535 版本的驱动,直接尝试:

sudo apt install nvidia-driver-535

安装完成后重启,再次检测:

nvidia-smi

成功显示显卡型号!

在系统设置中的关于也可以看到显卡能检测为 NVIDIA 显卡:

最后的最后,跑代码也能顺利运行,真正成功!

8.
#

为了避免以后遇到同样的问题,可以将系统更新,内核更新等全部关掉。

输入:

sudo gedit /etc/apt/apt.conf.d/10periodic
sudo gedit /etc/apt/apt.conf.d/20auto-upgrades

将这些后面参数全部设为 0。

再输入:

sudo apt-mark hold linux-image-5.15.0-25-generic
sudo apt-mark hold linux-headers-5.15.0-25-generic
sudo apt-mark hold linux-modules-5.15.0-25-generic

使得软件包保持现状,可以查看hold的软件包:

sudo apt-mark showhold

若想取消hold,可以输入:

sudo apt-mark unhold linux-image-5.15.0-25-generic
sudo apt-mark unhold linux-headers-5.15.0-25-generic
sudo apt-mark unhold linux-modules-5.15.0-25-generic

另外,在 Software & Updates(软件和更新)中,找到 update(更新)标签,将 Automatically check for updates(自动检查更新)选项设为 Never(从不),如图:

后记
#

这个问题真是浅入深出啊,本来以为是个简单的掉驱动问题,没想到解决了一圈,花了一整天时间,Ubuntu 你罪该万死啊!

参考文献
#

1.NVIDIA驱动失效简单解决方案:NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver.

2.显卡驱动报错:NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver.v

3.Ubuntu22.04回退系统内核

4.Secure Boot时,提示内核签名无效

5.ubuntu20.04.6安装Intel AX211网卡驱动 2024.8

6.Ubuntu下安装nvidia显卡驱动

7.Ubuntu中之前安装好Nvidia驱动driver但是检测不到的解决(仅供参考)

8.Ubuntu 在线安装NVIDIA驱动——PPA方式

9.从 apt 升级中排除/保留/阻止特定软件包的三种方法

10.ubuntu20.04关闭内核自动更新、禁止/取消系统自动更新的方法