mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 02:01:36 +03:00
mft: Initial copy of mft source
Add initial mft source of version-4.26.1-3 from https://www.mellanox.com/downloads/MFT/mft-4.26.1-3-arm64-deb.tgz bug 4192483 bug 4312056 Change-Id: I77c0af297c9833c3dcbcdfc89b316042548b9af8 Signed-off-by: Bharath H S <bhs@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3069977 (cherry picked from commit d65df2a986469950aab3f323bbee3a3aee0c0308) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3069972 GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com> Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
f451b88fd7
commit
bf89e2d98e
@@ -0,0 +1,32 @@
|
||||
KPVER ?= $(shell uname -r)
|
||||
KSRC ?= /lib/modules/$(KPVER)/build
|
||||
|
||||
# Oracle Linux OS.
|
||||
ifneq ($(shell if (echo $(KPVER) | grep -qE 'uek'); then \
|
||||
echo "YES"; else echo ""; fi),)
|
||||
override WITH_MAKE_PARAMS += ctf-dir=$(CWD)/.ctf
|
||||
endif
|
||||
|
||||
NNT_DRIVER_LOCATION = ../../nnt_driver
|
||||
PACKAGE_NAME = nnt-driver
|
||||
PACKAGE_VERSION = 1.0.0
|
||||
PACKAGE_RC = 1
|
||||
|
||||
%: %.in
|
||||
sed \
|
||||
-e 's/@PACKAGE_NAME@/$(PACKAGE_NAME)/g' \
|
||||
-e 's/@PACKAGE_VERSION@/$(PACKAGE_VERSION)/g' \
|
||||
-e 's/@PACKAGE_RC@/$(PACKAGE_RC)/g' \
|
||||
<$< >$@
|
||||
|
||||
obj-m += mst_pci.o
|
||||
EXTRA_CFLAGS= -I$(PWD)/$(NNT_DRIVER_LOCATION)
|
||||
mst_pci-objs += $(NNT_DRIVER_LOCATION)/nnt_device.o $(NNT_DRIVER_LOCATION)/nnt_dma.o $(NNT_DRIVER_LOCATION)/nnt_pci_conf_access.o \
|
||||
$(NNT_DRIVER_LOCATION)/nnt_pci_conf_access_no_vsec.o $(NNT_DRIVER_LOCATION)/nnt_memory_access.o \
|
||||
$(NNT_DRIVER_LOCATION)/nnt_ioctl.o mst_pci_bc.o
|
||||
|
||||
all:
|
||||
make -C $(KSRC) M=$(PWD) CONFIG_CTF= CONFIG_CC_STACKPROTECTOR_STRONG= $(WITH_MAKE_PARAMS) modules
|
||||
|
||||
clean:
|
||||
make -C $(KSRC) M=$(PWD) clean
|
||||
@@ -0,0 +1,3 @@
|
||||
mst_pciconf.ko external
|
||||
mst_pci.ko external
|
||||
mst_ppc_pci_reset.ko external
|
||||
@@ -0,0 +1,436 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "nnt_ioctl.h"
|
||||
#include "nnt_defs.h"
|
||||
#include "nnt_device.h"
|
||||
#include "nnt_ioctl_defs.h"
|
||||
#include "nnt_pci_conf_access.h"
|
||||
#include "mst_pci_bc.h"
|
||||
|
||||
MODULE_AUTHOR("Itay Avraham <itayavr@nvidia.com>");
|
||||
MODULE_DESCRIPTION("NNT Linux driver (NVIDIA® networking tools driver), this is the backward compatibility driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
struct driver_info nnt_driver_info;
|
||||
static int major_number = -1;
|
||||
static char* name = "mst_pci";
|
||||
|
||||
#define INIT PCI_INIT
|
||||
#define STOP PCI_STOP
|
||||
#define PCI_PARAMS_ PCI_PARAMS
|
||||
#define CONNECTX_WA PCI_CONNECTX_WA
|
||||
|
||||
struct mst_device_data
|
||||
{
|
||||
char buffer[MST_BC_BUFFER_SIZE];
|
||||
int buffer_used;
|
||||
};
|
||||
|
||||
static struct mst_device_data mst_devices[MST_BC_MAX_MINOR];
|
||||
|
||||
static int mst_pci_bc_open(struct inode* inode, struct file* file)
|
||||
{
|
||||
if (file->private_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
set_private_data_open(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t mst_pci_bc_read(struct file* file, char* buf, size_t count, loff_t* f_pos)
|
||||
{
|
||||
struct mst_device_data* mst_device = NULL;
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
int* buffer_used = NULL;
|
||||
char* buffer = NULL;
|
||||
int minor = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
minor = iminor(file_inode(file));
|
||||
mst_device = &mst_devices[minor];
|
||||
buffer = mst_device->buffer;
|
||||
buffer_used = &mst_device->buffer_used;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = nnt_device->buffer_bc;
|
||||
buffer_used = &nnt_device->buffer_used_bc;
|
||||
error = mutex_lock_nnt(file);
|
||||
CHECK_ERROR(error);
|
||||
}
|
||||
|
||||
if (*f_pos >= *buffer_used)
|
||||
{
|
||||
count = 0;
|
||||
goto MutexUnlock;
|
||||
}
|
||||
|
||||
if (*f_pos + count > *buffer_used)
|
||||
{
|
||||
count = *buffer_used - *f_pos;
|
||||
}
|
||||
|
||||
if (copy_to_user(buf, buffer + *f_pos, count))
|
||||
{
|
||||
count = -EFAULT;
|
||||
goto MutexUnlock;
|
||||
}
|
||||
|
||||
*f_pos += count;
|
||||
|
||||
MutexUnlock:
|
||||
if (nnt_device)
|
||||
{
|
||||
mutex_unlock_nnt(file);
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t mst_pci_bc_write(struct file* file, const char* buf, size_t count, loff_t* f_pos)
|
||||
{
|
||||
struct mst_device_data* mst_device = NULL;
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
int* buffer_used = NULL;
|
||||
char* buffer = NULL;
|
||||
int minor = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
minor = iminor(file_inode(file));
|
||||
mst_device = &mst_devices[minor];
|
||||
buffer = mst_device->buffer;
|
||||
buffer_used = &mst_device->buffer_used;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = nnt_device->buffer_bc;
|
||||
buffer_used = &nnt_device->buffer_used_bc;
|
||||
error = mutex_lock_nnt(file);
|
||||
CHECK_ERROR(error);
|
||||
}
|
||||
|
||||
if (*f_pos >= MST_BC_BUFFER_SIZE)
|
||||
{
|
||||
count = 0;
|
||||
goto MutexUnlock;
|
||||
}
|
||||
|
||||
if (*f_pos + count > MST_BC_BUFFER_SIZE)
|
||||
{
|
||||
count = MST_BC_BUFFER_SIZE - *f_pos;
|
||||
}
|
||||
|
||||
if (copy_from_user(buffer + *f_pos, buf, count))
|
||||
{
|
||||
count = -EFAULT;
|
||||
goto MutexUnlock;
|
||||
}
|
||||
|
||||
*f_pos += count;
|
||||
|
||||
if (*buffer_used < *f_pos)
|
||||
{
|
||||
*buffer_used = *f_pos;
|
||||
}
|
||||
|
||||
MutexUnlock:
|
||||
if (nnt_device)
|
||||
{
|
||||
mutex_unlock_nnt(file);
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline int noncached_address(unsigned long addr)
|
||||
{
|
||||
return addr >= __pa(high_memory);
|
||||
}
|
||||
|
||||
static int mst_pci_mmap(struct file* file, struct vm_area_struct* vma)
|
||||
{
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
unsigned long long offset = 0;
|
||||
unsigned long vsize = 0;
|
||||
unsigned long off = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
off = vma->vm_pgoff << PAGE_SHIFT;
|
||||
vsize = vma->vm_end - vma->vm_start;
|
||||
|
||||
if ((nnt_device->device_pci.bar_size <= off) || (nnt_device->device_pci.bar_size < off + vsize))
|
||||
{
|
||||
error = -EINVAL;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
offset = nnt_device->device_pci.bar_address + off;
|
||||
|
||||
/* Accessing memory above the top the kernel knows about or through
|
||||
a file pointer that was marked O_SYNC will be done non-cached. */
|
||||
if (noncached_address(offset) || (file->f_flags & O_SYNC))
|
||||
{
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
}
|
||||
|
||||
error = io_remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, vsize, vma->vm_page_prot);
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
static long ioctl(struct file* file, unsigned int command, unsigned long argument)
|
||||
{
|
||||
void* user_buffer = (void*)argument;
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
int error = 0;
|
||||
|
||||
/* By convention, any user gets read access
|
||||
* and is allowed to use the device.
|
||||
* Commands with no direction are administration
|
||||
* commands, and you need write permission
|
||||
* for this */
|
||||
|
||||
if (_IOC_DIR(command) == _IOC_NONE)
|
||||
{
|
||||
if (!(file->f_mode & FMODE_WRITE))
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(file->f_mode & FMODE_READ))
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
if (command != INIT)
|
||||
{
|
||||
error = mutex_lock_nnt(file);
|
||||
if (error)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
error = 0;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case INIT:
|
||||
{
|
||||
struct mst_pci_init_st mst_init;
|
||||
struct pci_bus* bus = NULL;
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&mst_init, user_buffer, sizeof(struct mst_pci_init_st)))
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
error = set_private_data_bc(file, mst_init.bus, mst_init.devfn, mst_init.domain);
|
||||
if (error)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
error = mutex_lock_nnt(file);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
bus = pci_find_bus(mst_init.domain, mst_init.bus);
|
||||
|
||||
if (!bus)
|
||||
{
|
||||
printk(KERN_ERR "unable to find pci bus for domain: %x and bus: %x\n", mst_init.domain, mst_init.bus);
|
||||
error = -ENXIO;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
nnt_device->pci_device = NULL;
|
||||
nnt_device->pci_device = pci_get_slot(bus, mst_init.devfn);
|
||||
|
||||
if (!nnt_device->pci_device)
|
||||
{
|
||||
printk(KERN_ERR "missing pci device");
|
||||
error = -ENXIO;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
if (mst_init.bar >= DEVICE_COUNT_RESOURCE)
|
||||
{
|
||||
printk(KERN_ERR "bar offset is too large");
|
||||
error = -ENXIO;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
nnt_device->device_pci.bar_address = nnt_device->pci_device->resource[mst_init.bar].start;
|
||||
nnt_device->device_pci.bar_size = nnt_device->pci_device->resource[mst_init.bar].end + 1 -
|
||||
nnt_device->pci_device->resource[mst_init.bar].start;
|
||||
|
||||
if (nnt_device->device_pci.bar_size == 1)
|
||||
{
|
||||
nnt_device->device_pci.bar_size = 0;
|
||||
}
|
||||
|
||||
nnt_device->buffer_used_bc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PCI_PARAMS_:
|
||||
{
|
||||
struct mst_pci_params_st params;
|
||||
params.bar = nnt_device->device_pci.bar_address;
|
||||
params.size = nnt_device->device_pci.bar_size;
|
||||
|
||||
if (copy_to_user(user_buffer, ¶ms, sizeof(struct mst_pci_params_st)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CONNECTX_WA:
|
||||
{
|
||||
struct nnt_connectx_wa connectx_wa;
|
||||
error = pci_connectx_wa(&connectx_wa, nnt_device);
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &connectx_wa, sizeof(struct nnt_connectx_wa)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case STOP:
|
||||
error = destroy_nnt_device_bc(nnt_device);
|
||||
break;
|
||||
default:
|
||||
error = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
mutex_unlock_nnt(file);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int mst_release(struct inode* inode, struct file* file)
|
||||
{
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
int error = 0;
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
error = 0;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
if (nnt_device->memory_device.connectx_wa_slot_p1)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
|
||||
error = mutex_lock_nnt(file);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
mask = ~(1 << (nnt_device->memory_device.connectx_wa_slot_p1 - 1));
|
||||
|
||||
nnt_device->memory_device.connectx_wa_slot_p1 &= mask; // Fix me
|
||||
|
||||
nnt_device->memory_device.connectx_wa_slot_p1 = 0;
|
||||
mutex_unlock_nnt(file);
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct file_operations fop = {.unlocked_ioctl = ioctl,
|
||||
.open = mst_pci_bc_open,
|
||||
.write = mst_pci_bc_write,
|
||||
.read = mst_pci_bc_read,
|
||||
.mmap = mst_pci_mmap,
|
||||
.release = mst_release,
|
||||
.owner = THIS_MODULE};
|
||||
|
||||
int with_unknown = 0;
|
||||
|
||||
module_param(with_unknown, int, S_IRUSR | S_IWUSR);
|
||||
|
||||
static int __init mst_pci_init_module(void)
|
||||
{
|
||||
dev_t device_number = -1;
|
||||
int is_alloc_chrdev_region = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Allocate char driver region and assign major number */
|
||||
major_number = register_chrdev(0, name, &fop);
|
||||
if (major_number <= 0)
|
||||
{
|
||||
printk(KERN_ERR "Unable to register character mst pci driver.\n");
|
||||
error = -EINVAL;
|
||||
}
|
||||
|
||||
/* Create device files for MFT. */
|
||||
error = create_nnt_devices(device_number, is_alloc_chrdev_region, &fop, NNT_PCI_DEVICES, NNT_MELLANOX_PCI_VENDOR,
|
||||
with_unknown) ||
|
||||
create_nnt_devices(device_number, is_alloc_chrdev_region, &fop, NNT_PCI_DEVICES, NNT_NVIDIA_PCI_VENDOR,
|
||||
with_unknown);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void __exit mst_pci_cleanup_module(void)
|
||||
{
|
||||
int is_alloc_chrdev_region = 0;
|
||||
|
||||
destroy_nnt_devices(is_alloc_chrdev_region);
|
||||
unregister_chrdev(major_number, name);
|
||||
}
|
||||
|
||||
module_init(mst_pci_init_module);
|
||||
module_exit(mst_pci_cleanup_module);
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef MST_PCI_H
|
||||
#define MST_PCI_H
|
||||
|
||||
/* These will be specific for PCI */
|
||||
#define PCI_MAGIC 0xD1
|
||||
|
||||
#define PCI_INIT _IOC(_IOC_NONE,PCI_MAGIC,0,sizeof(struct mst_pci_init_st))
|
||||
struct mst_pci_init_st {
|
||||
unsigned int domain;
|
||||
unsigned int bus;
|
||||
unsigned int devfn;
|
||||
int bar;
|
||||
};
|
||||
|
||||
#define PCI_STOP _IOC(_IOC_NONE,PCI_MAGIC,1,0)
|
||||
|
||||
#define PCI_PARAMS _IOR(PCI_MAGIC,2, struct mst_pci_params_st)
|
||||
|
||||
struct mst_pci_params_st {
|
||||
unsigned long long __attribute__((packed)) bar;
|
||||
unsigned long long __attribute__((packed)) size;
|
||||
};
|
||||
|
||||
|
||||
#define CONNECTX_WA_BASE 0xf0384 // SEM BASE ADDR. SEM 0xf0380 is reserved for external tools usage.
|
||||
#define CONNECTX_WA_SIZE 3 // Size in entries
|
||||
|
||||
#define PCI_CONNECTX_WA _IOR(PCI_MAGIC,3, u_int32_t)
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
KPVER ?= $(shell uname -r)
|
||||
KSRC ?= /lib/modules/$(KPVER)/build
|
||||
|
||||
# Oracle Linux OS.
|
||||
ifneq ($(shell if (echo $(KPVER) | grep -qE 'uek'); then \
|
||||
echo "YES"; else echo ""; fi),)
|
||||
override WITH_MAKE_PARAMS += ctf-dir=$(CWD)/.ctf
|
||||
endif
|
||||
|
||||
NNT_DRIVER_LOCATION = ../../nnt_driver
|
||||
PACKAGE_NAME = nnt-driver
|
||||
PACKAGE_VERSION = 1.0.0
|
||||
PACKAGE_RC = 1
|
||||
|
||||
%: %.in
|
||||
sed \
|
||||
-e 's/@PACKAGE_NAME@/$(PACKAGE_NAME)/g' \
|
||||
-e 's/@PACKAGE_VERSION@/$(PACKAGE_VERSION)/g' \
|
||||
-e 's/@PACKAGE_RC@/$(PACKAGE_RC)/g' \
|
||||
<$< >$@
|
||||
|
||||
obj-m += mst_pciconf.o
|
||||
EXTRA_CFLAGS= -I$(PWD)/$(NNT_DRIVER_LOCATION)
|
||||
mst_pciconf-objs += $(NNT_DRIVER_LOCATION)/nnt_device.o $(NNT_DRIVER_LOCATION)/nnt_dma.o $(NNT_DRIVER_LOCATION)/nnt_pci_conf_access.o \
|
||||
$(NNT_DRIVER_LOCATION)/nnt_pci_conf_access_no_vsec.o $(NNT_DRIVER_LOCATION)/nnt_memory_access.o \
|
||||
$(NNT_DRIVER_LOCATION)/nnt_ioctl.o mst_pciconf_bc.o
|
||||
|
||||
all:
|
||||
make -C $(KSRC) M=$(PWD) CONFIG_CTF= CONFIG_CC_STACKPROTECTOR_STRONG= $(WITH_MAKE_PARAMS) modules
|
||||
|
||||
clean:
|
||||
make -C $(KSRC) M=$(PWD) clean
|
||||
@@ -0,0 +1,3 @@
|
||||
mst_pciconf.ko external
|
||||
mst_pci.ko external
|
||||
mst_ppc_pci_reset.ko external
|
||||
@@ -0,0 +1,635 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "nnt_ioctl.h"
|
||||
#include "nnt_defs.h"
|
||||
#include "nnt_device.h"
|
||||
#include "nnt_ioctl_defs.h"
|
||||
#include "nnt_pci_conf_access.h"
|
||||
#include "mst_pciconf_bc.h"
|
||||
|
||||
MODULE_AUTHOR("Itay Avraham <itayavr@nvidia.com>");
|
||||
MODULE_DESCRIPTION("NNT Linux driver (NVIDIA® networking tools driver), this is the backward compatibility driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
struct driver_info nnt_driver_info;
|
||||
static int major_number = -1;
|
||||
static char* name = "mst_pciconf";
|
||||
|
||||
#define INIT PCICONF_INIT
|
||||
#define STOP PCICONF_STOP
|
||||
#define READ4 PCICONF_READ4
|
||||
#define READ4_NEW PCICONF_READ4_NEW
|
||||
#define WRITE4 PCICONF_WRITE4
|
||||
#define WRITE4_NEW PCICONF_WRITE4_NEW
|
||||
#define MODIFY PCICONF_MODIFY
|
||||
#define READ4_BUFFER PCICONF_READ4_BUFFER
|
||||
#define READ4_BUFFER_EX PCICONF_READ4_BUFFER_EX
|
||||
#define WRITE4_BUFFER PCICONF_WRITE4_BUFFER
|
||||
#define MST_PARAMS PCICONF_MST_PARAMS
|
||||
#define MST_META_DATA PCICONF_MST_META_DATA
|
||||
#define GET_DMA_PAGES PCICONF_GET_DMA_PAGES
|
||||
#define RELEASE_DMA_PAGES PCICONF_RELEASE_DMA_PAGES
|
||||
#define READ_DWORD_FROM_CONFIG_SPACE PCICONF_READ_DWORD_FROM_CONFIG_SPACE
|
||||
|
||||
static int mst_pciconf_bc_open(struct inode* inode, struct file* file)
|
||||
{
|
||||
if (file->private_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
set_private_data_open(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t mst_pciconf_bc_read(struct file* file, char* buf, size_t count, loff_t* f_pos)
|
||||
{
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
int error = 0;
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
count = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
error = mutex_lock_nnt(file);
|
||||
|
||||
if (*f_pos >= nnt_device->buffer_used_bc)
|
||||
{
|
||||
count = 0;
|
||||
goto MutexUnlock;
|
||||
}
|
||||
|
||||
if (*f_pos + count > nnt_device->buffer_used_bc)
|
||||
{
|
||||
count = nnt_device->buffer_used_bc - *f_pos;
|
||||
}
|
||||
|
||||
if (copy_to_user(buf, nnt_device->buffer_bc + *f_pos, count))
|
||||
{
|
||||
count = -EFAULT;
|
||||
goto MutexUnlock;
|
||||
}
|
||||
|
||||
*f_pos += count;
|
||||
|
||||
MutexUnlock:
|
||||
mutex_unlock_nnt(file);
|
||||
ReturnOnFinished:
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t mst_pciconf_bc_write(struct file* file, const char* buf, size_t count, loff_t* f_pos)
|
||||
{
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
int error = 0;
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
count = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
error = mutex_lock_nnt(file);
|
||||
|
||||
if (*f_pos >= MST_BC_BUFFER_SIZE)
|
||||
{
|
||||
count = 0;
|
||||
goto MutexUnlock;
|
||||
}
|
||||
|
||||
if (*f_pos + count > MST_BC_BUFFER_SIZE)
|
||||
{
|
||||
count = MST_BC_BUFFER_SIZE - *f_pos;
|
||||
}
|
||||
|
||||
if (copy_from_user(nnt_device->buffer_bc + *f_pos, buf, count))
|
||||
{
|
||||
count = -EFAULT;
|
||||
goto MutexUnlock;
|
||||
}
|
||||
|
||||
*f_pos += count;
|
||||
|
||||
if (nnt_device->buffer_used_bc < *f_pos)
|
||||
{
|
||||
nnt_device->buffer_used_bc = *f_pos;
|
||||
}
|
||||
|
||||
MutexUnlock:
|
||||
mutex_unlock_nnt(file);
|
||||
ReturnOnFinished:
|
||||
return count;
|
||||
}
|
||||
|
||||
static long ioctl(struct file* file, unsigned int command, unsigned long argument)
|
||||
{
|
||||
void* user_buffer = (void*)argument;
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
int error = 0;
|
||||
|
||||
/* By convention, any user gets read access
|
||||
* and is allowed to use the device.
|
||||
* Commands with no direction are administration
|
||||
* commands, and you need write permission
|
||||
* for this */
|
||||
|
||||
if (_IOC_DIR(command) == _IOC_NONE)
|
||||
{
|
||||
if (!(file->f_mode & FMODE_WRITE))
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(file->f_mode & FMODE_READ))
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
if (command != INIT)
|
||||
{
|
||||
error = mutex_lock_nnt(file);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case INIT:
|
||||
{
|
||||
struct nnt_pciconf_init nnt_init;
|
||||
struct mst_pciconf_init_st mst_init;
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
|
||||
if (copy_from_user(&mst_init, user_buffer, sizeof(struct mst_pciconf_init_st)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
error = set_private_data_bc(file, mst_init.bus, mst_init.devfn, mst_init.domain);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
error = mutex_lock_nnt(file);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Get the nnt device structure */
|
||||
error = get_nnt_device(file, &nnt_device);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
nnt_init.address_register = mst_init.addr_reg;
|
||||
nnt_init.address_data_register = mst_init.data_reg;
|
||||
|
||||
/* Truncate to 0 length on open for writing. */
|
||||
if (file->f_flags & O_APPEND)
|
||||
{
|
||||
file->f_pos = nnt_device->buffer_used_bc;
|
||||
}
|
||||
else if ((file->f_flags & O_TRUNC) || (file->f_flags & O_WRONLY))
|
||||
{
|
||||
nnt_device->buffer_used_bc = 0;
|
||||
}
|
||||
|
||||
error = nnt_device->access.init(nnt_device);
|
||||
break;
|
||||
}
|
||||
case WRITE4:
|
||||
{
|
||||
struct nnt_rw_operation rw_operation;
|
||||
struct mst_write4_st mst_write;
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&mst_write, user_buffer, sizeof(struct mst_write4_st)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
rw_operation.data[0] = mst_write.data;
|
||||
rw_operation.offset = mst_write.offset;
|
||||
rw_operation.size = 4;
|
||||
|
||||
error = nnt_device->access.write(nnt_device, &rw_operation);
|
||||
|
||||
break;
|
||||
}
|
||||
case WRITE4_NEW:
|
||||
{
|
||||
struct nnt_rw_operation rw_operation;
|
||||
struct mst_write4_new_st mst_write;
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&mst_write, user_buffer, sizeof(struct mst_write4_new_st)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
rw_operation.data[0] = mst_write.data;
|
||||
rw_operation.offset = mst_write.offset;
|
||||
rw_operation.address_space = mst_write.address_space;
|
||||
rw_operation.size = 4;
|
||||
|
||||
error = nnt_device->access.write(nnt_device, &rw_operation);
|
||||
|
||||
break;
|
||||
}
|
||||
case WRITE4_BUFFER:
|
||||
{
|
||||
struct mst_write4_buffer_st mst_write;
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&mst_write, user_buffer, sizeof(struct mst_write4_buffer_st)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
error = nnt_device->access.write(nnt_device, (struct nnt_rw_operation*)&mst_write);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* No error, return the requested data length. */
|
||||
error = mst_write.size;
|
||||
|
||||
break;
|
||||
}
|
||||
case READ4:
|
||||
{
|
||||
struct nnt_rw_operation rw_operation;
|
||||
struct mst_read4_st mst_read;
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&mst_read, user_buffer, sizeof(struct mst_read4_st)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
rw_operation.offset = mst_read.offset;
|
||||
rw_operation.size = 4;
|
||||
|
||||
error = nnt_device->access.read(nnt_device, &rw_operation);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
mst_read.data = rw_operation.data[0];
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &mst_read, sizeof(struct mst_read4_st)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case READ4_NEW:
|
||||
{
|
||||
struct nnt_rw_operation rw_operation;
|
||||
struct mst_read4_new_st mst_read;
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&mst_read, user_buffer, sizeof(struct mst_read4_new_st)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
rw_operation.offset = mst_read.offset;
|
||||
rw_operation.address_space = mst_read.address_space;
|
||||
rw_operation.size = 4;
|
||||
error = nnt_device->access.read(nnt_device, &rw_operation);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
mst_read.data = rw_operation.data[0];
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &mst_read, sizeof(struct mst_read4_new_st)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case READ4_BUFFER_EX:
|
||||
case READ4_BUFFER:
|
||||
{
|
||||
struct mst_read4_buffer_st mst_read;
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&mst_read, user_buffer, sizeof(struct mst_read4_buffer_st)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
error = nnt_device->access.read(nnt_device, (struct nnt_rw_operation*)&mst_read);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &mst_read, sizeof(struct mst_read4_buffer_st)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* No error, return the requested data length. */
|
||||
error = mst_read.size;
|
||||
|
||||
break;
|
||||
}
|
||||
case PCICONF_VPD_READ4:
|
||||
{
|
||||
int vpd_default_timeout = 2000;
|
||||
struct mst_vpd_read4_st mst_vpd_read;
|
||||
struct nnt_vpd nnt_vpd;
|
||||
|
||||
if (!nnt_device->vpd_capability_address)
|
||||
{
|
||||
printk(KERN_ERR "Device %s not support Vital Product Data\n", nnt_device->device_name);
|
||||
error = -ENODEV;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&mst_vpd_read, user_buffer, sizeof(struct mst_vpd_read4_st)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
nnt_vpd.offset = mst_vpd_read.offset;
|
||||
nnt_vpd.data = mst_vpd_read.data;
|
||||
|
||||
if (!nnt_vpd.timeout)
|
||||
{
|
||||
nnt_vpd.timeout = vpd_default_timeout;
|
||||
}
|
||||
|
||||
error = vpd_read(&nnt_vpd, nnt_device);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
mst_vpd_read.offset = nnt_vpd.offset;
|
||||
mst_vpd_read.data = nnt_vpd.data;
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &mst_vpd_read, sizeof(struct mst_vpd_read4_st)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PCICONF_VPD_WRITE4:
|
||||
{
|
||||
int vpd_default_timeout = 2000;
|
||||
struct mst_vpd_write4_st mst_vpd_write;
|
||||
struct nnt_vpd nnt_vpd;
|
||||
|
||||
if (!nnt_device->vpd_capability_address)
|
||||
{
|
||||
printk(KERN_ERR "Device %s not support Vital Product Data\n", nnt_device->device_name);
|
||||
error = -ENODEV;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&mst_vpd_write, user_buffer, sizeof(struct mst_vpd_write4_st)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
nnt_vpd.offset = mst_vpd_write.offset;
|
||||
nnt_vpd.data = mst_vpd_write.data;
|
||||
|
||||
if (!nnt_vpd.timeout)
|
||||
{
|
||||
nnt_vpd.timeout = vpd_default_timeout;
|
||||
}
|
||||
|
||||
error = vpd_write(&nnt_vpd, nnt_device);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
mst_vpd_write.offset = nnt_vpd.offset;
|
||||
mst_vpd_write.data = nnt_vpd.data;
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &mst_vpd_write, sizeof(struct mst_vpd_write4_st)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GET_DMA_PAGES:
|
||||
{
|
||||
error = dma_pages_ioctl(NNT_GET_DMA_PAGES, user_buffer, nnt_device);
|
||||
break;
|
||||
}
|
||||
case RELEASE_DMA_PAGES:
|
||||
{
|
||||
error = dma_pages_ioctl(NNT_RELEASE_DMA_PAGES, user_buffer, nnt_device);
|
||||
break;
|
||||
}
|
||||
case READ_DWORD_FROM_CONFIG_SPACE:
|
||||
{
|
||||
struct nnt_read_dword_from_config_space nnt_read_from_cspace = {0};
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&nnt_read_from_cspace, user_buffer, sizeof(struct nnt_read_dword_from_config_space)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Read the dword. */
|
||||
if (read_dword(&nnt_read_from_cspace, nnt_device))
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &nnt_read_from_cspace, sizeof(struct nnt_read_dword_from_config_space)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MST_META_DATA:
|
||||
{
|
||||
struct mst_meta_data meta_data;
|
||||
struct mst_hdr hdr;
|
||||
memset(&meta_data, 0, sizeof(meta_data));
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&hdr, user_buffer, sizeof(struct mst_hdr)))
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
if (hdr.payload_version_major != MST_META_DATA_VERSION_MAJOR || hdr.payload_len < sizeof(meta_data.data))
|
||||
{
|
||||
error = -EINVAL;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
// fill meta_data hdr
|
||||
meta_data.hdr.hdr_version = MST_HDR_VERSION;
|
||||
meta_data.hdr.hdr_len = sizeof(meta_data.hdr);
|
||||
meta_data.hdr.payload_len = sizeof(meta_data.data);
|
||||
meta_data.hdr.payload_version_major = MST_META_DATA_VERSION_MAJOR;
|
||||
meta_data.hdr.payload_version_minor = MST_META_DATA_VERSION_MINOR;
|
||||
// fill payload
|
||||
meta_data.data.api_version_major = MST_API_VERSION_MAJOR;
|
||||
meta_data.data.api_version_minor = MST_API_VERSION_MINOR;
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &meta_data, sizeof(meta_data)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MST_PARAMS:
|
||||
{
|
||||
struct nnt_device_parameters nnt_parameters;
|
||||
struct mst_params_st mst_params;
|
||||
|
||||
error = get_nnt_device_parameters(&nnt_parameters, nnt_device);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
mst_params.bus = nnt_parameters.bus;
|
||||
mst_params.bar = 0;
|
||||
mst_params.domain = nnt_parameters.domain;
|
||||
mst_params.func = nnt_parameters.function;
|
||||
mst_params.slot = nnt_parameters.slot;
|
||||
mst_params.device = nnt_parameters.device;
|
||||
mst_params.vendor = nnt_parameters.vendor;
|
||||
mst_params.subsystem_device = nnt_parameters.subsystem_device;
|
||||
mst_params.subsystem_vendor = nnt_parameters.subsystem_vendor;
|
||||
mst_params.vendor_specific_cap = nnt_parameters.vendor_specific_capability;
|
||||
mst_params.multifunction = nnt_parameters.multifunction;
|
||||
mst_params.vsec_cap_mask = nnt_parameters.vsec_capability_mask;
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &mst_params, sizeof(struct mst_params_st)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case STOP:
|
||||
{
|
||||
error = destroy_nnt_device_bc(nnt_device);
|
||||
break;
|
||||
}
|
||||
case PCICONF_DMA_PROPS:
|
||||
case PCICONF_MEM_ACCESS:
|
||||
case MODIFY:
|
||||
break;
|
||||
default:
|
||||
error = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
mutex_unlock_nnt(file);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
struct file_operations fop = {.unlocked_ioctl = ioctl,
|
||||
.open = mst_pciconf_bc_open,
|
||||
.write = mst_pciconf_bc_write,
|
||||
.read = mst_pciconf_bc_read,
|
||||
.owner = THIS_MODULE};
|
||||
|
||||
int with_unknown = 0;
|
||||
|
||||
module_param(with_unknown, int, S_IRUSR | S_IWUSR);
|
||||
|
||||
static int __init mst_pciconf_init_module(void)
|
||||
{
|
||||
dev_t device_number = -1;
|
||||
int is_alloc_chrdev_region = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Allocate char driver region and assign major number */
|
||||
major_number = register_chrdev(0, name, &fop);
|
||||
if (major_number <= 0)
|
||||
{
|
||||
printk(KERN_ERR "Unable to register character mst pciconf driver.\n");
|
||||
error = -EINVAL;
|
||||
}
|
||||
|
||||
/* Create device files for MFT. */
|
||||
error = create_nnt_devices(device_number, is_alloc_chrdev_region, &fop, NNT_PCICONF_DEVICES,
|
||||
NNT_MELLANOX_PCI_VENDOR, with_unknown) ||
|
||||
create_nnt_devices(device_number, is_alloc_chrdev_region, &fop, NNT_PCI_DEVICES, NNT_NVIDIA_PCI_VENDOR,
|
||||
with_unknown);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void __exit mst_pciconf_cleanup_module(void)
|
||||
{
|
||||
int is_alloc_chrdev_region = 0;
|
||||
|
||||
destroy_nnt_devices(is_alloc_chrdev_region);
|
||||
unregister_chrdev(major_number, name);
|
||||
}
|
||||
|
||||
module_init(mst_pciconf_init_module);
|
||||
module_exit(mst_pciconf_cleanup_module);
|
||||
@@ -0,0 +1,193 @@
|
||||
#ifndef MST_PCICONF_H
|
||||
#define MST_PCICONF_H
|
||||
|
||||
|
||||
/* These will be specific for PCI CONF*/
|
||||
#define PCICONF_MAGIC 0xD2
|
||||
#define PCICONF_MAX_BUFFER_SIZE 256
|
||||
#define PCICONF_MAX_MEMACCESS_SIZE 1024
|
||||
#define PCICONF_MAX_PAGES_SIZE 8
|
||||
#define PCICONF_CAP_VEC_LEN 16
|
||||
|
||||
/* Versions */
|
||||
#define MST_HDR_VERSION 1
|
||||
#define MST_META_DATA_VERSION_MAJOR 1
|
||||
#define MST_META_DATA_VERSION_MINOR 0
|
||||
#define MST_API_VERSION_MAJOR 1
|
||||
#define MST_API_VERSION_MINOR 0
|
||||
|
||||
/* Common Structs*/
|
||||
struct mst_hdr {
|
||||
unsigned short hdr_version;
|
||||
unsigned short hdr_len;
|
||||
unsigned short payload_version_major;
|
||||
unsigned int payload_version_minor;
|
||||
unsigned int payload_len;
|
||||
};
|
||||
|
||||
|
||||
#define PCICONF_INIT _IOC(_IOC_NONE,PCICONF_MAGIC,0,sizeof(struct mst_pciconf_init_st))
|
||||
struct mst_pciconf_init_st {
|
||||
unsigned int domain;
|
||||
unsigned int bus;
|
||||
unsigned int devfn;
|
||||
/* Byte offsets in configuration space */
|
||||
unsigned int addr_reg;
|
||||
unsigned int data_reg;
|
||||
};
|
||||
|
||||
#define PCICONF_STOP _IOC (_IOC_NONE,PCICONF_MAGIC,1,0)
|
||||
|
||||
#define PCICONF_READ4 _IOR (PCICONF_MAGIC,1,struct mst_read4_st)
|
||||
struct mst_read4_st {
|
||||
unsigned int offset;
|
||||
unsigned int data; /*OUT*/
|
||||
};
|
||||
|
||||
#define PCICONF_WRITE4 _IOW (PCICONF_MAGIC,2,struct mst_write4_st)
|
||||
struct mst_write4_st {
|
||||
unsigned int offset;
|
||||
unsigned int data;
|
||||
};
|
||||
|
||||
|
||||
#define PCICONF_MODIFY _IOWR(PCICONF_MAGIC,3,struct mst_modify_st)
|
||||
struct mst_modify_st {
|
||||
unsigned int address_space;
|
||||
unsigned int offset;
|
||||
unsigned int data;
|
||||
unsigned int mask;
|
||||
unsigned int old_data; /*OUT*/
|
||||
};
|
||||
|
||||
#define PCICONF_READ4_BUFFER _IOR (PCICONF_MAGIC,4,struct mst_read4_st)
|
||||
#define PCICONF_READ4_BUFFER_EX _IOR (PCICONF_MAGIC,4,struct mst_read4_buffer_st)
|
||||
struct mst_read4_buffer_st {
|
||||
unsigned int address_space;
|
||||
unsigned int offset;
|
||||
int size;
|
||||
unsigned int data[PCICONF_MAX_BUFFER_SIZE/4]; /*OUT*/
|
||||
};
|
||||
|
||||
#define PCICONF_WRITE4_BUFFER _IOW (PCICONF_MAGIC,5,struct mst_write4_buffer_st)
|
||||
struct mst_write4_buffer_st {
|
||||
unsigned int address_space;
|
||||
unsigned int offset;
|
||||
int size;
|
||||
unsigned int data[PCICONF_MAX_BUFFER_SIZE/4]; /*IN*/
|
||||
};
|
||||
|
||||
#define PCICONF_MST_PARAMS _IOR (PCICONF_MAGIC,6,struct mst_params_st)
|
||||
struct mst_params_st {
|
||||
unsigned int domain;
|
||||
unsigned int bus;
|
||||
unsigned int slot;
|
||||
unsigned int func;
|
||||
unsigned int bar;
|
||||
unsigned int device;
|
||||
unsigned int vendor;
|
||||
unsigned int subsystem_device;
|
||||
unsigned int subsystem_vendor;
|
||||
unsigned int vendor_specific_cap;
|
||||
u_int32_t vsec_cap_mask;
|
||||
unsigned int multifunction;
|
||||
};
|
||||
|
||||
#define PCICONF_READ4_NEW _IOR (PCICONF_MAGIC,7,struct mst_read4_new_st)
|
||||
struct mst_read4_new_st {
|
||||
unsigned int address_space;
|
||||
unsigned int offset;
|
||||
unsigned int data; /*OUT*/
|
||||
};
|
||||
|
||||
/****************************************************/
|
||||
/* VPD ACCESS */
|
||||
#define PCICONF_VPD_READ4 _IOR(PCICONF_MAGIC, 7, struct mst_vpd_read4_st)
|
||||
struct mst_vpd_read4_st {
|
||||
unsigned int offset; /* IN - must be aligned to DWORD */
|
||||
unsigned int data; /* OUT */
|
||||
|
||||
};
|
||||
|
||||
#define PCICONF_WRITE4_NEW _IOW (PCICONF_MAGIC,8,struct mst_write4_new_st)
|
||||
struct mst_write4_new_st {
|
||||
unsigned int address_space;
|
||||
unsigned int offset;
|
||||
unsigned int data;
|
||||
};
|
||||
|
||||
|
||||
#define PCICONF_VPD_WRITE4 _IOW(PCICONF_MAGIC, 8, struct mst_vpd_write4_st)
|
||||
struct mst_vpd_write4_st {
|
||||
unsigned int offset; /* IN - must be aligned to DWORD */
|
||||
unsigned int data; /* IN */
|
||||
};
|
||||
|
||||
/*
|
||||
* MEM_ACCESS
|
||||
*/
|
||||
|
||||
|
||||
typedef enum {
|
||||
MST_DMA_ICMD,
|
||||
MST_DMA_END=32
|
||||
} mst_dma_type_t;
|
||||
|
||||
|
||||
#define PCICONF_MEM_ACCESS _IOWR(PCICONF_MAGIC, 10, struct mst_mem_access_st)
|
||||
struct mst_mem_access_st {
|
||||
mst_dma_type_t mem_type;
|
||||
unsigned int _rw; /* READ: 0, WRITE: 1 */
|
||||
unsigned int offset;
|
||||
unsigned int size;
|
||||
unsigned char data[PCICONF_MAX_MEMACCESS_SIZE];
|
||||
};
|
||||
|
||||
#define PCICONF_DMA_PROPS _IOR (PCICONF_MAGIC, 11, struct mst_dma_props_st)
|
||||
|
||||
struct dma_prop {
|
||||
unsigned long long int dma_pa;
|
||||
unsigned int mem_size;
|
||||
};
|
||||
struct mst_dma_props_st {
|
||||
struct dma_prop dma_props[MST_DMA_END];
|
||||
};
|
||||
|
||||
|
||||
#define PCICONF_MST_META_DATA _IOR (PCICONF_MAGIC, 12, struct mst_meta_data)
|
||||
|
||||
struct mst_meta_data_payload {
|
||||
unsigned short api_version_major;
|
||||
unsigned int api_version_minor;
|
||||
unsigned int cap_vector[PCICONF_CAP_VEC_LEN];
|
||||
};
|
||||
|
||||
struct mst_meta_data {
|
||||
struct mst_hdr hdr;
|
||||
struct mst_meta_data_payload data;
|
||||
};
|
||||
|
||||
|
||||
#define PCICONF_GET_DMA_PAGES _IOR (PCICONF_MAGIC, 13, struct page_info_st)
|
||||
#define PCICONF_RELEASE_DMA_PAGES _IOR (PCICONF_MAGIC, 14, struct page_info_st)
|
||||
|
||||
struct page_address_st {
|
||||
u_int64_t dma_address;
|
||||
u_int64_t virtual_address;
|
||||
};
|
||||
|
||||
|
||||
struct page_info_st {
|
||||
unsigned int page_amount;
|
||||
unsigned long page_pointer_start;
|
||||
struct page_address_st page_address_array[PCICONF_MAX_PAGES_SIZE];
|
||||
};
|
||||
|
||||
|
||||
#define PCICONF_READ_DWORD_FROM_CONFIG_SPACE _IOR (PCICONF_MAGIC, 15, struct read_dword_from_config_space)
|
||||
struct read_dword_from_config_space {
|
||||
unsigned int offset;
|
||||
unsigned int data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
KPVER ?= $(shell uname -r)
|
||||
KSRC ?= /lib/modules/$(KPVER)/build
|
||||
CPU_ARCH ?= $(shell uname -m)
|
||||
|
||||
# Oracle Linux OS.
|
||||
ifneq ($(shell if (echo $(KPVER) | grep -qE 'uek'); then \
|
||||
echo "YES"; else echo ""; fi),)
|
||||
override WITH_MAKE_PARAMS += ctf-dir=$(CWD)/.ctf
|
||||
endif
|
||||
|
||||
NNT_DRIVER_LOCATION = ../../nnt_driver
|
||||
PACKAGE_NAME = nnt-driver
|
||||
PACKAGE_VERSION = 1.0.0
|
||||
PACKAGE_RC = 1
|
||||
|
||||
%: %.in
|
||||
sed \
|
||||
-e 's/@PACKAGE_NAME@/$(PACKAGE_NAME)/g' \
|
||||
-e 's/@PACKAGE_VERSION@/$(PACKAGE_VERSION)/g' \
|
||||
-e 's/@PACKAGE_RC@/$(PACKAGE_RC)/g' \
|
||||
<$< >$@
|
||||
|
||||
ifneq ($(findstring ppc64, $(CPU_ARCH)),)
|
||||
obj-m += mst_ppc_pci_reset.o
|
||||
EXTRA_CFLAGS= -I$(PWD)/$(NNT_DRIVER_LOCATION)
|
||||
endif
|
||||
|
||||
all:
|
||||
make -C $(KSRC) M=$(PWD) CONFIG_CTF= CONFIG_CC_STACKPROTECTOR_STRONG= $(WITH_MAKE_PARAMS) modules
|
||||
|
||||
clean:
|
||||
make -C $(KSRC) M=$(PWD) clean
|
||||
306
drivers/net/ethernet/mft/mst_backward_compatibility/mst_ppc/mst_ppc_pci_reset.c
Executable file
306
drivers/net/ethernet/mft/mst_backward_compatibility/mst_ppc/mst_ppc_pci_reset.c
Executable file
@@ -0,0 +1,306 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/delay.h>
|
||||
#include "nnt_ppc_device_list.h"
|
||||
#include "nnt_ppc_driver_defs.h"
|
||||
#include "nnt_defs.h"
|
||||
|
||||
MODULE_AUTHOR("Itay Avraham <itayavr@nvidia.com>");
|
||||
MODULE_DESCRIPTION("NNT PPC driver (NVIDIA® networking tools driver)");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
||||
|
||||
/* Passing PCI devices (DBDF addresses), separated by comma, for example:
|
||||
* 0000:00:08.0,0000:00:08.1 */
|
||||
char pci_device_list[NNT_DEVICE_LIST_SIZE];
|
||||
|
||||
/* Create the file in sysfs. */
|
||||
module_param_string(pci_dev, pci_device_list, sizeof(pci_device_list), 0444);
|
||||
|
||||
|
||||
struct nnt_ppc_reset_info nnt_ppc_reset;
|
||||
|
||||
|
||||
void restore_pci_configuration_space(void)
|
||||
{
|
||||
struct nnt_ppc_device* nnt_pci_device;
|
||||
|
||||
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||
entry) {
|
||||
/* Restore the saved state of a PCI device. */
|
||||
pci_restore_state(nnt_pci_device->pci_device);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int wait_for_response(void)
|
||||
{
|
||||
unsigned short device_id = NNT_UNKNOWN_DEVICE_ID;
|
||||
struct nnt_ppc_device* nnt_pci_device;
|
||||
int polling_counter = 0;
|
||||
int error = 0;
|
||||
|
||||
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||
entry) {
|
||||
struct pci_dev* pci_device = nnt_pci_device->pci_device;
|
||||
|
||||
/* Device id still unknown ? */
|
||||
while(device_id != pci_device->device) {
|
||||
/* 100ms is the minimum time that prevents error logs on
|
||||
dmesg (device is not ready for PCI configuration cycles). */
|
||||
msleep(NNT_MINIMUM_WAITING_TIME);
|
||||
|
||||
/* Read the device id.
|
||||
Access can fail (if device is not ready) and
|
||||
as a result we might get errors in dmesg. */
|
||||
pci_read_config_word(pci_device, PCI_DEVICE_ID,
|
||||
&device_id);
|
||||
|
||||
/* Polling counter violation. */
|
||||
if (polling_counter > NNT_MAXIMUM_POLLING_NUMBER) {
|
||||
printk(KERN_ERR "%s Polling on device id failed: reached max value of polling failures for device: %s\n",
|
||||
dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev));
|
||||
error = -EINVAL;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
polling_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int set_reset_state(enum pcie_reset_state state)
|
||||
{
|
||||
struct nnt_ppc_device* nnt_pci_device;
|
||||
int error = 0;
|
||||
|
||||
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||
entry) {
|
||||
struct pci_dev* pci_device = nnt_pci_device->pci_device;
|
||||
|
||||
if (PCI_FUNC(pci_device->devfn) == 0) {
|
||||
/* Set reset state for device devce. */
|
||||
printk(KERN_DEBUG "%s Send hot reset to the device: %s\n",dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev));
|
||||
error = pci_set_pcie_reset_state(pci_device, state);
|
||||
if (error) {
|
||||
printk(KERN_ERR "%s Set reset state for device failed for device: %s - error: %d\n",
|
||||
dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev), error);
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int save_pci_configucation_space(void)
|
||||
{
|
||||
struct nnt_ppc_device* nnt_pci_device = NULL;
|
||||
int error = 0;
|
||||
|
||||
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||
entry) {
|
||||
struct pci_dev* pci_device = nnt_pci_device->pci_device;
|
||||
|
||||
/* Initialize device before it's used by a driver. */
|
||||
error = pci_enable_device(pci_device);
|
||||
if (error) {
|
||||
printk(KERN_ERR "%s Reset failed for device: %s - error: %d\n",
|
||||
dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev), error);
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Enables bus-mastering for device device. */
|
||||
pci_set_master(pci_device);
|
||||
|
||||
/* Save the PCI configuration space of a device before sending hot reset. */
|
||||
error = pci_save_state(pci_device);
|
||||
if (error) {
|
||||
printk(KERN_ERR "%s Reset failed for device: %s - error: %d\n",
|
||||
dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev), error);
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int pci_devices_reset(void)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (nnt_ppc_reset.reset_was_done) {
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Save configuration space for all devices. */
|
||||
error = save_pci_configucation_space();
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Disable the link by sending the hot reset. */
|
||||
error = set_reset_state(pcie_hot_reset);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
msleep(jiffies_to_msecs(HZ));
|
||||
|
||||
/* Enable the link by sending the hot reset. */
|
||||
error = set_reset_state(pcie_deassert_reset);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Wait for the device to response to PCI configuration cycles. */
|
||||
error = wait_for_response();
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Restore PCI configuration space for all PCI devices. */
|
||||
restore_pci_configuration_space();
|
||||
|
||||
nnt_ppc_reset.reset_was_done = 1;
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int init_pci_device(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct nnt_ppc_device* nnt_pci_device;
|
||||
|
||||
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||
entry) {
|
||||
if (!strcmp(nnt_pci_device->pci_device_dbdf_name, dev_name(&pdev->dev))) {
|
||||
nnt_pci_device->pci_device = pdev;
|
||||
nnt_ppc_reset.number_of_found_pci_device++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nnt_ppc_reset.number_of_requested_pci_device == nnt_ppc_reset.number_of_found_pci_device) {
|
||||
return pci_devices_reset();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void remove_pci_device(struct pci_dev *pdev)
|
||||
{
|
||||
struct nnt_ppc_device* nnt_pci_device;
|
||||
|
||||
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||
entry) {
|
||||
if (!strcmp(nnt_pci_device->pci_device_dbdf_name, dev_name(&pdev->dev))) {
|
||||
pci_clear_master(pdev);
|
||||
pci_disable_device(pdev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ppc_device_structure_init(struct nnt_ppc_device** nnt_pci_device, unsigned int pci_device_name_length)
|
||||
{
|
||||
/* Allocate nnt device structure. */
|
||||
*nnt_pci_device=
|
||||
kzalloc(sizeof(struct nnt_ppc_device),GFP_KERNEL);
|
||||
|
||||
if (!(*nnt_pci_device)) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* initialize nnt structure. */
|
||||
memset(*nnt_pci_device, 0, sizeof(struct nnt_ppc_device));
|
||||
|
||||
(*nnt_pci_device)->pci_device_dbdf_name =
|
||||
kzalloc(pci_device_name_length,GFP_KERNEL);
|
||||
|
||||
if (!(*nnt_pci_device)->pci_device_dbdf_name) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int parse_pci_devices_string(void)
|
||||
{
|
||||
struct nnt_ppc_device* nnt_pci_device;
|
||||
char buffer[NNT_DEVICE_LIST_SIZE];
|
||||
char* pci_device_dbdf_name = NULL;
|
||||
char* dbdf_list = NULL;
|
||||
int error;
|
||||
|
||||
strncpy(buffer, pci_device_list, NNT_DEVICE_LIST_SIZE);
|
||||
dbdf_list = buffer;
|
||||
|
||||
/* Add the pci device name (DBDF) to the list. */
|
||||
while ((pci_device_dbdf_name = strsep(&dbdf_list, ",")) != NULL) {
|
||||
/* Allocate ppc device info structure. */
|
||||
unsigned int pci_device_name_length = strlen(pci_device_dbdf_name);
|
||||
nnt_pci_device = NULL;
|
||||
|
||||
error = ppc_device_structure_init(&nnt_pci_device, pci_device_name_length);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Copy the device name string. */
|
||||
strncpy(nnt_pci_device->pci_device_dbdf_name, pci_device_dbdf_name,
|
||||
pci_device_name_length);
|
||||
|
||||
/* Create a device entry in the list. */
|
||||
list_add_tail(&nnt_pci_device->entry, &nnt_device_list);
|
||||
nnt_ppc_reset.number_of_requested_pci_device++;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void init_members(void)
|
||||
{
|
||||
memset(&nnt_ppc_reset, 0, sizeof(struct nnt_ppc_reset_info));
|
||||
}
|
||||
|
||||
|
||||
static struct pci_driver nnt_ppc_driver = {
|
||||
.name = "nnt_ppc_driver",
|
||||
.id_table = pciconf_devices,
|
||||
.probe = init_pci_device,
|
||||
.remove = remove_pci_device,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
init_members();
|
||||
|
||||
/* Parse the parameters from the user space. */
|
||||
error = parse_pci_devices_string();
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Register the NNT PPC driver. */
|
||||
return pci_register_driver(&nnt_ppc_driver);
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static void __exit cleanup(void)
|
||||
{
|
||||
/* Unregister the NNT PPC driver. */
|
||||
pci_unregister_driver(&nnt_ppc_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init(init);
|
||||
module_exit(cleanup);
|
||||
Reference in New Issue
Block a user