root/drivers/fpga/dfl-pci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cci_pci_ioremap_bar
  2. cci_init_drvdata
  3. cci_remove_feature_devs
  4. cci_enumerate_feature_devs
  5. cci_pci_probe
  6. cci_pci_sriov_configure
  7. cci_pci_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Driver for FPGA Device Feature List (DFL) PCIe device
   4  *
   5  * Copyright (C) 2017-2018 Intel Corporation, Inc.
   6  *
   7  * Authors:
   8  *   Zhang Yi <Yi.Z.Zhang@intel.com>
   9  *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
  10  *   Joseph Grecco <joe.grecco@intel.com>
  11  *   Enno Luebbers <enno.luebbers@intel.com>
  12  *   Tim Whisonant <tim.whisonant@intel.com>
  13  *   Ananda Ravuri <ananda.ravuri@intel.com>
  14  *   Henry Mitchel <henry.mitchel@intel.com>
  15  */
  16 
  17 #include <linux/pci.h>
  18 #include <linux/types.h>
  19 #include <linux/kernel.h>
  20 #include <linux/module.h>
  21 #include <linux/stddef.h>
  22 #include <linux/errno.h>
  23 #include <linux/aer.h>
  24 
  25 #include "dfl.h"
  26 
  27 #define DRV_VERSION     "0.8"
  28 #define DRV_NAME        "dfl-pci"
  29 
  30 struct cci_drvdata {
  31         struct dfl_fpga_cdev *cdev;     /* container device */
  32 };
  33 
  34 static void __iomem *cci_pci_ioremap_bar(struct pci_dev *pcidev, int bar)
  35 {
  36         if (pcim_iomap_regions(pcidev, BIT(bar), DRV_NAME))
  37                 return NULL;
  38 
  39         return pcim_iomap_table(pcidev)[bar];
  40 }
  41 
  42 /* PCI Device ID */
  43 #define PCIE_DEVICE_ID_PF_INT_5_X       0xBCBD
  44 #define PCIE_DEVICE_ID_PF_INT_6_X       0xBCC0
  45 #define PCIE_DEVICE_ID_PF_DSC_1_X       0x09C4
  46 /* VF Device */
  47 #define PCIE_DEVICE_ID_VF_INT_5_X       0xBCBF
  48 #define PCIE_DEVICE_ID_VF_INT_6_X       0xBCC1
  49 #define PCIE_DEVICE_ID_VF_DSC_1_X       0x09C5
  50 
  51 static struct pci_device_id cci_pcie_id_tbl[] = {
  52         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X),},
  53         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X),},
  54         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X),},
  55         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_6_X),},
  56         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),},
  57         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),},
  58         {0,}
  59 };
  60 MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl);
  61 
  62 static int cci_init_drvdata(struct pci_dev *pcidev)
  63 {
  64         struct cci_drvdata *drvdata;
  65 
  66         drvdata = devm_kzalloc(&pcidev->dev, sizeof(*drvdata), GFP_KERNEL);
  67         if (!drvdata)
  68                 return -ENOMEM;
  69 
  70         pci_set_drvdata(pcidev, drvdata);
  71 
  72         return 0;
  73 }
  74 
  75 static void cci_remove_feature_devs(struct pci_dev *pcidev)
  76 {
  77         struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
  78 
  79         /* remove all children feature devices */
  80         dfl_fpga_feature_devs_remove(drvdata->cdev);
  81 }
  82 
  83 /* enumerate feature devices under pci device */
  84 static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
  85 {
  86         struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
  87         struct dfl_fpga_enum_info *info;
  88         struct dfl_fpga_cdev *cdev;
  89         resource_size_t start, len;
  90         int port_num, bar, i, ret = 0;
  91         void __iomem *base;
  92         u32 offset;
  93         u64 v;
  94 
  95         /* allocate enumeration info via pci_dev */
  96         info = dfl_fpga_enum_info_alloc(&pcidev->dev);
  97         if (!info)
  98                 return -ENOMEM;
  99 
 100         /* start to find Device Feature List from Bar 0 */
 101         base = cci_pci_ioremap_bar(pcidev, 0);
 102         if (!base) {
 103                 ret = -ENOMEM;
 104                 goto enum_info_free_exit;
 105         }
 106 
 107         /*
 108          * PF device has FME and Ports/AFUs, and VF device only has one
 109          * Port/AFU. Check them and add related "Device Feature List" info
 110          * for the next step enumeration.
 111          */
 112         if (dfl_feature_is_fme(base)) {
 113                 start = pci_resource_start(pcidev, 0);
 114                 len = pci_resource_len(pcidev, 0);
 115 
 116                 dfl_fpga_enum_info_add_dfl(info, start, len, base);
 117 
 118                 /*
 119                  * find more Device Feature Lists (e.g. Ports) per information
 120                  * indicated by FME module.
 121                  */
 122                 v = readq(base + FME_HDR_CAP);
 123                 port_num = FIELD_GET(FME_CAP_NUM_PORTS, v);
 124 
 125                 WARN_ON(port_num > MAX_DFL_FPGA_PORT_NUM);
 126 
 127                 for (i = 0; i < port_num; i++) {
 128                         v = readq(base + FME_HDR_PORT_OFST(i));
 129 
 130                         /* skip ports which are not implemented. */
 131                         if (!(v & FME_PORT_OFST_IMP))
 132                                 continue;
 133 
 134                         /*
 135                          * add Port's Device Feature List information for next
 136                          * step enumeration.
 137                          */
 138                         bar = FIELD_GET(FME_PORT_OFST_BAR_ID, v);
 139                         offset = FIELD_GET(FME_PORT_OFST_DFH_OFST, v);
 140                         base = cci_pci_ioremap_bar(pcidev, bar);
 141                         if (!base)
 142                                 continue;
 143 
 144                         start = pci_resource_start(pcidev, bar) + offset;
 145                         len = pci_resource_len(pcidev, bar) - offset;
 146 
 147                         dfl_fpga_enum_info_add_dfl(info, start, len,
 148                                                    base + offset);
 149                 }
 150         } else if (dfl_feature_is_port(base)) {
 151                 start = pci_resource_start(pcidev, 0);
 152                 len = pci_resource_len(pcidev, 0);
 153 
 154                 dfl_fpga_enum_info_add_dfl(info, start, len, base);
 155         } else {
 156                 ret = -ENODEV;
 157                 goto enum_info_free_exit;
 158         }
 159 
 160         /* start enumeration with prepared enumeration information */
 161         cdev = dfl_fpga_feature_devs_enumerate(info);
 162         if (IS_ERR(cdev)) {
 163                 dev_err(&pcidev->dev, "Enumeration failure\n");
 164                 ret = PTR_ERR(cdev);
 165                 goto enum_info_free_exit;
 166         }
 167 
 168         drvdata->cdev = cdev;
 169 
 170 enum_info_free_exit:
 171         dfl_fpga_enum_info_free(info);
 172 
 173         return ret;
 174 }
 175 
 176 static
 177 int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
 178 {
 179         int ret;
 180 
 181         ret = pcim_enable_device(pcidev);
 182         if (ret < 0) {
 183                 dev_err(&pcidev->dev, "Failed to enable device %d.\n", ret);
 184                 return ret;
 185         }
 186 
 187         ret = pci_enable_pcie_error_reporting(pcidev);
 188         if (ret && ret != -EINVAL)
 189                 dev_info(&pcidev->dev, "PCIE AER unavailable %d.\n", ret);
 190 
 191         pci_set_master(pcidev);
 192 
 193         if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(64))) {
 194                 ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64));
 195                 if (ret)
 196                         goto disable_error_report_exit;
 197         } else if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(32))) {
 198                 ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
 199                 if (ret)
 200                         goto disable_error_report_exit;
 201         } else {
 202                 ret = -EIO;
 203                 dev_err(&pcidev->dev, "No suitable DMA support available.\n");
 204                 goto disable_error_report_exit;
 205         }
 206 
 207         ret = cci_init_drvdata(pcidev);
 208         if (ret) {
 209                 dev_err(&pcidev->dev, "Fail to init drvdata %d.\n", ret);
 210                 goto disable_error_report_exit;
 211         }
 212 
 213         ret = cci_enumerate_feature_devs(pcidev);
 214         if (ret) {
 215                 dev_err(&pcidev->dev, "enumeration failure %d.\n", ret);
 216                 goto disable_error_report_exit;
 217         }
 218 
 219         return ret;
 220 
 221 disable_error_report_exit:
 222         pci_disable_pcie_error_reporting(pcidev);
 223         return ret;
 224 }
 225 
 226 static int cci_pci_sriov_configure(struct pci_dev *pcidev, int num_vfs)
 227 {
 228         struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
 229         struct dfl_fpga_cdev *cdev = drvdata->cdev;
 230         int ret = 0;
 231 
 232         if (!num_vfs) {
 233                 /*
 234                  * disable SRIOV and then put released ports back to default
 235                  * PF access mode.
 236                  */
 237                 pci_disable_sriov(pcidev);
 238 
 239                 dfl_fpga_cdev_config_ports_pf(cdev);
 240 
 241         } else {
 242                 /*
 243                  * before enable SRIOV, put released ports into VF access mode
 244                  * first of all.
 245                  */
 246                 ret = dfl_fpga_cdev_config_ports_vf(cdev, num_vfs);
 247                 if (ret)
 248                         return ret;
 249 
 250                 ret = pci_enable_sriov(pcidev, num_vfs);
 251                 if (ret) {
 252                         dfl_fpga_cdev_config_ports_pf(cdev);
 253                         return ret;
 254                 }
 255         }
 256 
 257         return num_vfs;
 258 }
 259 
 260 static void cci_pci_remove(struct pci_dev *pcidev)
 261 {
 262         if (dev_is_pf(&pcidev->dev))
 263                 cci_pci_sriov_configure(pcidev, 0);
 264 
 265         cci_remove_feature_devs(pcidev);
 266         pci_disable_pcie_error_reporting(pcidev);
 267 }
 268 
 269 static struct pci_driver cci_pci_driver = {
 270         .name = DRV_NAME,
 271         .id_table = cci_pcie_id_tbl,
 272         .probe = cci_pci_probe,
 273         .remove = cci_pci_remove,
 274         .sriov_configure = cci_pci_sriov_configure,
 275 };
 276 
 277 module_pci_driver(cci_pci_driver);
 278 
 279 MODULE_DESCRIPTION("FPGA DFL PCIe Device Driver");
 280 MODULE_AUTHOR("Intel Corporation");
 281 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */