diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2010-07-29 14:56:40 -0700 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2010-07-29 14:56:40 -0700 |
commit | 2afc0d0c29d810f8c96380acd9cff776302c308b (patch) | |
tree | a41a3b6f977659ca9af2e0e714eb23860a83a3bc | |
parent | 1033fdc743ea8a6502273f08e5ebd8a3a91548dc (diff) |
256.44256.44
-rw-r--r-- | install-from-cwd.c | 4 | ||||
-rw-r--r-- | kernel.c | 4 | ||||
-rw-r--r-- | misc.c | 217 | ||||
-rw-r--r-- | misc.h | 1 | ||||
-rw-r--r-- | nvidia-installer.c | 1 | ||||
-rw-r--r-- | nvidia-installer.h | 1 | ||||
-rw-r--r-- | option_table.h | 4 | ||||
-rw-r--r-- | version.mk | 2 |
8 files changed, 231 insertions, 3 deletions
diff --git a/install-from-cwd.c b/install-from-cwd.c index 2af25f2..292d0a3 100644 --- a/install-from-cwd.c +++ b/install-from-cwd.c @@ -139,6 +139,10 @@ int install_from_cwd(Options *op) } ran_pre_install_hook = TRUE; + /* fail if the nouveau driver is currently in use */ + + if (!check_for_nouveau(op)) goto failed; + /* attempt to build a kernel module for the target kernel */ if (!op->no_kernel_module) { @@ -746,8 +746,8 @@ int test_kernel_module(Options *op, Package *p) "built against the wrong or improperly configured " "kernel sources, with a version of gcc that differs " "from the one used to build the target kernel, or " - "if a driver such as rivafb/nvidiafb is present and " - "prevents the NVIDIA kernel module from obtaining " + "if a driver such as rivafb, nvidiafb, or nouveau is present " + "and prevents the NVIDIA kernel module from obtaining " "ownership of the NVIDIA graphics device(s), or " "NVIDIA GPU installed in this system is not supported " "by this NVIDIA Linux graphics driver release.\n\n" @@ -2410,3 +2410,220 @@ done: nvfree(cmd); return ret; } + + + +/* + * Determine if the nouveau driver is currently in use. We do the + * equivalent of: + * + * ls -l /sys/bus/pci/devices/*\/driver | grep nouveau + * + * The directory structure under /sys/bus/pci/devices/ should contain + * a directory for each PCI device, and for those devices with a + * kernel driver there will be a "driver" symlink. + * + * This appears to be consistent with how libpciaccess works. + * + * Returns TRUE if nouveau is found; returns FALSE if not. + */ + +#define SYSFS_DEVICES_PATH "/sys/bus/pci/devices" + +static int nouveau_is_present(void) +{ + DIR *dir; + struct dirent * ent; + int found = FALSE; + + dir = opendir(SYSFS_DEVICES_PATH); + + if (!dir) { + return FALSE; + } + + while ((ent = readdir(dir)) != NULL) { + + char driver_path[PATH_MAX]; + char symlink_target[PATH_MAX]; + char *name; + ssize_t ret; + + if ((strcmp(ent->d_name, ".") == 0) || + (strcmp(ent->d_name, "..") == 0)) { + continue; + } + + snprintf(driver_path, PATH_MAX, + SYSFS_DEVICES_PATH "/%s/driver", ent->d_name); + + driver_path[PATH_MAX - 1] = '\0'; + + ret = readlink(driver_path, symlink_target, PATH_MAX); + if (ret < 0) { + continue; + } + + /* readlink(3) does not nul-terminate its returned string */ + + ret = NV_MIN(ret, PATH_MAX - 1); + + symlink_target[ret] = '\0'; + + name = basename(symlink_target); + + if (strcmp(name, "nouveau") == 0) { + found = TRUE; + break; + } + } + + closedir(dir); + + return found; +} + + + +/* + * Write a modprobe configuration fragment to disable loading of + * nouveau: + * + * if [ -d /etc/modprobe.d ]; then + * name=/etc/modprobe.d/nvidia-installer-nouveau-blacklist + * echo "# generated by nvidia-installer" > $name + * echo "blacklist nouveau" >> $name + * echo "options nouveau modeset=0" >> $name + * fi + * + * Returns TRUE if successful; returns FALSE if there was a failure. + */ + +#define ETC_MODPROBE_D "/etc/modprobe.d" +#define ETC_MODPROBE_D_FILE \ + ETC_MODPROBE_D "/nvidia-installer-disable-nouveau.conf" + +/* + * this checksum is the result of compute_crc() for the file contents + * written in blacklist_nouveau() + */ + +#define ETC_MODPROBE_D_FILE_CKSUM 3728279991U + +static int blacklist_nouveau(void) +{ + int ret; + struct stat stat_buf; + FILE *file; + + ret = stat(ETC_MODPROBE_D, &stat_buf); + + if (ret != 0) { + return FALSE; + } + + file = fopen(ETC_MODPROBE_D_FILE, "w+"); + + if (!file) { + return FALSE; + } + + fprintf(file, "# generated by nvidia-installer\n"); + fprintf(file, "blacklist nouveau\n"); + fprintf(file, "options nouveau modeset=0\n"); + + ret = fclose(file); + + if (ret != 0) { + return FALSE; + } + + return TRUE; +} + + + +/* + * Check if the nouveau blacklist file is already present with the + * contents that we expect + */ + +static int nouveau_blacklist_file_is_present(Options *op) +{ + if (access(ETC_MODPROBE_D_FILE, R_OK) != 0) { + return FALSE; + } + + if (compute_crc(op, ETC_MODPROBE_D_FILE) != ETC_MODPROBE_D_FILE_CKSUM) { + return FALSE; + } + + return TRUE; +} + + + +/* + * Check if the nouveau kernel driver is in use. If it is, provide an + * appropriate error message and offer to try to disable nouveau. + * + * Returns FALSE if the nouveau kernel driver is in use (cause + * installation to abort); returns TRUE if the nouveau driver is not + * in use. + */ + +int check_for_nouveau(Options *op) +{ + int ret; + +#define NOUVEAU_POINTER_MESSAGE \ + "Please consult the NVIDIA driver README and your Linux " \ + "distribution's documentation for details on how to correctly " \ + "disable the Nouveau kernel driver." + + if (op->no_nouveau_check) return TRUE; + + if (!nouveau_is_present()) return TRUE; + + ui_error(op, "The Nouveau kernel driver is currently in use " + "by your system. This driver is incompatible with the NVIDIA " + "driver, and must be disabled before proceeding. " + NOUVEAU_POINTER_MESSAGE); + + if (nouveau_blacklist_file_is_present(op)) { + ui_warn(op, "The modprobe configuration file to disable Nouveau, " + ETC_MODPROBE_D_FILE ", is already present. Please be " + "sure you have rebooted your system since that file was " + "written. If you have rebooted, then Nouveau may be enabled " + "for other reasons, such as being included in the system " + "initial ramdisk or in your X configuration file. " + NOUVEAU_POINTER_MESSAGE); + return FALSE; + } + + ret = ui_yes_no(op, FALSE, "For some distributions, Nouveau can be " + "disabled by adding a file in the modprobe configuration " + "directory. Would you like nvidia-installer to attempt " + "to create this modprobe file for you?"); + + if (ret) { + ret = blacklist_nouveau(); + + if (ret) { + ui_message(op, "The modprobe configuration file to disable " + "Nouveau, " ETC_MODPROBE_D_FILE ", has been written. " + "For some distributions, this may be sufficient to " + "disable Nouveau; other distributions may require " + "modification of the initial ramdisk. Please reboot " + "your system and attempt NVIDIA driver installation " + "again. Note if you later wish to reenable Nouveau, " + "you will need to delete the file " + ETC_MODPROBE_D_FILE "."); + } else { + ui_warn(op, "Unable to alter the nouveau modprobe configuration. " + NOUVEAU_POINTER_MESSAGE); + } + } + + return FALSE; +} @@ -104,5 +104,6 @@ int check_for_modular_xorg(Options *op); int check_for_nvidia_graphics_devices(Options *op, Package *p); int run_nvidia_xconfig(Options *op); int run_distro_hook(Options *op, const char *hook); +int check_for_nouveau(Options *op); #endif /* __NVIDIA_INSTALLER_MISC_H__ */ diff --git a/nvidia-installer.c b/nvidia-installer.c index 48912f8..0269533 100644 --- a/nvidia-installer.c +++ b/nvidia-installer.c @@ -185,6 +185,7 @@ static void parse_commandline(int argc, char *argv[], Options *op) op->silent = op->no_questions = op->accept_license = TRUE; op->ui_str = "none"; break; + case 'z': op->no_nouveau_check = TRUE; break; case 'k': op->kernel_name = strval; diff --git a/nvidia-installer.h b/nvidia-installer.h index e1d7285..ed12589 100644 --- a/nvidia-installer.h +++ b/nvidia-installer.h @@ -141,6 +141,7 @@ typedef struct __options { int no_x_check; int no_nvidia_xconfig_question; int run_distro_scripts; + int no_nouveau_check; char *opengl_prefix; char *opengl_libdir; diff --git a/option_table.h b/option_table.h index 7ad2e99..1d2a644 100644 --- a/option_table.h +++ b/option_table.h @@ -412,6 +412,10 @@ static const NVGetoptOption __options[] = { "for distributing precompiled kernel interfaces in a local area " "network." }, + { "no-nouveau-check", 'z', 0, + "Normally, nvidia-installer aborts installation if the nouveau kernel " + "driver is in use. Use this option to disable this check." }, + { "run-nvidia-xconfig", 'X', 0, "nvidia-installer can optionally invoke the nvidia-xconfig utility. " "This will update the system X configuration file so that the NVIDIA X " @@ -1 +1 @@ -NVIDIA_VERSION = 256.38.02 +NVIDIA_VERSION = 256.44 |