Newer
Older

Laura Rientsma
committed
This is the network driver for host side
to create a network interface over PCIe

Laura Rientsma
committed
1. Finds a FLX-182 PCIe card (vendor=0x10dc, device=0x0427)
2. Enables the PCIe device, reserve and map the BAR if BAR #3 is available
3. Register the peer with flxnet network device

Laura Rientsma
committed
4. Repeats untill all the PCIe devices available are configured with a network interface
5. If BAR #3 is not available, does nothing
*/
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
extern struct flxnet_peer * flxnet_add_peer(void* __iomem base_address,
int index, struct module *owner);
#define DRV_MODULE_NAME "flxnet_pcie"
#define FLX_PCIE_MAGIC 0xDED133D0UL

Laura Rientsma
committed
unsigned long magic; // structure ID for sanity checks

Laura Rientsma
committed
struct pci_dev *pdev; // pci device struct from probe()
void __iomem *bar; // addresses for the relevant BAR

Laura Rientsma
committed
spinlock_t lock; // protects concurrent access
unsigned int flags;
struct flxnet_peer * peer;
};

Frans Schreuder
committed
static int bar_idx = 3;
static int configure_pcie_device(struct pci_dev *pdev, int index);
static void deconfigure_device(struct pcie_flx_serial_device *fdev);
static int map_single_bar(struct pcie_flx_serial_device *fdev, int idx);
int index = 0;
int rv = -ENODEV;

Laura Rientsma
committed
struct pci_dev *pdev; // previous device

Laura Rientsma
committed
pdev = NULL; // a new search for PCI devices is initiated by passing NULL as the pdev argument

Laura Rientsma
committed
pr_info("flxnet_pcie: loading %s module\n", DRV_MODULE_NAME);

