mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +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
34
drivers/net/ethernet/mft/nnt_driver/Makefile
Normal file
34
drivers/net/ethernet/mft/nnt_driver/Makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
KVERSION ?= $(shell uname -r)
|
||||
CPU_ARCH ?= $(shell uname -m)
|
||||
|
||||
# Oracle Linux OS.
|
||||
ifneq ($(shell if (echo $(KVERSION) | grep -qE 'uek'); then \
|
||||
echo "YES"; else echo ""; fi),)
|
||||
override WITH_MAKE_PARAMS += ctf-dir=$(CWD)/.ctf
|
||||
endif
|
||||
|
||||
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
|
||||
endif
|
||||
|
||||
obj-m += nnt_driver.o
|
||||
nnt_driver-objs += nnt_device.o nnt_dma.o nnt_pci_conf_access.o \
|
||||
nnt_pci_conf_access_no_vsec.o nnt_memory_access.o \
|
||||
nnt_ioctl.o
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(KVERSION)/build M=$(PWD) CONFIG_CTF= CONFIG_CC_STACKPROTECTOR_STRONG= $(WITH_MAKE_PARAMS) modules
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
|
||||
42
drivers/net/ethernet/mft/nnt_driver/nnt_defs.h
Normal file
42
drivers/net/ethernet/mft/nnt_driver/nnt_defs.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef NNT_DEFS_H
|
||||
#define NNT_DEFS_H
|
||||
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
|
||||
/* Passing MFT flag argument */
|
||||
extern int is_mft_package;
|
||||
extern struct driver_info nnt_driver_info;
|
||||
|
||||
#define NNT_DRIVER_NAME "nnt_driver"
|
||||
#define NNT_CLASS_NAME "nnt_class"
|
||||
#define NNT_DEVICE_PREFIX "mt"
|
||||
#define NNT_DRIVER "NNT Driver::"
|
||||
|
||||
#define CHECK_PCI_READ_ERROR(error, address) \
|
||||
if (error) { \
|
||||
printk(KERN_ERR "Failed to read from address: %x\n", address); \
|
||||
goto ReturnOnFinished; \
|
||||
}
|
||||
|
||||
#define CHECK_PCI_WRITE_ERROR(error, address, data) \
|
||||
if (error) { \
|
||||
printk(KERN_ERR "Failed to write to address: %x, data: %x\n", address, data); \
|
||||
goto ReturnOnFinished; \
|
||||
}
|
||||
|
||||
#define CHECK_ERROR(error) \
|
||||
if (error) { \
|
||||
goto ReturnOnFinished; \
|
||||
}
|
||||
|
||||
struct driver_info {
|
||||
dev_t device_number;
|
||||
int contiguous_device_numbers;
|
||||
struct class* class_driver;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
626
drivers/net/ethernet/mft/nnt_driver/nnt_device.c
Normal file
626
drivers/net/ethernet/mft/nnt_driver/nnt_device.c
Normal file
@@ -0,0 +1,626 @@
|
||||
#include "nnt_device.h"
|
||||
#include "nnt_device_defs.h"
|
||||
#include "nnt_defs.h"
|
||||
#include "nnt_pci_conf_access.h"
|
||||
#include "nnt_pci_conf_access_no_vsec.h"
|
||||
#include "nnt_memory_access.h"
|
||||
#include <linux/module.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Device list to check if device is available
|
||||
since it could be removed by hotplug event. */
|
||||
LIST_HEAD(nnt_device_list);
|
||||
|
||||
int get_nnt_device(struct file* file, struct nnt_device** nnt_device)
|
||||
{
|
||||
int error_code = 0;
|
||||
|
||||
if (!file->private_data)
|
||||
{
|
||||
error_code = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*nnt_device = file->private_data;
|
||||
}
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
void set_private_data_open(struct file* file)
|
||||
{
|
||||
struct nnt_device* current_nnt_device = NULL;
|
||||
struct nnt_device* temp_nnt_device = NULL;
|
||||
int minor = iminor(file_inode(file));
|
||||
|
||||
/* Set private data to nnt structure. */
|
||||
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||
{
|
||||
if ((minor == current_nnt_device->device_minor_number) && current_nnt_device->device_enabled)
|
||||
{
|
||||
file->private_data = current_nnt_device;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int set_private_data_bc(struct file* file, unsigned int bus, unsigned int devfn, unsigned int domain)
|
||||
{
|
||||
struct nnt_device* current_nnt_device = NULL;
|
||||
struct nnt_device* temp_nnt_device = NULL;
|
||||
int minor = iminor(file_inode(file));
|
||||
unsigned int current_function;
|
||||
unsigned int current_device;
|
||||
|
||||
/* Set private data to nnt structure. */
|
||||
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||
{
|
||||
struct pci_bus* pci_bus = pci_find_bus(current_nnt_device->dbdf.domain, current_nnt_device->dbdf.bus);
|
||||
if (!pci_bus)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
current_nnt_device->pci_device = pci_get_slot(pci_bus, current_nnt_device->dbdf.devfn);
|
||||
if (!current_nnt_device->pci_device)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
current_function = PCI_FUNC(current_nnt_device->dbdf.devfn);
|
||||
current_device = PCI_SLOT(current_nnt_device->dbdf.devfn);
|
||||
|
||||
if ((current_nnt_device->dbdf.bus == bus) && (current_device == PCI_SLOT(devfn)) &&
|
||||
(current_function == PCI_FUNC(devfn)) && (current_nnt_device->dbdf.domain == domain))
|
||||
{
|
||||
current_nnt_device->device_minor_number = minor;
|
||||
current_nnt_device->device_enabled = true;
|
||||
file->private_data = current_nnt_device;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int set_private_data(struct file* file)
|
||||
{
|
||||
struct nnt_device* current_nnt_device = NULL;
|
||||
struct nnt_device* temp_nnt_device = NULL;
|
||||
int minor = iminor(file_inode(file));
|
||||
|
||||
/* Set private data to nnt structure. */
|
||||
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||
{
|
||||
if (current_nnt_device->device_minor_number == minor)
|
||||
{
|
||||
file->private_data = current_nnt_device;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_ERR "failed to find device with minor=%d\n", minor);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int create_file_name_mstflint(struct pci_dev* pci_device, struct nnt_device* nnt_dev, enum nnt_device_type device_type)
|
||||
{
|
||||
sprintf(nnt_dev->device_name, "%4.4x:%2.2x:%2.2x.%1.1x_%s", pci_domain_nr(pci_device->bus), pci_device->bus->number,
|
||||
PCI_SLOT(pci_device->devfn), PCI_FUNC(pci_device->devfn),
|
||||
(device_type == NNT_PCICONF) ? MSTFLINT_PCICONF_DEVICE_NAME : MSTFLINT_MEMORY_DEVICE_NAME);
|
||||
|
||||
printk(KERN_DEBUG
|
||||
"MSTFlint device name created: id: %d, slot id: %d, device name: /dev/%s domain: 0x%x bus: 0x%x\n",
|
||||
pci_device->device, PCI_FUNC(pci_device->devfn), nnt_dev->device_name, pci_domain_nr(pci_device->bus),
|
||||
pci_device->bus->number);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_file_name_mft(struct pci_dev* pci_device, struct nnt_device* nnt_dev, enum nnt_device_type device_type)
|
||||
{
|
||||
sprintf(nnt_dev->device_name, "mst/mt%d_%s0.%x", pci_device->device,
|
||||
(device_type == NNT_PCICONF) ? MFT_PCICONF_DEVICE_NAME : MFT_MEMORY_DEVICE_NAME,
|
||||
PCI_FUNC(pci_device->devfn));
|
||||
|
||||
printk(KERN_DEBUG "MFT device name created: id: %d, slot id: %d, device name: /dev/%s domain: 0x%x bus: 0x%x\n",
|
||||
pci_device->device, PCI_FUNC(pci_device->devfn), nnt_dev->device_name, pci_domain_nr(pci_device->bus),
|
||||
pci_device->bus->number);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nnt_device_structure_init(struct nnt_device** nnt_device)
|
||||
{
|
||||
/* Allocate nnt device structure. */
|
||||
*nnt_device = kzalloc(sizeof(struct nnt_device), GFP_KERNEL);
|
||||
|
||||
if (!(*nnt_device))
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* initialize nnt structure. */
|
||||
memset(*nnt_device, 0, sizeof(struct nnt_device));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_nnt_device(struct pci_dev* pci_device, enum nnt_device_type device_type, int is_alloc_chrdev_region)
|
||||
{
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
int error_code = 0;
|
||||
|
||||
/* Allocate nnt device info structure. */
|
||||
if ((error_code = nnt_device_structure_init(&nnt_device)) != 0)
|
||||
goto ReturnOnError;
|
||||
|
||||
if (is_alloc_chrdev_region)
|
||||
{
|
||||
/* Build the device file name of MSTFlint. */
|
||||
if ((error_code = create_file_name_mstflint(pci_device, nnt_device, device_type)) != 0)
|
||||
goto ReturnOnError;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Build the device file name of MFT. */
|
||||
if ((error_code = create_file_name_mft(pci_device, nnt_device, device_type)) != 0)
|
||||
goto ReturnOnError;
|
||||
}
|
||||
|
||||
nnt_device->dbdf.bus = pci_device->bus->number;
|
||||
nnt_device->dbdf.devfn = pci_device->devfn;
|
||||
nnt_device->dbdf.domain = pci_domain_nr(pci_device->bus);
|
||||
nnt_device->pci_device = pci_device;
|
||||
nnt_device->device_type = device_type;
|
||||
|
||||
/* Add the nnt device structure to the list. */
|
||||
list_add_tail(&nnt_device->entry, &nnt_device_list);
|
||||
|
||||
return error_code;
|
||||
|
||||
ReturnOnError:
|
||||
if (nnt_device)
|
||||
{
|
||||
kfree(nnt_device);
|
||||
}
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
int check_pci_id_range(unsigned short pci_device_id, unsigned short id_range_start)
|
||||
{
|
||||
return (pci_device_id >= id_range_start) && (pci_device_id <= (id_range_start + 100));
|
||||
}
|
||||
|
||||
int is_connectx(unsigned short pci_device_id)
|
||||
{
|
||||
return check_pci_id_range(pci_device_id, CONNECTX3_PCI_ID);
|
||||
}
|
||||
|
||||
int is_connectx3(unsigned short pci_device_id)
|
||||
{
|
||||
return pci_device_id == CONNECTX3_PCI_ID || pci_device_id == CONNECTX3PRO_PCI_ID;
|
||||
}
|
||||
|
||||
int is_bluefield(unsigned short pci_device_id)
|
||||
{
|
||||
return check_pci_id_range(pci_device_id, BLUEFIELD_PCI_ID) ||
|
||||
check_pci_id_range(pci_device_id, BLUEFIELD_DPU_AUX_PCI_ID);
|
||||
}
|
||||
|
||||
int is_pcie_switch(unsigned short pci_device_id)
|
||||
{
|
||||
return check_pci_id_range(pci_device_id, SCHRODINGER_PCI_ID);
|
||||
}
|
||||
|
||||
int is_quantum(unsigned short pci_device_id)
|
||||
{
|
||||
return check_pci_id_range(pci_device_id, QUANTUM_PCI_ID);
|
||||
}
|
||||
|
||||
int is_spectrum(unsigned short pci_device_id)
|
||||
{
|
||||
return (pci_device_id == SPECTRUM_PCI_ID) || (check_pci_id_range(pci_device_id, SPECTRUM2_PCI_ID));
|
||||
}
|
||||
|
||||
int is_switch_ib(unsigned short pci_device_id)
|
||||
{
|
||||
return pci_device_id == SWITCHIB_PCI_ID || pci_device_id == SWITCHIB2_PCI_ID;
|
||||
}
|
||||
|
||||
int is_bw00(unsigned short pci_device_id)
|
||||
{
|
||||
return check_pci_id_range(pci_device_id, BW00_PCI_ID);
|
||||
}
|
||||
|
||||
int is_bw02(unsigned short pci_device_id)
|
||||
{
|
||||
return check_pci_id_range(pci_device_id, BW02_PCI_ID);
|
||||
}
|
||||
|
||||
int is_livefish_device(unsigned short pci_device_id)
|
||||
{
|
||||
return pci_device_id >= CONNECTX3_LIVEFISH_ID && pci_device_id < CONNECTX3_PCI_ID;
|
||||
}
|
||||
|
||||
int is_nic(unsigned short pci_device_id)
|
||||
{
|
||||
return is_connectx(pci_device_id) || is_bluefield(pci_device_id);
|
||||
}
|
||||
|
||||
int is_switch(unsigned short pci_device_id)
|
||||
{
|
||||
return is_pcie_switch(pci_device_id) || is_quantum(pci_device_id) || is_spectrum(pci_device_id) ||
|
||||
is_switch_ib(pci_device_id) || is_bw00(pci_device_id) || is_bw02(pci_device_id);
|
||||
}
|
||||
|
||||
int is_toolspf(unsigned short pci_device_id)
|
||||
{
|
||||
return is_nic(pci_device_id - 4000) || is_switch(pci_device_id - 4000);
|
||||
}
|
||||
|
||||
int is_pciconf_device(unsigned short pci_device_id)
|
||||
{
|
||||
return is_nic(pci_device_id) || is_toolspf(pci_device_id) || is_livefish_device(pci_device_id) ||
|
||||
is_switch(pci_device_id);
|
||||
}
|
||||
|
||||
int is_pcicr_device(unsigned short pci_device_id)
|
||||
{
|
||||
return (is_switch(pci_device_id) || is_toolspf(pci_device_id) || is_connectx3(pci_device_id)) &&
|
||||
(!is_livefish_device(pci_device_id));
|
||||
}
|
||||
|
||||
int create_device_file(struct nnt_device* current_nnt_device,
|
||||
dev_t device_number,
|
||||
int minor,
|
||||
struct file_operations* fop,
|
||||
int is_alloc_chrdev_region)
|
||||
{
|
||||
struct device* device = NULL;
|
||||
int error = 0;
|
||||
int count = 1;
|
||||
|
||||
/* NNT driver will create the device file
|
||||
once we stop support backward compatibility. */
|
||||
current_nnt_device->device_minor_number = -1;
|
||||
current_nnt_device->device_number = device_number;
|
||||
current_nnt_device->mcdev.owner = THIS_MODULE;
|
||||
|
||||
mutex_init(¤t_nnt_device->lock);
|
||||
|
||||
if (!is_alloc_chrdev_region)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
// Create device with a new minor number.
|
||||
current_nnt_device->device_minor_number = minor;
|
||||
current_nnt_device->device_number = MKDEV(MAJOR(device_number), minor);
|
||||
|
||||
current_nnt_device->device_enabled = true;
|
||||
current_nnt_device->connectx_wa_slot_p1 = 0;
|
||||
|
||||
/* Create device node. */
|
||||
device = device_create(nnt_driver_info.class_driver, NULL, current_nnt_device->device_number, NULL,
|
||||
current_nnt_device->device_name);
|
||||
if (!device)
|
||||
{
|
||||
printk(KERN_ERR "Device creation failed\n");
|
||||
error = -EINVAL;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Init new device. */
|
||||
cdev_init(¤t_nnt_device->mcdev, fop);
|
||||
|
||||
/* Add device to the system. */
|
||||
error = cdev_add(¤t_nnt_device->mcdev, current_nnt_device->device_number, count);
|
||||
if (error)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
int check_if_vsec_supported(struct nnt_device* nnt_device)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
error = nnt_device->access.init(nnt_device);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
if (!nnt_device->pciconf_device.vsec_fully_supported)
|
||||
{
|
||||
nnt_device->device_type = NNT_PCICONF_NO_VSEC;
|
||||
nnt_device->access.read = read_pciconf_no_vsec;
|
||||
nnt_device->access.write = write_pciconf_no_vsec;
|
||||
nnt_device->access.init = init_pciconf_no_vsec;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
int is_mellanox_vendor_type(struct nnt_device* current_nnt_device, unsigned int vsec_address)
|
||||
{
|
||||
u_int8_t vendor_type = 0;
|
||||
int error = 0;
|
||||
/* Read the capability type field */
|
||||
if ((error = pci_read_config_byte(current_nnt_device->pci_device, (vsec_address + PCI_TYPE_OFFSET), &vendor_type)))
|
||||
{
|
||||
printk(KERN_ERR "Reading VSEC type failed with error %d\n", error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vendor_type == MELLANOX_VSEC_TYPE)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int get_mellanox_vsec_address(struct nnt_device* current_nnt_device)
|
||||
{
|
||||
unsigned int vsec_address = 0;
|
||||
|
||||
/* Look for the Mellanox VSEC address. if Mellanox VSEC isn't supported the address should be 0 */
|
||||
vsec_address = pci_find_capability(current_nnt_device->pci_device, VSEC_CAPABILITY_ADDRESS);
|
||||
if (!vsec_address || is_mellanox_vendor_type(current_nnt_device, vsec_address))
|
||||
{
|
||||
return vsec_address;
|
||||
}
|
||||
|
||||
/* if found a non-Mellanox type VSEC, iterate of the next available VSECs*/
|
||||
while (
|
||||
(vsec_address = pci_find_next_capability(current_nnt_device->pci_device, vsec_address, VSEC_CAPABILITY_ADDRESS)))
|
||||
{
|
||||
if (is_mellanox_vendor_type(current_nnt_device, vsec_address))
|
||||
{
|
||||
return vsec_address;
|
||||
}
|
||||
}
|
||||
/* if Mellanox VSEC address was not found, return 0 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_devices(dev_t device_number, struct file_operations* fop, int is_alloc_chrdev_region)
|
||||
{
|
||||
struct nnt_device* current_nnt_device = NULL;
|
||||
struct nnt_device* temp_nnt_device = NULL;
|
||||
int minor = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Create necessary number of the devices. */
|
||||
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||
{
|
||||
/* Create the device file. */
|
||||
if ((error = create_device_file(current_nnt_device, device_number, minor, fop, is_alloc_chrdev_region)) != 0)
|
||||
goto ReturnOnFinished;
|
||||
|
||||
/* Members initialization. */
|
||||
current_nnt_device->pciconf_device.vendor_specific_capability = get_mellanox_vsec_address(current_nnt_device);
|
||||
current_nnt_device->vpd_capability_address =
|
||||
pci_find_capability(current_nnt_device->pci_device, PCI_CAP_ID_VPD);
|
||||
|
||||
if (!current_nnt_device->pciconf_device.vendor_specific_capability)
|
||||
{
|
||||
current_nnt_device->device_type = NNT_PCICONF_NO_VSEC;
|
||||
}
|
||||
|
||||
switch (current_nnt_device->device_type)
|
||||
{
|
||||
case NNT_PCICONF:
|
||||
current_nnt_device->access.read = read_pciconf;
|
||||
current_nnt_device->access.write = write_pciconf;
|
||||
current_nnt_device->access.init = init_pciconf;
|
||||
|
||||
error = check_if_vsec_supported(current_nnt_device);
|
||||
CHECK_ERROR(error);
|
||||
break;
|
||||
|
||||
case NNT_PCICONF_NO_VSEC:
|
||||
current_nnt_device->access.read = read_pciconf_no_vsec;
|
||||
current_nnt_device->access.write = write_pciconf_no_vsec;
|
||||
current_nnt_device->access.init = init_pciconf_no_vsec;
|
||||
break;
|
||||
|
||||
case NNT_PCI_MEMORY:
|
||||
current_nnt_device->access.read = read_memory;
|
||||
current_nnt_device->access.write = write_memory;
|
||||
current_nnt_device->access.init = init_memory;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_alloc_chrdev_region)
|
||||
{
|
||||
error = current_nnt_device->access.init(current_nnt_device);
|
||||
}
|
||||
|
||||
minor++;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
int create_nnt_devices(dev_t device_number,
|
||||
int is_alloc_chrdev_region,
|
||||
struct file_operations* fop,
|
||||
enum nnt_device_type_flag nnt_device_flag,
|
||||
unsigned int vendor_id,
|
||||
int with_unknown)
|
||||
{
|
||||
struct pci_dev* pci_device = NULL;
|
||||
int error_code = 0;
|
||||
|
||||
/* Find all Nvidia PCI devices. */
|
||||
while ((pci_device = pci_get_device(vendor_id, PCI_ANY_ID, pci_device)) != NULL)
|
||||
{
|
||||
if ((nnt_device_flag == NNT_PCICONF_DEVICES) || (nnt_device_flag == NNT_ALL_DEVICES))
|
||||
{
|
||||
/* Create pciconf device. */
|
||||
if (with_unknown || is_pciconf_device(pci_device->device))
|
||||
{
|
||||
if ((error_code = create_nnt_device(pci_device, NNT_PCICONF, is_alloc_chrdev_region)) != 0)
|
||||
{
|
||||
printk(KERN_ERR "Failed to create pci conf device\n");
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((nnt_device_flag == NNT_PCI_DEVICES) || (nnt_device_flag == NNT_ALL_DEVICES))
|
||||
{
|
||||
/* Create pci memory device. */
|
||||
if (with_unknown || is_pcicr_device(pci_device->device))
|
||||
{
|
||||
if ((error_code = create_nnt_device(pci_device, NNT_PCI_MEMORY, is_alloc_chrdev_region)) != 0)
|
||||
{
|
||||
printk(KERN_ERR "Failed to create pci memory device\n");
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the devices. */
|
||||
if ((error_code = create_devices(device_number, fop, is_alloc_chrdev_region)) != 0)
|
||||
{
|
||||
return error_code;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error_code;
|
||||
}
|
||||
|
||||
int find_all_vendor_devices(unsigned int vendor_id)
|
||||
{
|
||||
struct pci_dev* pci_device = NULL;
|
||||
int contiguous_device_numbers = 0;
|
||||
while ((pci_device = pci_get_device(vendor_id, PCI_ANY_ID, pci_device)) != NULL)
|
||||
{
|
||||
contiguous_device_numbers++;
|
||||
}
|
||||
return contiguous_device_numbers;
|
||||
}
|
||||
|
||||
int get_amount_of_nvidia_devices(void)
|
||||
{
|
||||
int contiguous_device_numbers = 0;
|
||||
/* Find all Mellanox & Nvidia PCI devices. */
|
||||
contiguous_device_numbers +=
|
||||
find_all_vendor_devices(NNT_MELLANOX_PCI_VENDOR) + find_all_vendor_devices(NNT_NVIDIA_PCI_VENDOR);
|
||||
return contiguous_device_numbers;
|
||||
}
|
||||
|
||||
int mutex_lock_nnt(struct file* file)
|
||||
{
|
||||
struct nnt_device* nnt_device;
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
nnt_device = file->private_data;
|
||||
|
||||
if (!nnt_device)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&nnt_device->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mutex_unlock_nnt(struct file* file)
|
||||
{
|
||||
struct nnt_device* nnt_device = file->private_data;
|
||||
|
||||
if (nnt_device)
|
||||
{
|
||||
mutex_unlock(&nnt_device->lock);
|
||||
}
|
||||
}
|
||||
|
||||
void destroy_nnt_devices(int is_alloc_chrdev_region)
|
||||
{
|
||||
struct nnt_device* current_nnt_device;
|
||||
struct nnt_device* temp_nnt_device;
|
||||
|
||||
/* free all nnt_devices */
|
||||
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||
{
|
||||
/* Character device is no longer, it must be properly destroyed. */
|
||||
if (is_alloc_chrdev_region)
|
||||
{
|
||||
cdev_del(¤t_nnt_device->mcdev);
|
||||
device_destroy(nnt_driver_info.class_driver, current_nnt_device->device_number);
|
||||
}
|
||||
|
||||
list_del(¤t_nnt_device->entry);
|
||||
kfree(current_nnt_device);
|
||||
}
|
||||
}
|
||||
|
||||
void destroy_nnt_devices_bc(void)
|
||||
{
|
||||
struct nnt_device* current_nnt_device;
|
||||
struct nnt_device* temp_nnt_device;
|
||||
|
||||
/* free all nnt_devices */
|
||||
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||
{
|
||||
/* Character device is no longer, it must be properly destroyed. */
|
||||
list_del(¤t_nnt_device->entry);
|
||||
kfree(current_nnt_device);
|
||||
}
|
||||
}
|
||||
|
||||
int destroy_nnt_device_bc(struct nnt_device* nnt_device)
|
||||
{
|
||||
struct nnt_device* current_nnt_device;
|
||||
struct nnt_device* temp_nnt_device;
|
||||
unsigned int current_function;
|
||||
unsigned int current_device;
|
||||
|
||||
/* Set private data to nnt structure. */
|
||||
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||
{
|
||||
struct pci_bus* pci_bus = pci_find_bus(current_nnt_device->dbdf.domain, current_nnt_device->dbdf.bus);
|
||||
if (!pci_bus)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
current_nnt_device->pci_device = pci_get_slot(pci_bus, current_nnt_device->dbdf.devfn);
|
||||
if (!current_nnt_device->pci_device)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
current_function = PCI_FUNC(current_nnt_device->dbdf.devfn);
|
||||
current_device = PCI_SLOT(current_nnt_device->dbdf.devfn);
|
||||
|
||||
if ((current_nnt_device->dbdf.bus == nnt_device->dbdf.bus) &&
|
||||
(current_device == PCI_SLOT(nnt_device->dbdf.devfn)) &&
|
||||
(current_function == PCI_FUNC(nnt_device->dbdf.devfn)) &&
|
||||
(current_nnt_device->dbdf.domain == nnt_device->dbdf.domain))
|
||||
{
|
||||
/* Character device is no longer, it must be properly disabled. */
|
||||
current_nnt_device->device_enabled = false;
|
||||
printk(KERN_DEBUG "Device removed: domain: %d, bus: %d, device:%d, function:%d \n",
|
||||
current_nnt_device->dbdf.domain, current_nnt_device->dbdf.bus, current_device, current_function);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
26
drivers/net/ethernet/mft/nnt_driver/nnt_device.h
Normal file
26
drivers/net/ethernet/mft/nnt_driver/nnt_device.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef NNT_DEVICE_H
|
||||
#define NNT_DEVICE_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include "nnt_device_defs.h"
|
||||
|
||||
int create_nnt_devices(dev_t device_number,
|
||||
int is_alloc_chrdev_region,
|
||||
struct file_operations* fop,
|
||||
enum nnt_device_type_flag nnt_device_flag,
|
||||
unsigned int vendor_id,
|
||||
int with_unknown);
|
||||
void destroy_nnt_devices(int is_alloc_chrdev_region);
|
||||
void destroy_nnt_devices_bc(void);
|
||||
int destroy_nnt_device_bc(struct nnt_device* nnt_device);
|
||||
int is_pciconf_device(unsigned short pci_device_id);
|
||||
int is_pcicr_device(unsigned short pci_device_id);
|
||||
int get_amount_of_nvidia_devices(void);
|
||||
int set_private_data(struct file* file);
|
||||
void set_private_data_open(struct file* file);
|
||||
int set_private_data_bc(struct file* file, unsigned int bus, unsigned int devfn, unsigned int domain);
|
||||
int get_nnt_device(struct file* file, struct nnt_device** nnt_device);
|
||||
int mutex_lock_nnt(struct file* file);
|
||||
void mutex_unlock_nnt(struct file* file);
|
||||
|
||||
#endif
|
||||
169
drivers/net/ethernet/mft/nnt_driver/nnt_device_defs.h
Normal file
169
drivers/net/ethernet/mft/nnt_driver/nnt_device_defs.h
Normal file
@@ -0,0 +1,169 @@
|
||||
#ifndef NNT_DEVICE_DEFS_H
|
||||
#define NNT_DEVICE_DEFS_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/cdev.h>
|
||||
#include "nnt_ioctl_defs.h"
|
||||
|
||||
#define NNT_DEVICE_ID_OFFSET 0xf0014
|
||||
#define NNT_WO_REG_ADDR_DATA 0xbadacce5
|
||||
#define NNT_NAME_SIZE 75
|
||||
#define NNT_CONF_ADDRES_REGISETER 88
|
||||
#define NNT_CONF_DATA_REGISTER 92
|
||||
#define MELLANOX_VSEC_TYPE 0
|
||||
#define PCI_TYPE_OFFSET 0x03
|
||||
#define PCI_SEMAPHORE_OFFSET 0x0c
|
||||
#define PCI_ADDRESS_OFFSET 0x10
|
||||
#define PCI_DATA_OFFSET 0x14
|
||||
#define NNT_MEMORY_SIZE 1024 * 1024
|
||||
#define VSEC_CAPABILITY_ADDRESS 0x9
|
||||
|
||||
#define MSTFLINT_PCICONF_DEVICE_NAME "mstconf"
|
||||
#define MSTFLINT_MEMORY_DEVICE_NAME "mstcr"
|
||||
#define MFT_PCICONF_DEVICE_NAME "pciconf"
|
||||
#define MFT_MEMORY_DEVICE_NAME "pci_cr"
|
||||
|
||||
#define MST_BC_BUFFER_SIZE 256
|
||||
#define MST_BC_MAX_MINOR 256
|
||||
|
||||
// Mellanox Vendor ID.
|
||||
#define NNT_MELLANOX_PCI_VENDOR 0x15b3
|
||||
|
||||
// NVIDIA Vendor ID.
|
||||
#define NNT_NVIDIA_PCI_VENDOR 0x10de
|
||||
|
||||
// Livefish Device ID range.
|
||||
#define CONNECTX3_LIVEFISH_ID 502
|
||||
|
||||
// PCI Device IDs.
|
||||
#define CONNECTX3_PCI_ID 4099
|
||||
#define CONNECTX3PRO_PCI_ID 4103
|
||||
#define CONNECTIB_PCI_ID 4113
|
||||
#define CONNECTX4_PCI_ID 4115
|
||||
#define CONNECTX4LX_PCI_ID 4117
|
||||
#define CONNECTX5_PCI_ID 4119
|
||||
#define CONNECTX5EX_PCI_ID 4121
|
||||
#define CONNECTX6_PCI_ID 4123
|
||||
#define CONNECTX6DX_PCI_ID 4125
|
||||
#define CONNECTX6LX_PCI_ID 4127
|
||||
#define CONNECTX7_PCI_ID 4129
|
||||
#define CONNECTX8_PCI_ID 4131
|
||||
#define SCHRODINGER_PCI_ID 6518
|
||||
#define FREYSA_PCI_ID 6521
|
||||
#define BLUEFIELD_PCI_ID 41682
|
||||
#define BLUEFIELD2_PCI_ID 41686
|
||||
#define BLUEFIELD_DPU_AUX_PCI_ID 49873
|
||||
#define BLUEFIELD3_PCI_ID 41692
|
||||
#define BLUEFIELD4_PCI_ID 41694
|
||||
#define SWITCHIB_PCI_ID 52000
|
||||
#define SWITCHIB2_PCI_ID 53000
|
||||
#define QUANTUM_PCI_ID 54000
|
||||
#define QUANTUM2_PCI_ID 54002
|
||||
#define QUANTUM3_PCI_ID 54004
|
||||
#define SPECTRUM_PCI_ID 52100
|
||||
#define SPECTRUM2_PCI_ID 53100
|
||||
#define SPECTRUM3_PCI_ID 53104
|
||||
#define SPECTRUM4_PCI_ID 53120
|
||||
#define BW00_PCI_ID 10496
|
||||
#define BW02_PCI_ID 10624
|
||||
|
||||
enum nnt_device_type_flag
|
||||
{
|
||||
NNT_PCICONF_DEVICES = 0x01,
|
||||
NNT_PCI_DEVICES,
|
||||
NNT_ALL_DEVICES
|
||||
};
|
||||
|
||||
struct nnt_dma_page
|
||||
{
|
||||
struct page** page_list;
|
||||
dma_addr_t* dma_address_list;
|
||||
};
|
||||
|
||||
enum nnt_device_type
|
||||
{
|
||||
NNT_PCICONF,
|
||||
NNT_PCICONF_NO_VSEC,
|
||||
NNT_PCI_MEMORY
|
||||
};
|
||||
|
||||
struct supported_address_space
|
||||
{
|
||||
int cr_space;
|
||||
int icmd;
|
||||
int semaphore;
|
||||
};
|
||||
|
||||
/* Forward declaration */
|
||||
struct nnt_device;
|
||||
typedef int (*callback_read)(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation);
|
||||
typedef int (*callback_write)(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation);
|
||||
typedef int (*callback_init)(struct nnt_device* nnt_device);
|
||||
|
||||
struct nnt_access_callback
|
||||
{
|
||||
callback_read read;
|
||||
callback_write write;
|
||||
callback_init init;
|
||||
};
|
||||
|
||||
struct nnt_device_pciconf
|
||||
{
|
||||
struct supported_address_space address_space;
|
||||
unsigned int address_register;
|
||||
unsigned int data_register;
|
||||
unsigned int semaphore_offset;
|
||||
unsigned int data_offset;
|
||||
unsigned int address_offset;
|
||||
unsigned int vendor_specific_capability;
|
||||
unsigned int vsec_capability_mask;
|
||||
unsigned int vsec_fully_supported;
|
||||
};
|
||||
|
||||
struct nnt_device_pci
|
||||
{
|
||||
unsigned long long bar_address;
|
||||
unsigned int bar_size;
|
||||
};
|
||||
|
||||
struct nnt_device_memory
|
||||
{
|
||||
unsigned int pci_memory_bar_address;
|
||||
unsigned int connectx_wa_slot_p1;
|
||||
void* hardware_memory_address;
|
||||
};
|
||||
|
||||
struct nnt_device_dbdf
|
||||
{
|
||||
unsigned int domain;
|
||||
unsigned int bus;
|
||||
unsigned int devfn;
|
||||
};
|
||||
|
||||
struct nnt_device
|
||||
{
|
||||
struct nnt_device_pciconf pciconf_device;
|
||||
struct nnt_device_memory memory_device;
|
||||
struct nnt_access_callback access;
|
||||
struct nnt_device_pci device_pci;
|
||||
struct pci_dev* pci_device;
|
||||
struct nnt_dma_page dma_page;
|
||||
struct list_head entry;
|
||||
struct cdev mcdev;
|
||||
struct mutex lock;
|
||||
struct nnt_device_dbdf dbdf;
|
||||
enum nnt_device_type device_type;
|
||||
int vpd_capability_address;
|
||||
int device_minor_number;
|
||||
int wo_address;
|
||||
int buffer_used_bc;
|
||||
int device_enabled;
|
||||
char device_name[NNT_NAME_SIZE];
|
||||
char buffer_bc[MST_BC_BUFFER_SIZE];
|
||||
unsigned int connectx_wa_slot_p1;
|
||||
unsigned char connectx_wa_slots;
|
||||
dev_t device_number;
|
||||
};
|
||||
|
||||
#endif
|
||||
196
drivers/net/ethernet/mft/nnt_driver/nnt_dma.c
Normal file
196
drivers/net/ethernet/mft/nnt_driver/nnt_dma.c
Normal file
@@ -0,0 +1,196 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include "nnt_device_defs.h"
|
||||
#include "nnt_pci_conf_access_defs.h"
|
||||
#include "nnt_pci_conf_access.h"
|
||||
#include "nnt_defs.h"
|
||||
#include "nnt_ioctl_defs.h"
|
||||
|
||||
int dma_mapping_page(unsigned int total_pinned, unsigned int page_mapped_counter,
|
||||
struct nnt_device* nnt_device, struct page** current_pages,
|
||||
struct nnt_page_info* page_info)
|
||||
{
|
||||
int current_page = total_pinned + page_mapped_counter;
|
||||
int error_code = 0;
|
||||
|
||||
/* Get the dma address. */
|
||||
nnt_device->dma_page.dma_address_list[current_page] =
|
||||
dma_map_page(&nnt_device->pci_device->dev, current_pages[current_page],
|
||||
0, PAGE_SIZE,
|
||||
DMA_BIDIRECTIONAL);
|
||||
/* Do we get a valid dma address ? */
|
||||
if (dma_mapping_error(&nnt_device->pci_device->dev, nnt_device->dma_page.dma_address_list[current_page])) {
|
||||
printk(KERN_ERR "Failed to get DMA addresses\n");
|
||||
error_code = -EINVAL;
|
||||
goto ReturnOnFinsihed;
|
||||
}
|
||||
|
||||
page_info->page_address_array[current_page].dma_address =
|
||||
nnt_device->dma_page.dma_address_list[current_page];
|
||||
|
||||
ReturnOnFinsihed:
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int pin_user_pages_in_kernel_space(unsigned int total_pages, unsigned int total_pinned,
|
||||
int* pinned_pages, struct nnt_device* nnt_device,
|
||||
struct nnt_page_info* page_info, struct page*** current_pages)
|
||||
{
|
||||
unsigned long page_pointer_start = page_info->page_pointer_start;
|
||||
int error_code = 0;
|
||||
|
||||
|
||||
/* Remaining pages to pin. */
|
||||
int remaining_pages = total_pages - total_pinned;
|
||||
|
||||
/* Point to the current offset. */
|
||||
uint64_t current_page_pointer = page_pointer_start + (total_pinned * PAGE_SIZE);
|
||||
|
||||
/* Save the current page. */
|
||||
*current_pages = nnt_device->dma_page.page_list + total_pinned;
|
||||
|
||||
/* Returns number of pages pinned - this may be fewer than the number requested
|
||||
or -errno in case of error. */
|
||||
*pinned_pages = get_user_pages_fast(current_page_pointer, remaining_pages,
|
||||
FOLL_WRITE, *current_pages);
|
||||
|
||||
if (*pinned_pages < 1) {
|
||||
kfree(nnt_device->dma_page.page_list);
|
||||
error_code = -EFAULT;
|
||||
}
|
||||
|
||||
/* Allocate dma addresses structure. */
|
||||
if ((nnt_device->dma_page.dma_address_list =
|
||||
kcalloc(total_pages, sizeof(dma_addr_t), GFP_KERNEL)) == NULL) {
|
||||
error_code = -ENOMEM;
|
||||
}
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int pin_user_memory_in_kernel_space(unsigned int total_pages, struct nnt_device* nnt_device,
|
||||
struct nnt_page_info* page_info)
|
||||
{
|
||||
unsigned int page_mapped_counter= 0;
|
||||
unsigned int total_pinned = 0;
|
||||
unsigned int pinned_pages;
|
||||
struct page** current_pages = NULL;
|
||||
int error_code = 0;
|
||||
|
||||
while (total_pinned < total_pages) {
|
||||
/* Pinning user pages in kernel space. */
|
||||
if((error_code =
|
||||
pin_user_pages_in_kernel_space(total_pages, total_pinned,
|
||||
&pinned_pages, nnt_device,
|
||||
page_info, ¤t_pages)) != 0)
|
||||
goto ReturnOnFinished;
|
||||
|
||||
/* When the parameter 'inter_iommu' is on, we need to set up
|
||||
a mapping on a pages in order to access the physical address. */
|
||||
while(page_mapped_counter < pinned_pages)
|
||||
{
|
||||
if((error_code =
|
||||
dma_mapping_page(total_pinned, page_mapped_counter,
|
||||
nnt_device, current_pages,
|
||||
page_info)) != 0)
|
||||
goto ReturnOnFinished;
|
||||
|
||||
page_mapped_counter++;
|
||||
}
|
||||
|
||||
/* Advance the memory that already pinned. */
|
||||
total_pinned += pinned_pages;
|
||||
}
|
||||
|
||||
/* There is a page not pinned in the kernel space ? */
|
||||
if (total_pinned != total_pages) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int map_dma_pages(struct nnt_page_info* page_info, struct nnt_device* nnt_device)
|
||||
{
|
||||
unsigned int total_pages = page_info->total_pages;
|
||||
int page_counter = 0;
|
||||
int error_code = 0;
|
||||
|
||||
|
||||
/* Check if we allow locking memory. */
|
||||
if (!can_do_mlock()) {
|
||||
error_code = -EPERM;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Allocate the page list. */
|
||||
if ((nnt_device->dma_page.page_list =
|
||||
kcalloc(total_pages, sizeof(struct page *), GFP_KERNEL)) == NULL) {
|
||||
error_code = -ENOMEM;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Go over the user memory buffer and pin user pages in kernel space */
|
||||
if((error_code =
|
||||
pin_user_memory_in_kernel_space(total_pages, nnt_device,
|
||||
page_info)) != 0)
|
||||
goto ReturnOnFinished;
|
||||
|
||||
for (page_counter = 0;
|
||||
page_counter < total_pages;
|
||||
page_counter++) {
|
||||
printk(KERN_INFO "Page address structure number: %d, device: %04x:%02x:%02x.%0x\n",
|
||||
page_counter, pci_domain_nr(nnt_device->pci_device->bus),
|
||||
nnt_device->pci_device->bus->number, PCI_SLOT(nnt_device->pci_device->devfn),
|
||||
PCI_FUNC(nnt_device->pci_device->devfn));
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int release_dma_pages(struct nnt_page_info* page_info, struct nnt_device* nnt_device)
|
||||
{
|
||||
int page_counter;
|
||||
|
||||
if (nnt_device->dma_page.page_list == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Deallocate the pages. */
|
||||
for (page_counter = 0;
|
||||
page_counter < page_info->total_pages;
|
||||
page_counter++) {
|
||||
/* DMA activity is finished. */
|
||||
dma_unmap_page(&nnt_device->pci_device->dev, nnt_device->dma_page.dma_address_list[page_counter],
|
||||
PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||
|
||||
/* Release the page list. */
|
||||
set_page_dirty(nnt_device->dma_page.page_list[page_counter]);
|
||||
put_page(nnt_device->dma_page.page_list[page_counter]);
|
||||
nnt_device->dma_page.page_list[page_counter] = NULL;
|
||||
nnt_device->dma_page.dma_address_list[page_counter] = 0;
|
||||
|
||||
printk(KERN_INFO "Page structure number: %d was released. device:%04x:%02x:%02x.%0x\n",
|
||||
page_counter, pci_domain_nr(nnt_device->pci_device->bus),
|
||||
nnt_device->pci_device->bus->number, PCI_SLOT(nnt_device->pci_device->devfn),
|
||||
PCI_FUNC(nnt_device->pci_device->devfn));
|
||||
}
|
||||
|
||||
// All the pages are clean.
|
||||
nnt_device->dma_page.page_list = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
10
drivers/net/ethernet/mft/nnt_driver/nnt_dma.h
Normal file
10
drivers/net/ethernet/mft/nnt_driver/nnt_dma.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef NNT_DMA_H
|
||||
#define NNT_DMA_H
|
||||
|
||||
#include "nnt_ioctl_defs.h"
|
||||
#include "nnt_device_defs.h"
|
||||
|
||||
int map_dma_pages(struct nnt_page_info* page_info, struct nnt_device* nnt_device);
|
||||
int release_dma_pages(struct nnt_page_info* page_info, struct nnt_device* nnt_device);
|
||||
|
||||
#endif
|
||||
230
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl.c
Normal file
230
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl.c
Normal file
@@ -0,0 +1,230 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/sched.h>
|
||||
#include "nnt_dma.h"
|
||||
#include "nnt_defs.h"
|
||||
#include "nnt_pci_conf_access.h"
|
||||
|
||||
|
||||
unsigned int mask = 0x7fff;
|
||||
unsigned int msb_mask = 0x8000;
|
||||
|
||||
int dma_pages_ioctl(unsigned int command, void* user_buffer,
|
||||
struct nnt_device* nnt_device)
|
||||
{
|
||||
struct nnt_page_info page_info;
|
||||
int error_code = 0;
|
||||
|
||||
|
||||
/* Copy the page info structure from user space. */
|
||||
if (copy_from_user(&page_info, user_buffer,
|
||||
sizeof(struct nnt_page_info))) {
|
||||
error_code = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
if (command == NNT_GET_DMA_PAGES) {
|
||||
if (map_dma_pages(&page_info, nnt_device)) {
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Return the physical address to the user */
|
||||
if (copy_to_user(user_buffer, &page_info,
|
||||
sizeof(struct nnt_page_info)) != 0) {
|
||||
error_code = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
} else {
|
||||
error_code =
|
||||
release_dma_pages(&page_info, nnt_device);
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int read_dword_ioctl(void* user_buffer, struct nnt_device* nnt_device)
|
||||
{
|
||||
struct nnt_read_dword_from_config_space read_from_cspace;
|
||||
int error_code = 0;
|
||||
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&read_from_cspace, user_buffer,
|
||||
sizeof(struct nnt_read_dword_from_config_space)) != 0) {
|
||||
error_code = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Read the dword. */
|
||||
if (read_dword(&read_from_cspace, nnt_device)) {
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &read_from_cspace,
|
||||
sizeof(struct nnt_read_dword_from_config_space)) != 0) {
|
||||
error_code = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
||||
int get_nnt_device_parameters(struct nnt_device_parameters* nnt_parameters, struct nnt_device* nnt_device)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
nnt_parameters->domain = pci_domain_nr(nnt_device->pci_device->bus);
|
||||
nnt_parameters->bus = nnt_device->pci_device->bus->number;
|
||||
nnt_parameters->slot = PCI_SLOT(nnt_device->pci_device->devfn);
|
||||
nnt_parameters->function = PCI_FUNC(nnt_device->pci_device->devfn);
|
||||
nnt_parameters->pci_memory_bar_address= nnt_device->memory_device.pci_memory_bar_address;
|
||||
nnt_parameters->device = nnt_device->pci_device->device;
|
||||
nnt_parameters->vendor = nnt_device->pci_device->vendor;
|
||||
nnt_parameters->subsystem_device = nnt_device->pci_device->subsystem_device;
|
||||
nnt_parameters->multifunction = nnt_device->pci_device->multifunction;
|
||||
nnt_parameters->subsystem_vendor = nnt_device->pci_device->subsystem_vendor;
|
||||
|
||||
check_address_space_support(nnt_device);
|
||||
if (nnt_device->pciconf_device.vendor_specific_capability &&
|
||||
(nnt_device->pciconf_device.address_space.icmd || nnt_device->pciconf_device.address_space.cr_space ||
|
||||
nnt_device->pciconf_device.address_space.semaphore)) {
|
||||
nnt_parameters->vendor_specific_capability = nnt_device->pciconf_device.vendor_specific_capability;
|
||||
nnt_parameters->vsec_capability_mask = nnt_device->pciconf_device.vsec_capability_mask;
|
||||
} else {
|
||||
nnt_parameters->vendor_specific_capability = 0;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int pci_connectx_wa(struct nnt_connectx_wa* connectx_wa, struct nnt_device* nnt_device)
|
||||
{
|
||||
unsigned int slot_mask;
|
||||
int error = 0;
|
||||
|
||||
/* Is this slot exists ? */
|
||||
if (nnt_device->memory_device.connectx_wa_slot_p1) {
|
||||
printk(KERN_DEBUG "Slot exits for file %s, slot:0x%x\n",
|
||||
nnt_device->device_name, nnt_device->memory_device.connectx_wa_slot_p1);
|
||||
error = 0;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Find first un(set) bit. and remember the slot */
|
||||
nnt_device->memory_device.connectx_wa_slot_p1= ffs(~nnt_device->memory_device.connectx_wa_slot_p1);
|
||||
if (nnt_device->memory_device.connectx_wa_slot_p1 == 0 ||
|
||||
nnt_device->memory_device.connectx_wa_slot_p1 > NNT_CONNECTX_WA_SIZE) {
|
||||
error = -ENOLCK;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
slot_mask = 1 << (nnt_device->memory_device.connectx_wa_slot_p1 - 1);
|
||||
|
||||
/* set the slot as taken */
|
||||
nnt_device->memory_device.connectx_wa_slot_p1 |= slot_mask;
|
||||
|
||||
connectx_wa->connectx_wa_slot_p1 = nnt_device->memory_device.connectx_wa_slot_p1;
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int vpd_read(struct nnt_vpd* vpd, struct nnt_device* nnt_device)
|
||||
{
|
||||
unsigned long jiffies_time;
|
||||
unsigned int address;
|
||||
unsigned short data;
|
||||
int is_bit_set = 0;
|
||||
int error;
|
||||
|
||||
/* Sets F bit to zero and write VPD address. */
|
||||
address = mask & vpd->offset;
|
||||
error = pci_write_config_word(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||
address);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||
address);
|
||||
|
||||
/* Wait for data until F bit is set with one */
|
||||
jiffies_time = msecs_to_jiffies(vpd->timeout) + jiffies;
|
||||
while (time_before(jiffies, jiffies_time)) {
|
||||
error = pci_read_config_word(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||
&data);
|
||||
CHECK_PCI_READ_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_ADDR);
|
||||
|
||||
if (data & msb_mask) {
|
||||
is_bit_set = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
if (!is_bit_set) {
|
||||
printk(KERN_ERR "Failed to retrieve valid data\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_DATA,
|
||||
&vpd->data);
|
||||
CHECK_PCI_READ_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_DATA);
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int vpd_write(struct nnt_vpd* vpd, struct nnt_device* nnt_device)
|
||||
{
|
||||
unsigned long jiffies_time;
|
||||
unsigned int address;
|
||||
unsigned short data;
|
||||
int is_bit_set = 0;
|
||||
int error;
|
||||
|
||||
/* Write the user data */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_DATA,
|
||||
vpd->data);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_DATA,
|
||||
vpd->data);
|
||||
|
||||
/* sets F bit to one and write VPD addr */
|
||||
address = msb_mask | (mask & vpd->offset);
|
||||
error = pci_write_config_word(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||
address);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||
address);
|
||||
|
||||
/* wait for data until F bit is set with zero */
|
||||
jiffies_time = msecs_to_jiffies(vpd->timeout) + jiffies;
|
||||
while (time_before(jiffies, jiffies_time)) {
|
||||
error = pci_read_config_word(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||
&data);
|
||||
CHECK_PCI_READ_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_ADDR);
|
||||
|
||||
if (!(data & msb_mask)) {
|
||||
is_bit_set = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
if (!is_bit_set) {
|
||||
printk(KERN_ERR "Failed to retrieve valid data\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
14
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl.h
Normal file
14
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef NNT_IOCTL_H
|
||||
#define NNT_IOCTL_H
|
||||
|
||||
#include "nnt_device_defs.h"
|
||||
|
||||
int dma_pages_ioctl(unsigned int command, void* user_buffer,
|
||||
struct nnt_device* nnt_device);
|
||||
int read_dword_ioctl(unsigned int command, void* user_buffer,
|
||||
struct nnt_device* nnt_device);
|
||||
int get_nnt_device_parameters(struct nnt_device_parameters* nnt_parameters, struct nnt_device* nnt_device);
|
||||
int pci_connectx_wa(struct nnt_connectx_wa* connectx_wa, struct nnt_device* nnt_device);
|
||||
int vpd_read(struct nnt_vpd* vpd, struct nnt_device* nnt_device);
|
||||
int vpd_write(struct nnt_vpd* vpd, struct nnt_device* nnt_device);
|
||||
#endif
|
||||
83
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl_defs.h
Normal file
83
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl_defs.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef NNT_IOCTL_DEFS_H
|
||||
#define NNT_IOCTL_DEFS_H
|
||||
|
||||
#define NNT_MAGIC_NUMBER 0xD3
|
||||
#define MAX_BUFFER_BLOCK_SIZE 256
|
||||
#define NNT_MAX_PAGES_SIZE 8
|
||||
#define NNT_CONNECTX_WA_SIZE 3
|
||||
|
||||
#define NNT_WRITE _IOW (NNT_MAGIC_NUMBER, 1, struct nnt_rw_operation)
|
||||
#define NNT_READ _IOW (NNT_MAGIC_NUMBER, 2, struct nnt_rw_operation)
|
||||
#define NNT_GET_DMA_PAGES _IOR (NNT_MAGIC_NUMBER, 3, struct nnt_page_info)
|
||||
#define NNT_RELEASE_DMA_PAGES _IOR (NNT_MAGIC_NUMBER, 4, struct nnt_page_info)
|
||||
#define NNT_READ_DWORD_FROM_CONFIG_SPACE _IOR (NNT_MAGIC_NUMBER, 5, struct nnt_read_dword_from_config_space)
|
||||
#define NNT_GET_DEVICE_PARAMETERS _IOR (NNT_MAGIC_NUMBER, 6, struct nnt_device_parameters)
|
||||
#define NNT_INIT _IOR (NNT_MAGIC_NUMBER, 7, struct nnt_pciconf_init)
|
||||
#define NNT_PCI_CONNECTX_WA _IOR (NNT_MAGIC_NUMBER, 8, u_int32_t)
|
||||
#define NNT_VPD_READ _IOR (NNT_MAGIC_NUMBER, 9, struct nnt_vpd)
|
||||
#define NNT_VPD_WRITE _IOW (NNT_MAGIC_NUMBER, 10, struct nnt_vpd)
|
||||
|
||||
|
||||
|
||||
struct nnt_vpd {
|
||||
unsigned int offset;
|
||||
unsigned int timeout;
|
||||
unsigned int data;
|
||||
};
|
||||
|
||||
|
||||
struct nnt_pciconf_init {
|
||||
unsigned int address_register;
|
||||
unsigned int address_data_register;
|
||||
};
|
||||
|
||||
|
||||
struct nnt_device_parameters {
|
||||
unsigned int domain;
|
||||
unsigned int bus;
|
||||
unsigned int slot;
|
||||
unsigned int function;
|
||||
unsigned int pci_memory_bar_address;
|
||||
unsigned int device;
|
||||
unsigned int vendor;
|
||||
unsigned int subsystem_device;
|
||||
unsigned int subsystem_vendor;
|
||||
unsigned int multifunction;
|
||||
unsigned int vendor_specific_capability;
|
||||
unsigned int vsec_capability_mask;
|
||||
};
|
||||
|
||||
|
||||
struct nnt_page_address {
|
||||
u_int64_t dma_address;
|
||||
u_int64_t virtual_address;
|
||||
};
|
||||
|
||||
|
||||
struct nnt_page_info {
|
||||
unsigned int total_pages;
|
||||
unsigned long page_pointer_start;
|
||||
struct nnt_page_address page_address_array[NNT_MAX_PAGES_SIZE];
|
||||
};
|
||||
|
||||
|
||||
struct nnt_read_dword_from_config_space {
|
||||
unsigned int offset;
|
||||
unsigned int data;
|
||||
};
|
||||
|
||||
|
||||
struct nnt_rw_operation {
|
||||
unsigned int address_space;
|
||||
unsigned int offset;
|
||||
int size;
|
||||
unsigned int data[MAX_BUFFER_BLOCK_SIZE / 4];
|
||||
};
|
||||
|
||||
|
||||
struct nnt_connectx_wa {
|
||||
unsigned int connectx_wa_slot_p1;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
295
drivers/net/ethernet/mft/nnt_driver/nnt_linux_driver_main.c
Normal file
295
drivers/net/ethernet/mft/nnt_driver/nnt_linux_driver_main.c
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "nnt_defs.h"
|
||||
#include "nnt_device.h"
|
||||
#include "nnt_ioctl.h"
|
||||
#include "nnt_ioctl_defs.h"
|
||||
|
||||
MODULE_AUTHOR("Itay Avraham <itayavr@nvidia.com>");
|
||||
MODULE_DESCRIPTION("NNT Linux driver (NVIDIA® networking tools driver)");
|
||||
|
||||
/* Passing MFT flag argument */
|
||||
int mft_package = 0;
|
||||
|
||||
/* Create the file in sysfs. */
|
||||
module_param(mft_package, int, S_IRUSR);
|
||||
|
||||
struct driver_info nnt_driver_info;
|
||||
|
||||
static long nnt_ioctl(struct file* file, unsigned int command, unsigned long argument)
|
||||
{
|
||||
void* user_buffer = (void*)argument;
|
||||
struct nnt_device* nnt_device = NULL;
|
||||
int error;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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 NNT_GET_DMA_PAGES:
|
||||
case NNT_RELEASE_DMA_PAGES:
|
||||
error = dma_pages_ioctl(command, user_buffer, nnt_device);
|
||||
break;
|
||||
|
||||
case NNT_READ_DWORD_FROM_CONFIG_SPACE:
|
||||
error = read_dword_ioctl(command, user_buffer, nnt_device);
|
||||
break;
|
||||
|
||||
case NNT_WRITE:
|
||||
case NNT_READ:
|
||||
{
|
||||
struct nnt_rw_operation rw_operation;
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&rw_operation, user_buffer, sizeof(struct nnt_rw_operation)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case NNT_WRITE:
|
||||
nnt_device->access.write(nnt_device, &rw_operation);
|
||||
break;
|
||||
case NNT_READ:
|
||||
nnt_device->access.read(nnt_device, &rw_operation);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &rw_operation, sizeof(struct nnt_rw_operation)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NNT_GET_DEVICE_PARAMETERS:
|
||||
{
|
||||
struct nnt_device_parameters nnt_parameters;
|
||||
|
||||
error = get_nnt_device_parameters(&nnt_parameters, nnt_device);
|
||||
|
||||
/* Copy the data to the user space. */
|
||||
if (copy_to_user(user_buffer, &nn_parameters, sizeof(struct device_parameters)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NNT_INIT:
|
||||
{
|
||||
struct nnt_pciconf_init init;
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&init, user_buffer, sizeof(struct nnt_pciconf_init)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
error = nnt_device->access.init(&init, nnt_device);
|
||||
break;
|
||||
}
|
||||
case NNT_PCI_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 NNT_VPD_READ:
|
||||
case NNT_VPD_WRITE:
|
||||
{
|
||||
int vpd_default_timeout = 2000;
|
||||
struct nnt_vpd vpd;
|
||||
|
||||
if (!nnt_device->vpd_capability_address)
|
||||
{
|
||||
printk(KERN_ERR "Device %s not support Vital Product Data\n", nnt_device->device_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Copy the request from user space. */
|
||||
if (copy_from_user(&vpd, user_buffer, sizeof(struct nnt_vpd)) != 0)
|
||||
{
|
||||
error = -EFAULT;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
if (!vpd.timeout)
|
||||
{
|
||||
vpd.timeout = vpd_default_timeout;
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case NNT_VPD_READ:
|
||||
error = vpd_read(command, &vpd, nnt_device);
|
||||
break;
|
||||
case NNT_VPD_WRITE:
|
||||
error = vpd_write(command, &vpd, nnt_device);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printk(KERN_ERR "ioctl not implemented, command id: %x\n", command);
|
||||
error = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
mutex_unlock_nnt(file);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int nnt_open(struct inode* inode, struct file* file)
|
||||
{
|
||||
if (file->private_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return set_private_data(inode, file);
|
||||
}
|
||||
|
||||
struct file_operations fop = {.unlocked_ioctl = ioctl, .open = nnt_open, .owner = THIS_MODULE};
|
||||
|
||||
int with_unknown = 0;
|
||||
|
||||
module_param(with_unknown, int, S_IRUSR | S_IWUSR);
|
||||
|
||||
static int __init nnt_init_module(void)
|
||||
{
|
||||
int first_minor_number = 0;
|
||||
int error = 0;
|
||||
dev_t device_numbers;
|
||||
|
||||
/* Get the amount of the Nvidia devices. */
|
||||
if ((nnt_driver_info.contiguous_device_numbers = get_amount_of_nvidia_devices()) == 0)
|
||||
{
|
||||
printk(KERN_ERR "No devices found\n");
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
/* Allocate char driver region and assign major number */
|
||||
if ((error = alloc_chrdev_region(&device_numbers, first_minor_number, nnt_driver_info.contiguous_device_numbers,
|
||||
NNT_DRIVER_NAME)) != 0)
|
||||
{
|
||||
printk(KERN_ERR "failed to allocate chrdev_region\n");
|
||||
goto CharDeviceAllocated;
|
||||
}
|
||||
|
||||
nnt_driver_info.driver_major_number = MAJOR(device_numbers);
|
||||
|
||||
/* create sysfs class. */
|
||||
if ((nnt_driver_info.class_driver = class_create(THIS_MODULE, NNT_CLASS_NAME)) == NULL)
|
||||
{
|
||||
printk(KERN_ERR "Class creation failed\n");
|
||||
error = -EFAULT;
|
||||
goto DriverClassAllocated;
|
||||
}
|
||||
|
||||
/* Create device files for MSTflint and MFT */
|
||||
error = create_nnt_devices(nnt_driver_info.contiguous_device_numbers, device_numbers, mft_package,
|
||||
NNT_MELLANOX_PCI_VENDOR, &fop) ||
|
||||
create_nnt_devices(nnt_driver_info.contiguous_device_numbers, device_numbers, mft_package,
|
||||
NNT_NVIDIA_PCI_VENDOR, &fop);
|
||||
if ((error) == 0)
|
||||
{
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
|
||||
DriverClassAllocated:
|
||||
destroy_nnt_devices();
|
||||
class_destroy(nnt_driver_info.class_driver);
|
||||
|
||||
CharDeviceAllocated:
|
||||
unregister_chrdev_region(nnt_driver_info.driver_major_number, nnt_driver_info.contiguous_device_numbers);
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void __exit nnt_cleanup_module(void)
|
||||
{
|
||||
destroy_nnt_devices();
|
||||
class_destroy(nnt_driver_info.class_driver);
|
||||
unregister_chrdev_region(nnt_driver_info.driver_major_number, nnt_driver_info.contiguous_device_numbers);
|
||||
}
|
||||
|
||||
module_init(nnt_init_module);
|
||||
module_exit(nnt_cleanup_module);
|
||||
46
drivers/net/ethernet/mft/nnt_driver/nnt_memory_access.c
Normal file
46
drivers/net/ethernet/mft/nnt_driver/nnt_memory_access.c
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "nnt_device_defs.h"
|
||||
#include "nnt_pci_conf_access_defs.h"
|
||||
#include "nnt_pci_conf_access.h"
|
||||
#include "nnt_defs.h"
|
||||
|
||||
|
||||
int write_memory(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation)
|
||||
{
|
||||
/* Endianness conversion. */
|
||||
cpu_to_be32s(write_operation->data);
|
||||
write_operation->data[0] = cpu_to_le32(write_operation->data[0]);
|
||||
|
||||
/* Write to the hardware memory address. */
|
||||
iowrite32(write_operation->data[0], nnt_device->memory_device.hardware_memory_address + write_operation->offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int read_memory(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation)
|
||||
{
|
||||
/* Read from the hardware memory address. */
|
||||
read_operation->data[0] = ioread32(nnt_device->memory_device.hardware_memory_address + read_operation->offset);
|
||||
|
||||
/* Endianness conversion */
|
||||
be32_to_cpus(read_operation->data);
|
||||
read_operation->data[0] = cpu_to_le32(read_operation->data[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int init_memory(struct nnt_device* nnt_device)
|
||||
{
|
||||
nnt_device->memory_device.connectx_wa_slot_p1 = 0;
|
||||
nnt_device->memory_device.hardware_memory_address =
|
||||
ioremap(pci_resource_start(nnt_device->pci_device, nnt_device->memory_device.pci_memory_bar_address),
|
||||
NNT_MEMORY_SIZE);
|
||||
|
||||
if (nnt_device->memory_device.hardware_memory_address <= 0) {
|
||||
printk(KERN_ERR "could not map device memory\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
7
drivers/net/ethernet/mft/nnt_driver/nnt_memory_access.h
Normal file
7
drivers/net/ethernet/mft/nnt_driver/nnt_memory_access.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef NNT_MEMORY_ACCESS_H
|
||||
#define NNT_MEMORY_ACCESS_H
|
||||
|
||||
int read_memory(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation);
|
||||
int write_memory(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation);
|
||||
int init_memory(struct nnt_device* nnt_device);
|
||||
#endif
|
||||
430
drivers/net/ethernet/mft/nnt_driver/nnt_pci_conf_access.c
Normal file
430
drivers/net/ethernet/mft/nnt_driver/nnt_pci_conf_access.c
Normal file
@@ -0,0 +1,430 @@
|
||||
#include "nnt_device_defs.h"
|
||||
#include "nnt_pci_conf_access_defs.h"
|
||||
#include "nnt_pci_conf_access.h"
|
||||
#include "nnt_defs.h"
|
||||
#include <linux/delay.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
|
||||
int clear_vsec_semaphore(struct nnt_device* nnt_device)
|
||||
{
|
||||
/* Clear the semaphore. */
|
||||
int error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.semaphore_offset,
|
||||
0);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.semaphore_offset,
|
||||
0)
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int get_semaphore_ticket(struct nnt_device* nnt_device, unsigned int* lock_value,
|
||||
unsigned int* counter)
|
||||
{
|
||||
unsigned int counter_offset = nnt_device->pciconf_device.vendor_specific_capability + PCI_COUNTER_OFFSET;
|
||||
int error = 0;
|
||||
|
||||
/* Read ticket. */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, counter_offset,
|
||||
counter);
|
||||
CHECK_PCI_READ_ERROR(error, counter_offset);
|
||||
|
||||
/* Write to semaphore ticket. */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.semaphore_offset,
|
||||
*counter);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.semaphore_offset,
|
||||
*counter);
|
||||
|
||||
/* Read back semaphore to make sure the
|
||||
* ticket is equal to semphore */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.semaphore_offset,
|
||||
lock_value);
|
||||
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.semaphore_offset);
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int lock_vsec_semaphore(struct nnt_device* nnt_device)
|
||||
{
|
||||
unsigned int lock_value = -1;
|
||||
unsigned int counter = 0;
|
||||
unsigned int retries = 0;
|
||||
int error = 0;
|
||||
|
||||
do {
|
||||
if (retries > SEMAPHORE_MAX_RETRIES) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Read the semaphore, until we will get 0. */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.semaphore_offset,
|
||||
&lock_value);
|
||||
|
||||
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.semaphore_offset);
|
||||
|
||||
/* Is semaphore taken ? */
|
||||
if (lock_value) {
|
||||
retries++;
|
||||
udelay(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get semaphore ticket */
|
||||
error = get_semaphore_ticket(nnt_device, &lock_value,
|
||||
&counter);
|
||||
CHECK_ERROR(error);
|
||||
} while (counter != lock_value);
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int read_dword(struct nnt_read_dword_from_config_space* read_from_cspace, struct nnt_device* nnt_device)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* Take semaphore. */
|
||||
error = lock_vsec_semaphore(nnt_device);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Read dword from config space. */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, read_from_cspace->offset,
|
||||
&read_from_cspace->data);
|
||||
CHECK_PCI_READ_ERROR(error, read_from_cspace->offset);
|
||||
|
||||
ReturnOnFinished:
|
||||
/* Clear semaphore. */
|
||||
clear_vsec_semaphore(nnt_device);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int wait_on_flag(struct nnt_device* nnt_device, u8 expected_val)
|
||||
{
|
||||
unsigned int flag = 0;
|
||||
int retries = 0;
|
||||
int error = -1;
|
||||
|
||||
for (retries = 0; retries < IFC_MAX_RETRIES; retries++) {
|
||||
/* Read the flag. */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_offset,
|
||||
&flag);
|
||||
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.address_offset);
|
||||
|
||||
flag = EXTRACT(flag, PCI_FLAG_BIT_OFFSET,
|
||||
1);
|
||||
if (flag == expected_val) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int set_address_space(struct nnt_device* nnt_device, unsigned int address_space)
|
||||
{
|
||||
unsigned int control_offset = nnt_device->pciconf_device.vendor_specific_capability + PCI_CONTROL_OFFSET;
|
||||
unsigned int value = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Read value from control offset. */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, control_offset,
|
||||
&value);
|
||||
CHECK_PCI_READ_ERROR(error, control_offset);
|
||||
|
||||
/* Set the bit address_space indication and write it back. */
|
||||
value = MERGE(value, address_space,
|
||||
PCI_SPACE_BIT_OFFSET, PCI_SPACE_BIT_LENGTH);
|
||||
error = pci_write_config_dword(nnt_device->pci_device, control_offset,
|
||||
value);
|
||||
CHECK_PCI_WRITE_ERROR(error, control_offset,
|
||||
value);
|
||||
|
||||
/* Read status and make sure address_space is supported. */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, control_offset,
|
||||
&value);
|
||||
CHECK_PCI_READ_ERROR(error, control_offset);
|
||||
|
||||
if (EXTRACT(value, PCI_STATUS_BIT_OFFSET,
|
||||
PCI_STATUS_BIT_LEN) == 0) {
|
||||
error = -EINVAL;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int check_address_space_support(struct nnt_device* nnt_device)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if ((!nnt_device->pciconf_device.vendor_specific_capability) || (!nnt_device->pci_device)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get semaphore ticket */
|
||||
error = lock_vsec_semaphore(nnt_device);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Is ICMD address space supported ?*/
|
||||
if(set_address_space(nnt_device, ADDRESS_SPACE_ICMD) == 0) {
|
||||
nnt_device->pciconf_device.address_space.icmd = 1;
|
||||
}
|
||||
|
||||
/* Is CR Space address space supported ?*/
|
||||
if(set_address_space(nnt_device, ADDRESS_SPACE_CR_SPACE) == 0) {
|
||||
nnt_device->pciconf_device.address_space.cr_space = 1;
|
||||
}
|
||||
|
||||
/* Is semaphore address space supported ?*/
|
||||
if(set_address_space(nnt_device, ADDRESS_SPACE_SEMAPHORE) == 0) {
|
||||
nnt_device->pciconf_device.address_space.semaphore = 1;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
/* Clear semaphore. */
|
||||
clear_vsec_semaphore(nnt_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int set_rw_address(unsigned int* offset, unsigned int rw)
|
||||
{
|
||||
u32 address = *offset;
|
||||
|
||||
/* Last 2 bits must be zero as we only allow 30 bits addresses. */
|
||||
if (EXTRACT(address, 30,
|
||||
2)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
address = MERGE(address, rw,
|
||||
PCI_FLAG_BIT_OFFSET, 1);
|
||||
*offset = address;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int read(struct nnt_device* nnt_device, unsigned int offset,
|
||||
unsigned int* data)
|
||||
{
|
||||
int error = set_rw_address(&offset, READ_OPERATION);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Write address. */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_offset,
|
||||
offset);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_offset,
|
||||
offset);
|
||||
|
||||
error = wait_on_flag(nnt_device, 1);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Read data. */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_offset,
|
||||
data);
|
||||
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.data_offset);
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int read_pciconf(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation)
|
||||
{
|
||||
int counter = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Lock semaphore. */
|
||||
error = lock_vsec_semaphore(nnt_device);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Is CR Space address space supported ?*/
|
||||
error = set_address_space(nnt_device, read_operation->address_space);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
for (counter = 0; counter < read_operation->size; counter += 4) {
|
||||
if (read(nnt_device, read_operation->offset + counter,
|
||||
&read_operation->data[counter >> 2])) {
|
||||
error = counter;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
/* Clear semaphore. */
|
||||
clear_vsec_semaphore(nnt_device);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int write(struct nnt_device* nnt_device, unsigned int offset,
|
||||
unsigned int data)
|
||||
{
|
||||
int error = set_rw_address(&offset, WRITE_OPERATION);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Write data. */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_offset,
|
||||
data);
|
||||
CHECK_PCI_WRITE_ERROR(error,nnt_device->pciconf_device.data_offset,
|
||||
data);
|
||||
|
||||
/* Write address. */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_offset,
|
||||
offset);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_offset,
|
||||
offset);
|
||||
|
||||
error = wait_on_flag(nnt_device, 0);
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int write_pciconf(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation)
|
||||
{
|
||||
int counter = 0;
|
||||
int error = 0;
|
||||
|
||||
/* Lock semaphore. */
|
||||
error = lock_vsec_semaphore(nnt_device);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
/* Is CR Space address space supported ?*/
|
||||
error = set_address_space(nnt_device, write_operation->address_space);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
for (counter = 0; counter < write_operation->size; counter += 4) {
|
||||
if (write(nnt_device, write_operation->offset + counter,
|
||||
write_operation->data[counter >> 2])) {
|
||||
error = counter;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
/* Clear semaphore. */
|
||||
clear_vsec_semaphore(nnt_device);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int address_space_to_capability(u_int16_t address_space)
|
||||
{
|
||||
switch (address_space) {
|
||||
case NNT_SPACE_ICMD:
|
||||
return NNT_VSEC_ICMD_SPACE_SUPPORTED;
|
||||
case NNT_SPACE_CR_SPACE:
|
||||
return NNT_VSEC_CRSPACE_SPACE_SUPPORTED;
|
||||
case NNT_SPACE_ALL_ICMD:
|
||||
return NNT_VSEC_ALL_ICMD_SPACE_SUPPORTED;
|
||||
case NNT_SPACE_NODNIC_INIT_SEG:
|
||||
return NNT_VSEC_NODNIC_INIT_SEG_SPACE_SUPPORTED;
|
||||
case NNT_SPACE_EXPANSION_ROM:
|
||||
return NNT_VSEC_EXPANSION_ROM_SPACE_SUPPORTED;
|
||||
case NNT_SPACE_ND_CR_SPACE:
|
||||
return NNT_VSEC_ND_CRSPACE_SPACE_SUPPORTED;
|
||||
case NNT_SPACE_SCAN_CR_SPACE:
|
||||
return NNT_VSEC_SCAN_CRSPACE_SPACE_SUPPORTED;
|
||||
case NNT_SPACE_GLOBAL_SEMAPHORE:
|
||||
return NNT_VSEC_GLOBAL_SEMAPHORE_SPACE_SUPPORTED;
|
||||
case NNT_SPACE_MAC:
|
||||
return NNT_VSEC_MAC_SPACE_SUPPORTED;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int get_space_support_status(struct nnt_device* nnt_device, u_int16_t address_space)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if(set_address_space(nnt_device, address_space) == 0) {
|
||||
status = 1;
|
||||
}
|
||||
|
||||
nnt_device->pciconf_device.vsec_capability_mask |=
|
||||
(status << address_space_to_capability(address_space));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int init_vsec_capability_mask(struct nnt_device* nnt_device)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* Lock semaphore. */
|
||||
error = lock_vsec_semaphore(nnt_device);
|
||||
CHECK_ERROR(error);
|
||||
|
||||
get_space_support_status(nnt_device, NNT_SPACE_ICMD);
|
||||
get_space_support_status(nnt_device, NNT_SPACE_CR_SPACE);
|
||||
get_space_support_status(nnt_device, NNT_SPACE_ALL_ICMD);
|
||||
get_space_support_status(nnt_device, NNT_SPACE_NODNIC_INIT_SEG);
|
||||
get_space_support_status(nnt_device, NNT_SPACE_EXPANSION_ROM);
|
||||
get_space_support_status(nnt_device, NNT_SPACE_ND_CR_SPACE);
|
||||
get_space_support_status(nnt_device, NNT_SPACE_SCAN_CR_SPACE);
|
||||
get_space_support_status(nnt_device, NNT_SPACE_GLOBAL_SEMAPHORE);
|
||||
get_space_support_status(nnt_device, NNT_SPACE_MAC);
|
||||
nnt_device->pciconf_device.vsec_capability_mask |= (1 << NNT_VSEC_INITIALIZED);
|
||||
|
||||
ReturnOnFinished:
|
||||
/* Clear semaphore. */
|
||||
clear_vsec_semaphore(nnt_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void check_vsec_minimum_support(struct nnt_device* nnt_device)
|
||||
{
|
||||
if ((nnt_device->pciconf_device.vsec_capability_mask & (1 << NNT_VSEC_INITIALIZED)) &&
|
||||
(nnt_device->pciconf_device.vsec_capability_mask & (1 << NNT_VSEC_ICMD_SPACE_SUPPORTED)) &&
|
||||
(nnt_device->pciconf_device.vsec_capability_mask & (1 << NNT_VSEC_CRSPACE_SPACE_SUPPORTED)) &&
|
||||
(nnt_device->pciconf_device.vsec_capability_mask & (1 << NNT_VSEC_GLOBAL_SEMAPHORE_SPACE_SUPPORTED))) {
|
||||
|
||||
nnt_device->pciconf_device.vsec_fully_supported = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int init_pciconf(struct nnt_device* nnt_device)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
nnt_device->pciconf_device.semaphore_offset =
|
||||
nnt_device->pciconf_device.vendor_specific_capability + PCI_SEMAPHORE_OFFSET;
|
||||
nnt_device->pciconf_device.data_offset =
|
||||
nnt_device->pciconf_device.vendor_specific_capability + PCI_DATA_OFFSET;
|
||||
nnt_device->pciconf_device.address_offset =
|
||||
nnt_device->pciconf_device.vendor_specific_capability + PCI_ADDRESS_OFFSET;
|
||||
|
||||
error = init_vsec_capability_mask(nnt_device);
|
||||
check_vsec_minimum_support(nnt_device);
|
||||
|
||||
return error;
|
||||
}
|
||||
14
drivers/net/ethernet/mft/nnt_driver/nnt_pci_conf_access.h
Normal file
14
drivers/net/ethernet/mft/nnt_driver/nnt_pci_conf_access.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef NNT_PCICONF_H
|
||||
#define NNT_PCICONF_H
|
||||
|
||||
#include "nnt_device_defs.h"
|
||||
#include "nnt_ioctl_defs.h"
|
||||
|
||||
|
||||
int read_pciconf(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation);
|
||||
int write_pciconf(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation);
|
||||
int init_pciconf(struct nnt_device* nnt_device);
|
||||
int read_dword(struct nnt_read_dword_from_config_space* read_from_cspace, struct nnt_device* nnt_device);
|
||||
int check_address_space_support(struct nnt_device* nnt_device);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef NNT_PCICONF_DEFS_H
|
||||
#define NNT_PCICONF_DEFS_H
|
||||
|
||||
#define ADDRESS_SPACE_CR_SPACE 0x2
|
||||
#define ADDRESS_SPACE_ICMD 0x3
|
||||
#define ADDRESS_SPACE_SEMAPHORE 0xa
|
||||
|
||||
#define PCI_CONTROL_OFFSET 0x04
|
||||
#define PCI_COUNTER_OFFSET 0x08
|
||||
|
||||
#define SEMAPHORE_MAX_RETRIES 0x1000
|
||||
|
||||
#define PCI_SPACE_BIT_OFFSET 0
|
||||
#define PCI_SPACE_BIT_LENGTH 16
|
||||
#define PCI_STATUS_BIT_OFFSET 29
|
||||
#define PCI_STATUS_BIT_LEN 3
|
||||
#define PCI_FLAG_BIT_OFFSET 31
|
||||
|
||||
#define READ_OPERATION 0
|
||||
#define WRITE_OPERATION 1
|
||||
|
||||
#define IFC_MAX_RETRIES 0x10000
|
||||
#define SEMAPHORE_MAX_RETRIES 0x1000
|
||||
|
||||
|
||||
typedef enum nnt_space_address {
|
||||
NNT_SPACE_ICMD = 0x1,
|
||||
NNT_SPACE_CR_SPACE = 0x2,
|
||||
NNT_SPACE_ALL_ICMD = 0x3,
|
||||
NNT_SPACE_NODNIC_INIT_SEG = 0x4,
|
||||
NNT_SPACE_EXPANSION_ROM = 0x5,
|
||||
NNT_SPACE_ND_CR_SPACE = 0x6,
|
||||
NNT_SPACE_SCAN_CR_SPACE = 0x7,
|
||||
NNT_SPACE_GLOBAL_SEMAPHORE = 0xa,
|
||||
NNT_SPACE_MAC = 0xf
|
||||
} NNT_SPACE_ADDRESS;
|
||||
|
||||
|
||||
typedef enum nnt_vsec_capability {
|
||||
NNT_VSEC_INITIALIZED = 0,
|
||||
NNT_VSEC_ICMD_SPACE_SUPPORTED,
|
||||
NNT_VSEC_CRSPACE_SPACE_SUPPORTED,
|
||||
NNT_VSEC_ALL_ICMD_SPACE_SUPPORTED,
|
||||
NNT_VSEC_NODNIC_INIT_SEG_SPACE_SUPPORTED,
|
||||
NNT_VSEC_EXPANSION_ROM_SPACE_SUPPORTED,
|
||||
NNT_VSEC_ND_CRSPACE_SPACE_SUPPORTED,
|
||||
NNT_VSEC_SCAN_CRSPACE_SPACE_SUPPORTED,
|
||||
NNT_VSEC_GLOBAL_SEMAPHORE_SPACE_SUPPORTED,
|
||||
NNT_VSEC_MAC_SPACE_SUPPORTED,
|
||||
} NNT_VSEC_CAPABILITY;
|
||||
|
||||
|
||||
// BIT Slicing macros
|
||||
#define ONES32(size) ((size)?(0xffffffff>>(32-(size))):0)
|
||||
#define MASK32(offset, size) ( ONES32(size)<<(offset))
|
||||
|
||||
#define EXTRACT_C(source, offset, size) ((((unsigned int)(source))>>(offset)) & ONES32(size))
|
||||
#define EXTRACT(src, start, len) (((len) == 32)?(src):EXTRACT_C(src, start, len))
|
||||
|
||||
#define MERGE_C(rsrc1, rsrc2, start, len) ((((rsrc2)<<(start)) & (MASK32((start), (len)))) | ((rsrc1) & (~MASK32((start), (len)))))
|
||||
#define MERGE(rsrc1, rsrc2, start, len) (((len) == 32)?(rsrc2):MERGE_C(rsrc1, rsrc2, start, len))
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "nnt_device_defs.h"
|
||||
#include "nnt_pci_conf_access_no_vsec.h"
|
||||
#include "nnt_defs.h"
|
||||
|
||||
|
||||
int read_no_vsec(struct nnt_device* nnt_device, unsigned int offset,
|
||||
unsigned int* data)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (nnt_device->wo_address) {
|
||||
offset |= 0x1;
|
||||
}
|
||||
|
||||
/* Write the wanted address to address register. */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||
offset);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_register,
|
||||
offset);
|
||||
|
||||
/* Read the result from data register */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_register,
|
||||
data);
|
||||
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.data_register);
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int read_pciconf_no_vsec(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation)
|
||||
{
|
||||
int counter = 0;
|
||||
int error = 0;
|
||||
|
||||
for (counter = 0; counter < read_operation->size; counter += 4) {
|
||||
if (read_no_vsec(nnt_device, read_operation->offset + counter,
|
||||
&read_operation->data[counter >> 2])) {
|
||||
error = counter;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int write_no_vsec(struct nnt_device* nnt_device, unsigned int offset,
|
||||
unsigned int data)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (nnt_device->wo_address) {
|
||||
/* write the data to the data register. */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_register,
|
||||
data);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.data_register,
|
||||
data);
|
||||
/* Write the destination address to address register. */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||
offset);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_register,
|
||||
offset);
|
||||
} else {
|
||||
/* Write the destination address to address register. */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||
offset);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_register,
|
||||
offset);
|
||||
|
||||
/* write the data to the data register. */
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_register,
|
||||
data);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.data_register,
|
||||
data);
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int write_pciconf_no_vsec(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation)
|
||||
{
|
||||
int counter = 0;
|
||||
int error = 0;
|
||||
|
||||
for (counter = 0; counter < write_operation->size; counter += 4) {
|
||||
if (write_no_vsec(nnt_device, write_operation->offset + counter,
|
||||
write_operation->data[counter >> 2])) {
|
||||
error = counter;
|
||||
goto ReturnOnFinished;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int is_wo_gw(struct nnt_device* nnt_device)
|
||||
{
|
||||
unsigned int data = 0;
|
||||
int error = 0;
|
||||
|
||||
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||
NNT_DEVICE_ID_OFFSET);
|
||||
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_register,
|
||||
NNT_DEVICE_ID_OFFSET);
|
||||
|
||||
/* Read the result from data register */
|
||||
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||
&data);
|
||||
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.address_register);
|
||||
|
||||
if (data == NNT_WO_REG_ADDR_DATA) {
|
||||
error = 1;
|
||||
}
|
||||
|
||||
ReturnOnFinished:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int init_pciconf_no_vsec(struct nnt_device* nnt_device)
|
||||
{
|
||||
nnt_device->pciconf_device.address_register = NNT_CONF_ADDRES_REGISETER;
|
||||
nnt_device->pciconf_device.data_register = NNT_CONF_DATA_REGISTER;
|
||||
nnt_device->wo_address = is_wo_gw(nnt_device);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef NNT_PCICONF_NO_VSEC_H
|
||||
#define NNT_PCICONF_NO_VSEC_H
|
||||
|
||||
#include "nnt_device_defs.h"
|
||||
#include "nnt_ioctl_defs.h"
|
||||
|
||||
|
||||
int read_pciconf_no_vsec(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation);
|
||||
int write_pciconf_no_vsec(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation);
|
||||
int init_pciconf_no_vsec(struct nnt_device* nnt_device);
|
||||
|
||||
#endif
|
||||
38
drivers/net/ethernet/mft/nnt_driver/nnt_ppc_device_list.h
Normal file
38
drivers/net/ethernet/mft/nnt_driver/nnt_ppc_device_list.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef NNT_DEVICE_LIST_H
|
||||
#define NNT_DEVICE_LIST_H
|
||||
|
||||
#include "nnt_device_defs.h"
|
||||
|
||||
static struct pci_device_id pciconf_devices[] = {{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX3_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX3PRO_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTIB_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX4_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX4LX_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX5_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX5EX_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX6_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX6DX_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX6LX_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX7_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX8_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SCHRODINGER_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, FREYSA_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BLUEFIELD_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BLUEFIELD2_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BLUEFIELD3_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BLUEFIELD4_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SWITCHIB_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SWITCHIB2_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, QUANTUM_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, QUANTUM2_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, QUANTUM3_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SPECTRUM_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SPECTRUM2_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SPECTRUM3_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SPECTRUM4_PCI_ID)},
|
||||
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BW00_PCI_ID)},
|
||||
{
|
||||
0,
|
||||
}};
|
||||
|
||||
#endif // NNT_DEVICE_LIST_H
|
||||
26
drivers/net/ethernet/mft/nnt_driver/nnt_ppc_driver_defs.h
Normal file
26
drivers/net/ethernet/mft/nnt_driver/nnt_ppc_driver_defs.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef NNT_DRIVER_PPC_H
|
||||
#define NNT_DRIVER_PPC_H
|
||||
|
||||
LIST_HEAD(nnt_device_list);
|
||||
|
||||
#define NNT_MAXIMUM_DEVICE_NAME_LENGTH 128
|
||||
#define NNT_MAXIMUM_NUMBER_OF_DEVICES 8
|
||||
#define NNT_MAXIMUM_POLLING_NUMBER 100
|
||||
#define NNT_UNKNOWN_DEVICE_ID 0xffff
|
||||
#define NNT_MINIMUM_WAITING_TIME 100
|
||||
#define NNT_DEVICE_LIST_SIZE NNT_MAXIMUM_DEVICE_NAME_LENGTH * NNT_MAXIMUM_NUMBER_OF_DEVICES
|
||||
|
||||
struct nnt_ppc_device {
|
||||
struct list_head entry;
|
||||
struct pci_dev* pci_device;
|
||||
char* pci_device_dbdf_name;
|
||||
};
|
||||
|
||||
|
||||
struct nnt_ppc_reset_info {
|
||||
unsigned int number_of_found_pci_device;
|
||||
unsigned int number_of_requested_pci_device;
|
||||
int reset_was_done;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user