open-gpu-kernel-modules/kernel-open/nvidia/procfs_nvswitch.c
2022-05-09 13:18:59 -07:00

206 lines
5.0 KiB
C

/*
* SPDX-FileCopyrightText: Copyright (c) 2016-2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "linux_nvswitch.h"
#include "nv-procfs.h"
#include <linux/fs.h>
#if defined(CONFIG_PROC_FS)
#define NV_DEFINE_SINGLE_NVSWITCH_PROCFS_FILE(name) \
NV_DEFINE_SINGLE_PROCFS_FILE_READ_ONLY(name, nv_system_pm_lock)
#define NVSWITCH_PROCFS_DIR "driver/nvidia-nvswitch"
static struct proc_dir_entry *nvswitch_procfs_dir;
static struct proc_dir_entry *nvswitch_permissions;
static struct proc_dir_entry *nvswitch_procfs_devices;
static int
nv_procfs_read_permissions
(
struct seq_file *s,
void *v
)
{
// Restrict device node permissions - 0666. Used by nvidia-modprobe.
seq_printf(s, "%s: %u\n", "DeviceFileMode", 438);
return 0;
}
NV_DEFINE_SINGLE_NVSWITCH_PROCFS_FILE(permissions);
static int
nv_procfs_read_device_info
(
struct seq_file *s,
void *v
)
{
NVSWITCH_DEV *nvswitch_dev = s->private;
if (!nvswitch_dev)
{
NVSWITCH_OS_ASSERT(0);
return -EFAULT;
}
seq_printf(s, "BIOS Version: ");
if (nvswitch_dev->bios_ver)
{
seq_printf(s, "%02llx.%02llx.%02llx.%02llx.%02llx\n",
nvswitch_dev->bios_ver >> 32,
(nvswitch_dev->bios_ver >> 24) & 0xFF,
(nvswitch_dev->bios_ver >> 16) & 0xFF,
(nvswitch_dev->bios_ver >> 8) & 0xFF,
nvswitch_dev->bios_ver & 0xFF);
}
else
{
seq_printf(s, "N/A\n");
}
return 0;
}
NV_DEFINE_SINGLE_NVSWITCH_PROCFS_FILE(device_info);
void
nvswitch_procfs_device_remove
(
NVSWITCH_DEV *nvswitch_dev
)
{
if (!nvswitch_dev || !nvswitch_dev->procfs_dir)
{
NVSWITCH_OS_ASSERT(0);
return;
}
nv_procfs_unregister_all(nvswitch_dev->procfs_dir, nvswitch_dev->procfs_dir);
nvswitch_dev->procfs_dir = NULL;
}
int
nvswitch_procfs_device_add
(
NVSWITCH_DEV *nvswitch_dev
)
{
struct pci_dev *pci_dev;
struct proc_dir_entry *device_dir, *entry;
char name[32];
if (!nvswitch_dev || !nvswitch_dev->pci_dev)
{
NVSWITCH_OS_ASSERT(0);
return -1;
}
pci_dev = nvswitch_dev->pci_dev;
snprintf(name, sizeof(name), "%04x:%02x:%02x.%1x",
NV_PCI_DOMAIN_NUMBER(pci_dev), NV_PCI_BUS_NUMBER(pci_dev),
NV_PCI_SLOT_NUMBER(pci_dev), PCI_FUNC(pci_dev->devfn));
device_dir = NV_CREATE_PROC_DIR(name, nvswitch_procfs_devices);
if (!device_dir)
return -1;
nvswitch_dev->procfs_dir = device_dir;
entry = NV_CREATE_PROC_FILE("information", device_dir, device_info,
nvswitch_dev);
if (!entry)
goto failed;
return 0;
failed:
nvswitch_procfs_device_remove(nvswitch_dev);
return -1;
}
void
nvswitch_procfs_exit
(
void
)
{
if (!nvswitch_procfs_dir)
{
return;
}
nv_procfs_unregister_all(nvswitch_procfs_dir, nvswitch_procfs_dir);
nvswitch_procfs_dir = NULL;
}
int
nvswitch_procfs_init
(
void
)
{
nvswitch_procfs_dir = NV_CREATE_PROC_DIR(NVSWITCH_PROCFS_DIR, NULL);
if (!nvswitch_procfs_dir)
{
return -EACCES;
}
nvswitch_permissions = NV_CREATE_PROC_FILE("permissions",
nvswitch_procfs_dir,
permissions,
NULL);
if (!nvswitch_permissions)
{
goto cleanup;
}
nvswitch_procfs_devices = NV_CREATE_PROC_DIR("devices", nvswitch_procfs_dir);
if (!nvswitch_procfs_devices)
{
goto cleanup;
}
return 0;
cleanup:
nvswitch_procfs_exit();
return -EACCES;
}
#else // !CONFIG_PROC_FS
int nvswitch_procfs_init(void) { return 0; }
void nvswitch_procfs_exit(void) { }
int nvswitch_procfs_device_add(NVSWITCH_DEV *nvswitch_dev) { return 0; }
void nvswitch_procfs_device_remove(NVSWITCH_DEV *nvswitch_dev) { }
#endif // CONFIG_PROC_FS