Laura Rientsma
committed
// if a PCI device is found, a pointer to its device structure is returned
pdev = pci_get_device(0x10dc, 0x0427, pdev);
// pdev returns NULL when all the PCI devices are found and stops searching
while (pdev != NULL) {

Laura Rientsma
committed
pr_info("flxnet_pcie: found %s with index %d\n", pci_name(pdev), index);

Laura Rientsma
committed
rv = configure_pcie_device(pdev, index);

Laura Rientsma
committed
if (rv < 0) {

Laura Rientsma
committed
pr_warn("flxnet_pcie: failed to configure %s\n", pci_name(pdev));

Laura Rientsma
committed
}
pdev = pci_get_device(0x10dc, 0x0427, pdev);
index++;
if (pdev == NULL) {

Laura Rientsma
committed
pr_info("flxnet_pcie: no more pcie devices found\n");

Laura Rientsma
committed
// deconfigure pcie devices if necessary, remove module

Laura Rientsma
committed
pr_info("flxnet_pcie: removing %s module\n", DRV_MODULE_NAME);

Laura Rientsma
committed
pr_info("flxnet_pcie: list not empty - deconfiguring PCIe devices\n");

Laura Rientsma
committed
else {
pr_info("flxnet_pcie: list is empty - nothing to deconfigure\n");
}
static int configure_pcie_device(struct pci_dev *pdev, int index) {
int rv;
struct pcie_flx_serial_device *fdev;
if (!pdev) {

Laura Rientsma
committed
pr_err("flxnet_pcie: invalid PCIe device structure\n");

Laura Rientsma
committed
pr_info("flxnet_pcie: initializing the PCIe device\n");
fdev = kzalloc(sizeof(struct pcie_flx_serial_device), GFP_KERNEL);
if (!fdev)
return -ENOMEM;
spin_lock_init(&fdev->lock);
fdev->magic = FLX_PCIE_MAGIC;
fdev->pdev = pdev;
fdev->bar_idx = bar_idx;

Laura Rientsma
committed
pr_info("flxnet_pcie: enabling PCIe device\n");

Laura Rientsma
committed
pr_err("flxnet_pcie: pci_enable_device() failed, %d\n", rv);
goto err_enable;
}
// reserve the selected bar for this driver

Laura Rientsma
committed
pr_info("flxnet_pcie: reserving BAR memory\n");
rv = pci_request_region(pdev, bar_idx, DRV_MODULE_NAME);
if (rv) {

Laura Rientsma
committed
pr_err("flxnet_pcie: pci_request_region() failed (%d)\n", rv);

Laura Rientsma
committed
pr_info("flxnet_pcie: mapping BAR memory\n");

Laura Rientsma
committed
goto warn_nobar;

Laura Rientsma
committed
pr_err("flxnet_pcie: mapped region is too small (%d bytes < %d)\n",
rv, MIN_MMAP_SIZE);
goto err_peer;
}
// add this device to the network

Laura Rientsma
committed
pr_info("flxnet_pcie: inserting peer into flxnet\n");

Laura Rientsma
committed
pr_err("flxnet_pcie: error inserting peer into flxnet\n");
goto err_peer;
}
// device structure
list_add(&fdev->list_head, &flx_devices);

Laura Rientsma
committed
pr_info("flxnet_pcie: added peer to list flx_devices\n");

Laura Rientsma
committed
warn_nobar:
pr_warn("flxnet_pcie: no network registered, disabling PCI device\n");
pci_disable_device(pdev);
pci_release_region(pdev, bar_idx);
return 0;

Laura Rientsma
committed
pr_info("flxnet_pcie: unmapping BAR memory\n");

Laura Rientsma
committed
pr_err("flxnet_pcie: pdev 0x%p, err %d\n", pdev, rv);
kfree(fdev);
return rv;
err_region:
pci_disable_device(pdev);
goto err_enable;
}

Laura Rientsma
committed
// unregister and deconfigure a felix serial device
static void deconfigure_device(struct pcie_flx_serial_device *fdev) {
struct pci_dev * pdev;

Laura Rientsma
committed
pr_info("flxnet_pcie: deconfiguring device %p\n", fdev);

Laura Rientsma
committed
pr_err("flxnet_pcie: felix_flx_serial_device ptr is NULL\n");
return;
}
if (fdev->magic != FLX_PCIE_MAGIC) {

Laura Rientsma
committed
pr_err("flxnet_pcie: incorrect MAGIC value in deconfigure_device()\n");
return;
}
pdev = fdev->pdev;
if (!pdev) {

Laura Rientsma
committed
pr_err("flxnet_pcie: pci_dev ptr is NULL\n");
goto err_exit;
}
if (fdev->bar) {
pci_iounmap(pdev, fdev->bar);
} else {

Laura Rientsma
committed
pr_err("flxnet_pcie: BAR memory is not mapped\n");
}
pci_disable_device(pdev);
pci_release_region(pdev, bar_idx);
err_exit:
list_del(&fdev->list_head);
// map BAR containing the serial communication registers
static int map_single_bar(struct pcie_flx_serial_device *fdev, int idx) {
struct pci_dev *pdev = fdev->pdev;
resource_size_t bar_start = pci_resource_start(pdev, idx);
resource_size_t bar_len = pci_resource_len(pdev, idx);
resource_size_t map_len = bar_len;
fdev->bar = NULL;

Laura Rientsma
committed
// do not map BARs with length 0. Note that start MAY be 0!

Laura Rientsma
committed
pr_info("flxnet_pcie: BAR #%d is not present\n", idx);

Laura Rientsma
committed
// BAR size exceeds maximum desired mapping?

Laura Rientsma
committed
pr_info("flxnet_pcie: limit BAR %d mapping from %llu to %d bytes\n", idx,
(u64)bar_len, INT_MAX);
map_len = (resource_size_t)INT_MAX;
}

Laura Rientsma
committed
// map the full device memory or IO region into kernel virtual address space
fdev->bar = pci_iomap(pdev, idx, map_len);
if (!fdev->bar) {

Laura Rientsma
committed
pr_info("flxnet_pcie: could not map BAR %d\n", idx);

Laura Rientsma
committed
pr_info("flxnet_pcie: BAR%d at 0x%llx mapped at 0x%p, length=%llu(/%llu)\n", idx,
(u64)bar_start, fdev->bar, (u64)map_len, (u64)bar_len);
return (int)map_len;
}
module_init(flxnet_pcie_init);
module_exit(flxnet_pcie_exit);
module_param(bar_idx, int, S_IRUSR);
MODULE_PARM_DESC(bar_idx, "BAR of the FIFO AXI device");
module_param(dev_base_addr, uint, S_IRUSR);
MODULE_PARM_DESC(dev_base_addr, "Base offset of the FIFO AXI device");
MODULE_AUTHOR("Elena Zhivun <elena.zhivun@cern.ch>");

Laura Rientsma
committed
MODULE_DESCRIPTION("Driver on host PC for establishing virtual network over PCIe, registers with flxnet_dev");