Commit 2ccbdae5 authored by Andreas Beckmann's avatar Andreas Beckmann

New upstream version 390.25

parents a1ff1798 cfe79149
......@@ -62,6 +62,11 @@
#define NV_MODESET_MODULE_NAME "nvidia-modeset"
#define NV_VGPU_VFIO_MODULE_NAME "nvidia-vgpu-vfio"
#define NV_NVLINK_MODULE_NAME "nvidia-nvlink"
#define NV_NVLINK_PROC_PERM_PATH "/proc/driver/nvidia-nvlink/permissions"
#define NV_DEVICE_FILE_MODE_MASK (S_IRWXU|S_IRWXG|S_IRWXO)
#define NV_DEVICE_FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
#define NV_DEVICE_FILE_UID 0
......@@ -477,6 +482,65 @@ static void init_device_file_parameters(uid_t *uid, gid_t *gid, mode_t *mode,
fclose(fp);
}
/*
* A helper to query device file states.
*/
static int get_file_state_helper(
const char *path,
int major,
int minor,
const char *proc_path,
uid_t uid,
gid_t gid,
mode_t mode)
{
dev_t dev = NV_MAKE_DEVICE(major, minor);
struct stat stat_buf;
int ret;
int state = 0;
ret = stat(path, &stat_buf);
if (ret == 0)
{
nvidia_update_file_state(&state, NvDeviceFileStateFileExists);
if (S_ISCHR(stat_buf.st_mode) && (stat_buf.st_rdev == dev))
{
nvidia_update_file_state(&state, NvDeviceFileStateChrDevOk);
}
if (((stat_buf.st_mode & NV_DEVICE_FILE_MODE_MASK) == mode) &&
(stat_buf.st_uid == uid) &&
(stat_buf.st_gid == gid))
{
nvidia_update_file_state(&state, NvDeviceFileStatePermissionsOk);
}
}
return state;
}
int nvidia_get_file_state(int minor, int module_instance)
{
char path[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
char proc_path[NV_MAX_PROC_REGISTRY_PATH_SIZE];
mode_t mode;
uid_t uid;
gid_t gid;
int modification_allowed;
int state = 0;
assign_device_file_name(path, minor, module_instance);
assign_proc_registry_path(proc_path, module_instance);
init_device_file_parameters(&uid, &gid, &mode, &modification_allowed,
proc_path);
state = get_file_state_helper(path, NV_MAJOR_DEVICE_NUMBER, minor,
proc_path, uid, gid, mode);
return state;
}
/*
* Attempt to create the specified device file with the specified major
......@@ -484,8 +548,8 @@ static void init_device_file_parameters(uid_t *uid, gid_t *gid, mode_t *mode,
* permissions. Returns 1 if the file is successfully created; returns 0
* if the file could not be created.
*/
static int mknod_helper(int major, int minor, const char *path,
const char *proc_path)
int mknod_helper(int major, int minor, const char *path,
const char *proc_path)
{
dev_t dev = NV_MAKE_DEVICE(major, minor);
mode_t mode;
......@@ -493,7 +557,7 @@ static int mknod_helper(int major, int minor, const char *path,
gid_t gid;
int modification_allowed;
int ret;
struct stat stat_buf;
int state;
int do_mknod;
if (path == NULL || path[0] == '\0')
......@@ -511,18 +575,12 @@ static int mknod_helper(int major, int minor, const char *path,
return 1;
}
/*
* If the device file already exists with correct properties,
* nothing to do: success.
*/
ret = stat(path, &stat_buf);
state = get_file_state_helper(path, major, minor,
proc_path, uid, gid, mode);
if ((ret == 0) &&
(S_ISCHR(stat_buf.st_mode)) &&
(stat_buf.st_rdev == dev) &&
((stat_buf.st_mode & NV_DEVICE_FILE_MODE_MASK) == mode) &&
(stat_buf.st_uid == uid) &&
(stat_buf.st_gid == gid))
if (nvidia_test_file_state(state, NvDeviceFileStateFileExists) &&
nvidia_test_file_state(state, NvDeviceFileStateChrDevOk) &&
nvidia_test_file_state(state, NvDeviceFileStatePermissionsOk))
{
return 1;
}
......@@ -531,19 +589,18 @@ static int mknod_helper(int major, int minor, const char *path,
do_mknod = 0;
if (ret != 0)
if (!nvidia_test_file_state(state, NvDeviceFileStateFileExists))
{
do_mknod = 1;
}
/*
* If the stat(2) above succeeded but the file is either not a
* character device or has the wrong major/minor character device
* number, then we need to delete it and recreate it.
* If the file exists but the file is either not a character device or has
* the wrong major/minor character device number, then we need to delete it
* and recreate it.
*/
if ((ret == 0) &&
(!S_ISCHR(stat_buf.st_mode) ||
(stat_buf.st_rdev != dev)))
if (!do_mknod &&
!nvidia_test_file_state(state, NvDeviceFileStateChrDevOk))
{
ret = remove(path);
if (ret != 0)
......@@ -602,7 +659,7 @@ int nvidia_mknod(int minor, int module_instance)
* device with the specified name. Returns the major number on success,
* or -1 on failure.
*/
static int get_chardev_major(const char *name)
int get_chardev_major(const char *name)
{
int ret = -1;
char line[NV_MAX_LINE_LENGTH];
......@@ -714,11 +771,50 @@ int nvidia_modeset_mknod(void)
{
char proc_path[NV_MAX_PROC_REGISTRY_PATH_SIZE];
assign_proc_registry_path(proc_path, 0);
assign_proc_registry_path(proc_path, NV_MODULE_INSTANCE_NONE);
return mknod_helper(NV_MAJOR_DEVICE_NUMBER,
NV_MODESET_MINOR_DEVICE_NUM,
NV_MODESET_DEVICE_NAME, proc_path);
}
/*
* Attempt to create the NVIDIA NVLink driver device file.
*/
int nvidia_nvlink_mknod(void)
{
int major = get_chardev_major(NV_NVLINK_MODULE_NAME);
if (major < 0)
{
return 0;
}
return mknod_helper(major,
0,
NV_NVLINK_DEVICE_NAME,
NV_NVLINK_PROC_PERM_PATH);
}
int nvidia_vgpu_vfio_mknod(int minor_num)
{
int major = get_chardev_major(NV_VGPU_VFIO_MODULE_NAME);
char vgpu_dev_name[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
char proc_path[NV_MAX_PROC_REGISTRY_PATH_SIZE];
if (major < 0)
{
return 0;
}
assign_proc_registry_path(proc_path, NV_MODULE_INSTANCE_NONE);
snprintf(vgpu_dev_name, NV_MAX_CHARACTER_DEVICE_FILE_STRLEN,
NV_VGPU_VFIO_DEVICE_NAME, minor_num);
vgpu_dev_name[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN - 1] = '\0';
return mknod_helper(major, minor_num, vgpu_dev_name, proc_path);
}
#endif /* NV_LINUX */
......@@ -42,6 +42,8 @@
#define NV_DEVICE_FILE_PATH "/dev/nvidia%d"
#define NV_CTRL_DEVICE_FILE_PATH "/dev/nvidiactl"
#define NV_MODESET_DEVICE_NAME "/dev/nvidia-modeset"
#define NV_VGPU_VFIO_DEVICE_NAME "/dev/nvidia-vgpu%d"
#define NV_NVLINK_DEVICE_NAME "/dev/nvidia-nvlink"
#define NV_NMODULE_CTRL_DEVICE_FILE_PATH "/dev/nvidiactl%d"
......@@ -55,16 +57,39 @@
#if defined(NV_LINUX)
typedef enum
{
NvDeviceFileStateFileExists = 0,
NvDeviceFileStateChrDevOk,
NvDeviceFileStatePermissionsOk
} NvDeviceFileState;
static __inline__ void nvidia_update_file_state(int *state,
NvDeviceFileState value)
{
*state |= (1 << value);
}
static __inline__ int nvidia_test_file_state(int state,
NvDeviceFileState value)
{
return !!(state & (1 << value));
}
int nvidia_get_file_state(int minor, int module_instance);
int nvidia_modprobe(const int print_errors, int module_instance);
int nvidia_mknod(int minor, int module_instance);
int nvidia_uvm_modprobe(void);
#define nvidia_uvm_modprobe(print_errors) nvidia_uvm_modprobe()
int nvidia_uvm_mknod(int base_minor);
int nvidia_modeset_modprobe(void);
int nvidia_modeset_mknod(void);
int nvidia_vgpu_vfio_mknod(int minor_num);
int nvidia_nvlink_mknod(void);
#endif /* NV_LINUX */
int mknod_helper(int major, int minor, const char *path, const char *proc_path);
int get_chardev_major(const char *name);
#endif /* NV_LINUX */
/*
* Detect use of multiple kernel module instances. Use a single
......
/*
* (C) Copyright IBM Corporation 2006
*
* Copyright (c) 2014-2017 NVIDIA Corporation
* Copyright (c) 2014 NVIDIA Corporation
*
* All Rights Reserved.
*
......@@ -51,8 +51,6 @@
#include <sys/mman.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
#include "pci-enum.h"
#include "pci-sysfs.h"
......@@ -60,23 +58,11 @@
#define SYS_BUS_PCI "/sys/bus/pci/"
#define SYS_BUS_PCI_DEVICES SYS_BUS_PCI "devices"
#define SYS_BUS_PCI_RESCAN SYS_BUS_PCI "rescan"
#define PCI_DBDF_FORMAT "%04x:%02x:%02x.%1u"
#define SYSFS_PCI_BRIDGE_RESCAN_FMT SYS_BUS_PCI_DEVICES "/" PCI_DBDF_FORMAT "/rescan"
#define SYSFS_PCI_BRIDGE_RESCAN_FMT SYS_BUS_PCI_DEVICES "/%04x:%02x:%02x.%1x/rescan"
#define SYSFS_RESCAN_STRING "1\n"
#define SYSFS_RESCAN_STRING_SIZE 2
#define PCI_CAP_TTL_MAX 20
#define SYSFS_PATH_SIZE 256
#define BAIL_ON_IO_ERR(buf, err, cnt, action) \
do { \
if (((err) != 0) || ((cnt) < sizeof(buf))) \
{ \
(err) = ((err) == 0) ? EIO : (err); \
action; \
} \
} while (0)
static int pci_sysfs_read_cfg(uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, void *,
static int pci_sysfs_read_cfg(uint16_t, uint16_t, uint16_t, uint16_t, void *,
uint16_t size, uint16_t *);
static int find_matches(struct pci_id_match *match);
......@@ -142,10 +128,10 @@ find_matches(struct pci_id_match *match)
continue;
}
sscanf(d->d_name, PCI_DBDF_FORMAT,
sscanf(d->d_name, "%04x:%02x:%02x.%1u",
& dom, & bus, & dev, & func);
err = pci_sysfs_read_cfg(dom, bus, dev, func, 0, config, 48, & bytes);
err = pci_sysfs_read_cfg(dom, bus, dev, func, config, 48, & bytes);
if ((bytes == 48) && !err)
{
vendor_id = (uint16_t)config[0] + ((uint16_t)config[1] << 8);
......@@ -184,10 +170,10 @@ find_matches(struct pci_id_match *match)
static int
pci_sysfs_read_cfg(uint16_t domain, uint16_t bus, uint16_t device,
uint16_t function, uint16_t off, void *data,
uint16_t size, uint16_t *bytes_read)
uint16_t function, void * data, uint16_t size,
uint16_t *bytes_read)
{
char name[SYSFS_PATH_SIZE];
char name[256];
uint16_t temp_size = size;
int err = 0;
int fd;
......@@ -204,7 +190,7 @@ pci_sysfs_read_cfg(uint16_t domain, uint16_t bus, uint16_t device,
* space. It is used here to obtain most of the information about the
* device.
*/
snprintf(name, SYSFS_PATH_SIZE - 1, "%s/" PCI_DBDF_FORMAT "/config",
snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/config",
SYS_BUS_PCI_DEVICES, domain, bus, device, function);
fd = open(name, O_RDONLY);
......@@ -213,15 +199,6 @@ pci_sysfs_read_cfg(uint16_t domain, uint16_t bus, uint16_t device,
return errno;
}
if (off != 0)
{
if (lseek(fd, (off_t) off, SEEK_SET) < 0)
{
close(fd);
return errno;
}
}
while (temp_size > 0)
{
const ssize_t bytes = read(fd, data_bytes, temp_size);
......@@ -249,81 +226,11 @@ pci_sysfs_read_cfg(uint16_t domain, uint16_t bus, uint16_t device,
return err;
}
static int
pci_sysfs_write_cfg(uint16_t domain, uint16_t bus, uint16_t device,
uint16_t function, uint16_t off, void *data,
uint16_t size, uint16_t *bytes_written)
{
char name[SYSFS_PATH_SIZE];
uint16_t temp_size = size;
int err = 0;
int fd;
char *data_bytes = data;
if (bytes_written != NULL)
{
*bytes_written = 0;
}
/*
* Each device has a directory under sysfs. Within that directory there
* is a file named "config". This file used to access the PCI config
* space.
*/
snprintf(name, SYSFS_PATH_SIZE - 1, "%s/" PCI_DBDF_FORMAT "/config",
SYS_BUS_PCI_DEVICES, domain, bus, device, function);
fd = open(name, O_WRONLY);
if (fd < 0)
{
return errno;
}
if (off != 0)
{
if (lseek(fd, (off_t) off, SEEK_SET) < 0)
{
close(fd);
return errno;
}
}
while (temp_size > 0)
{
const ssize_t bytes = write(fd, data_bytes, temp_size);
if (bytes < 0)
{
err = errno;
break;
}
/*
* If zero bytes were written, then we assume it's the end of the
* config file.
*/
if (bytes == 0)
{
break;
}
temp_size -= bytes;
data_bytes += bytes;
}
if (bytes_written != NULL)
{
*bytes_written = size - temp_size;
}
close(fd);
return err;
}
int
pci_rescan(uint16_t domain, uint8_t bus, uint8_t slot, uint8_t function)
{
char const *node;
char node_buf[SYSFS_PATH_SIZE];
char node_buf[256];
int node_fd;
ssize_t cnt;
......@@ -353,153 +260,4 @@ pci_rescan(uint16_t domain, uint8_t bus, uint8_t slot, uint8_t function)
return cnt == SYSFS_RESCAN_STRING_SIZE ? 0 : EIO;
}
int
pci_find_parent_bridge(pci_info_t *p_gpu_info, pci_info_t *p_bridge_info)
{
char gpu_path[SYSFS_PATH_SIZE];
char bridge_path[SYSFS_PATH_SIZE];
char *p_node;
snprintf(gpu_path, SYSFS_PATH_SIZE - 1, "%s/" PCI_DBDF_FORMAT "/..", SYS_BUS_PCI_DEVICES,
p_gpu_info->domain, p_gpu_info->bus,
p_gpu_info->dev, p_gpu_info->ftn);
if (realpath(gpu_path, bridge_path) == NULL)
{
return errno;
}
p_node = strrchr(bridge_path, '/');
if (p_node == NULL)
{
return ENOENT;
}
++p_node;
if (sscanf(p_node, PCI_DBDF_FORMAT,
&p_bridge_info->domain, &p_bridge_info->bus,
&p_bridge_info->dev, &p_bridge_info->ftn) != 4)
{
return ENOENT;
}
return 0;
}
static int
pci_find_pcie_caps(uint16_t domain, uint8_t bus, uint8_t device, uint8_t ftn, uint8_t *p_caps)
{
unsigned ttl;
uint8_t off;
uint8_t cap_id;
int err = ENXIO;
uint16_t cnt;
for (off = PCI_CAPABILITY_LIST, ttl = PCI_CAP_TTL_MAX; ttl; --ttl)
{
err = pci_sysfs_read_cfg(domain, bus, device, ftn, off,
&off, sizeof(off), &cnt);
BAIL_ON_IO_ERR(off, err, cnt, break);
/* Capabilities must reside above the std config header */
if ((off < PCI_STD_HEADER_SIZEOF) || (off == 0xff))
{
break;
}
/* Clear the reserved bits */
off &= ~3;
err = pci_sysfs_read_cfg(domain, bus, device, ftn, off + PCI_CAP_LIST_ID,
&cap_id, sizeof(cap_id), &cnt);
BAIL_ON_IO_ERR(cap_id, err, cnt, break);
if (cap_id == PCI_CAP_ID_EXP)
{
goto found;
}
if (cap_id == 0xff)
{
break;
}
off += PCI_CAP_LIST_NEXT;
}
return err;
found:
*p_caps = off;
return 0;
}
int
pci_bridge_link_set_enable(uint16_t domain, uint8_t bus, uint8_t device, uint8_t ftn, int enable)
{
uint8_t pcie_caps = 0;
uint16_t reg;
uint16_t cnt;
int err;
struct timeval start;
struct timeval curr;
struct timeval diff;
struct timespec delay = {0, PCI_LINK_DELAY_NS};
err = pci_find_pcie_caps(domain, bus, device, ftn, &pcie_caps);
if (err != 0)
{
return err;
}
err = pci_sysfs_read_cfg(domain, bus, device, ftn, pcie_caps + PCI_EXP_LNKCTL,
&reg, sizeof(reg), &cnt);
BAIL_ON_IO_ERR(reg, err, cnt, return err);
if (enable)
{
reg &= ~PCI_EXP_LNKCTL_LD;
}
else
{
reg |= PCI_EXP_LNKCTL_LD;
}
err = pci_sysfs_write_cfg(domain, bus, device, ftn, pcie_caps + PCI_EXP_LNKCTL,
&reg, sizeof(reg), &cnt);
BAIL_ON_IO_ERR(reg, err, cnt, return err);
if (enable)
{
/* wait for the link to go up and then sleep for 100 ms */
gettimeofday(&start, NULL);
for (;;)
{
err = pci_sysfs_read_cfg(domain, bus, device, ftn, pcie_caps + PCI_EXP_LNKSTA,
&reg, sizeof(reg), &cnt);
BAIL_ON_IO_ERR(reg, err, cnt, return err);
if ((reg & PCI_EXP_LNKSTA_DLLLA) != 0)
{
break;
}
gettimeofday(&curr, NULL);
timersub(&curr, &start, &diff);
if ((diff.tv_sec > 0) || (diff.tv_usec >= PCI_LINK_WAIT_US))
{
return ETIME;
}
}
PCI_NANOSLEEP(&delay, NULL);
}
return err;
}
#endif /* defined(NV_LINUX) */
/*
* Copyright (c) 2016-2017, NVIDIA CORPORATION.
* Copyright (c) 2016, NVIDIA CORPORATION.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
......@@ -28,51 +28,6 @@
#ifndef __PCI_SYSFS_H__
#define __PCI_SYSFS_H__
#if defined(NV_LINUX)
#include <linux/pci.h>
#if !defined(PCI_STD_HEADER_SIZEOF)
#define PCI_STD_HEADER_SIZEOF 64
#endif
#if !defined(PCI_CAP_ID_EXP)
#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
#endif
#if !defined(PCI_EXP_LNKCTL)
#define PCI_EXP_LNKCTL 16 /* Link Control */
#endif
#if !defined(PCI_EXP_LNKCTL_LD)
#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */
#endif
#if !defined(PCI_EXP_LNKSTA)
#define PCI_EXP_LNKSTA 18 /* Link Status */
#endif
#if !defined(PCI_EXP_LNKSTA_DLLLA)
#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */
#endif
#define PCI_LINK_WAIT_US 200000 /* 200 ms, must be less than 1000000 (1s) */
#define PCI_LINK_DELAY_NS 100000000 /* 100 ms */
#if (_POSIX_C_SOURCE >= 199309L)
#define PCI_NANOSLEEP(ts, rem) nanosleep(ts, rem)
#elif !(_POSIX_C_SOURCE >= 200809L)
#define PCI_NANOSLEEP(ts, rem) usleep((ts)->tv_sec * 1000000 + ((ts)->tv_nsec + 999) / 1000)
#else
#define PCI_NANOSLEEP(ts, rem) sleep((ts)->tv_sec + ((ts)->tv_nsec + 999999999) / 1000000000)
#endif
typedef struct {
unsigned domain;
unsigned bus;
unsigned dev;
unsigned ftn;
} pci_info_t;
int pci_rescan(uint16_t domain, uint8_t bus, uint8_t slot, uint8_t function);
int pci_find_parent_bridge(pci_info_t *p_gpu_info, pci_info_t *p_bridge_info);
int pci_bridge_link_set_enable(uint16_t domain, uint8_t bus, uint8_t device, uint8_t ftn, int enable);
#endif /* NV_LINUX */
#endif /* __PCI_SYSFS_H__ */
......@@ -80,6 +80,7 @@ HOSTNAME_CMD ?= hostname
DATE ?= date
GZIP_CMD ?= gzip
CHMOD ?= chmod
OBJCOPY ?= objcopy
NV_AUTO_DEPEND ?= 1
NV_VERBOSE ?= 0
......@@ -271,10 +272,14 @@ endif
NV_MODULE_LOGGING_NAME ?=
ifeq ($(NV_VERBOSE),0)
quiet_cmd = @$(PRINTF) \
at_if_quiet := @
quiet_cmd_no_at = $(PRINTF) \
" $(if $(NV_MODULE_LOGGING_NAME),[ %-17.17s ],%s) $(quiet_$(1))\n" \
"$(NV_MODULE_LOGGING_NAME)" && $($(1))
quiet_cmd = @$(quiet_cmd_no_at)
else
at_if_quiet :=
quiet_cmd_no_at = $($(1))
quiet_cmd = $($(1))
endif
......@@ -295,6 +300,8 @@ quiet_HOST_LINK = $(call define_quiet_cmd,HOST_LINK ,$@)
quiet_M4 = $(call define_quiet_cmd,M4 ,$<)
quiet_STRIP_CMD = $(call define_quiet_cmd,STRIP ,$@)
quiet_HARDLINK = $(call define_quiet_cmd,HARDLINK ,$@)
quiet_LD = $(call define_quiet_cmd,LD ,$@)
quiet_OBJCOPY = $(call define_quiet_cmd,OBJCOPY ,$@)
##############################################################################
# Tell gmake to delete the target of a rule if it has changed and its
......@@ -447,3 +454,30 @@ define DEFINE_STAMP_C_RULE
@ $$(PRINTF) "%s\n" "const char *pNV_ID = NV_ID + 11;" >> $$@
endef
##############################################################################
# Define rules that can be used for embedding a file into an ELF object that
# contains the raw contents of that file and symbols pointing to the embedded
# data.
#
# Note that objcopy will name the symbols in the resulting object file based on
# the filename specified in $(1). For example,
#
# $(eval $(call $(READ_ONLY_OBJECT_FROM_FILE_RULE),a/b/c))
#
# will create an object named $(OUTPUTDIR)/c.o with the symbols _binary_c_start,
# _binary_c_end, and _binary_c_size.
#
# Arguments:
# $(1): Path to the file to convert
##############################################################################
define READ_ONLY_OBJECT_FROM_FILE_RULE
$$(OUTPUTDIR)/$$(notdir $(1)).o: $(1)
$(at_if_quiet)cd $$(dir $(1)); \
$$(call quiet_cmd_no_at,LD) -r -z noexecstack --format=binary \
$$(notdir $(1)) -o $$(OUTPUTDIR_ABSOLUTE)/$$(notdir $$@)
$$(call quiet_cmd,OBJCOPY) \
--rename-section .data=.rodata,contents,alloc,load,data,readonly \
$$@
endef
NVIDIA_VERSION = 384.111
NVIDIA_VERSION = 390.25
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment