Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for FPGA Device Feature List (DFL) PCIe device
0004  *
0005  * Copyright (C) 2017-2018 Intel Corporation, Inc.
0006  *
0007  * Authors:
0008  *   Zhang Yi <Yi.Z.Zhang@intel.com>
0009  *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
0010  *   Joseph Grecco <joe.grecco@intel.com>
0011  *   Enno Luebbers <enno.luebbers@intel.com>
0012  *   Tim Whisonant <tim.whisonant@intel.com>
0013  *   Ananda Ravuri <ananda.ravuri@intel.com>
0014  *   Henry Mitchel <henry.mitchel@intel.com>
0015  */
0016 
0017 #include <linux/pci.h>
0018 #include <linux/dma-mapping.h>
0019 #include <linux/types.h>
0020 #include <linux/kernel.h>
0021 #include <linux/module.h>
0022 #include <linux/stddef.h>
0023 #include <linux/errno.h>
0024 #include <linux/aer.h>
0025 
0026 #include "dfl.h"
0027 
0028 #define DRV_VERSION "0.8"
0029 #define DRV_NAME    "dfl-pci"
0030 
0031 #define PCI_VSEC_ID_INTEL_DFLS 0x43
0032 
0033 #define PCI_VNDR_DFLS_CNT 0x8
0034 #define PCI_VNDR_DFLS_RES 0xc
0035 
0036 #define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0)
0037 #define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
0038 
0039 struct cci_drvdata {
0040     struct dfl_fpga_cdev *cdev; /* container device */
0041 };
0042 
0043 static void __iomem *cci_pci_ioremap_bar0(struct pci_dev *pcidev)
0044 {
0045     if (pcim_iomap_regions(pcidev, BIT(0), DRV_NAME))
0046         return NULL;
0047 
0048     return pcim_iomap_table(pcidev)[0];
0049 }
0050 
0051 static int cci_pci_alloc_irq(struct pci_dev *pcidev)
0052 {
0053     int ret, nvec = pci_msix_vec_count(pcidev);
0054 
0055     if (nvec <= 0) {
0056         dev_dbg(&pcidev->dev, "fpga interrupt not supported\n");
0057         return 0;
0058     }
0059 
0060     ret = pci_alloc_irq_vectors(pcidev, nvec, nvec, PCI_IRQ_MSIX);
0061     if (ret < 0)
0062         return ret;
0063 
0064     return nvec;
0065 }
0066 
0067 static void cci_pci_free_irq(struct pci_dev *pcidev)
0068 {
0069     pci_free_irq_vectors(pcidev);
0070 }
0071 
0072 /* PCI Device ID */
0073 #define PCIE_DEVICE_ID_PF_INT_5_X       0xBCBD
0074 #define PCIE_DEVICE_ID_PF_INT_6_X       0xBCC0
0075 #define PCIE_DEVICE_ID_PF_DSC_1_X       0x09C4
0076 #define PCIE_DEVICE_ID_INTEL_PAC_N3000      0x0B30
0077 #define PCIE_DEVICE_ID_INTEL_PAC_D5005      0x0B2B
0078 #define PCIE_DEVICE_ID_SILICOM_PAC_N5010    0x1000
0079 #define PCIE_DEVICE_ID_SILICOM_PAC_N5011    0x1001
0080 
0081 /* VF Device */
0082 #define PCIE_DEVICE_ID_VF_INT_5_X       0xBCBF
0083 #define PCIE_DEVICE_ID_VF_INT_6_X       0xBCC1
0084 #define PCIE_DEVICE_ID_VF_DSC_1_X       0x09C5
0085 #define PCIE_DEVICE_ID_INTEL_PAC_D5005_VF   0x0B2C
0086 
0087 static struct pci_device_id cci_pcie_id_tbl[] = {
0088     {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X),},
0089     {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X),},
0090     {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X),},
0091     {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_6_X),},
0092     {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),},
0093     {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),},
0094     {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),},
0095     {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005),},
0096     {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),},
0097     {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5010),},
0098     {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5011),},
0099     {0,}
0100 };
0101 MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl);
0102 
0103 static int cci_init_drvdata(struct pci_dev *pcidev)
0104 {
0105     struct cci_drvdata *drvdata;
0106 
0107     drvdata = devm_kzalloc(&pcidev->dev, sizeof(*drvdata), GFP_KERNEL);
0108     if (!drvdata)
0109         return -ENOMEM;
0110 
0111     pci_set_drvdata(pcidev, drvdata);
0112 
0113     return 0;
0114 }
0115 
0116 static void cci_remove_feature_devs(struct pci_dev *pcidev)
0117 {
0118     struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
0119 
0120     /* remove all children feature devices */
0121     dfl_fpga_feature_devs_remove(drvdata->cdev);
0122     cci_pci_free_irq(pcidev);
0123 }
0124 
0125 static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec)
0126 {
0127     unsigned int i;
0128     int *table;
0129 
0130     table = kcalloc(nvec, sizeof(int), GFP_KERNEL);
0131     if (!table)
0132         return table;
0133 
0134     for (i = 0; i < nvec; i++)
0135         table[i] = pci_irq_vector(pcidev, i);
0136 
0137     return table;
0138 }
0139 
0140 static int find_dfls_by_vsec(struct pci_dev *pcidev, struct dfl_fpga_enum_info *info)
0141 {
0142     u32 bir, offset, vndr_hdr, dfl_cnt, dfl_res;
0143     int dfl_res_off, i, bars, voff = 0;
0144     resource_size_t start, len;
0145 
0146     while ((voff = pci_find_next_ext_capability(pcidev, voff, PCI_EXT_CAP_ID_VNDR))) {
0147         vndr_hdr = 0;
0148         pci_read_config_dword(pcidev, voff + PCI_VNDR_HEADER, &vndr_hdr);
0149 
0150         if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VSEC_ID_INTEL_DFLS &&
0151             pcidev->vendor == PCI_VENDOR_ID_INTEL)
0152             break;
0153     }
0154 
0155     if (!voff) {
0156         dev_dbg(&pcidev->dev, "%s no DFL VSEC found\n", __func__);
0157         return -ENODEV;
0158     }
0159 
0160     dfl_cnt = 0;
0161     pci_read_config_dword(pcidev, voff + PCI_VNDR_DFLS_CNT, &dfl_cnt);
0162     if (dfl_cnt > PCI_STD_NUM_BARS) {
0163         dev_err(&pcidev->dev, "%s too many DFLs %d > %d\n",
0164             __func__, dfl_cnt, PCI_STD_NUM_BARS);
0165         return -EINVAL;
0166     }
0167 
0168     dfl_res_off = voff + PCI_VNDR_DFLS_RES;
0169     if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
0170         dev_err(&pcidev->dev, "%s DFL VSEC too big for PCIe config space\n",
0171             __func__);
0172         return -EINVAL;
0173     }
0174 
0175     for (i = 0, bars = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
0176         dfl_res = GENMASK(31, 0);
0177         pci_read_config_dword(pcidev, dfl_res_off, &dfl_res);
0178 
0179         bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
0180         if (bir >= PCI_STD_NUM_BARS) {
0181             dev_err(&pcidev->dev, "%s bad bir number %d\n",
0182                 __func__, bir);
0183             return -EINVAL;
0184         }
0185 
0186         if (bars & BIT(bir)) {
0187             dev_err(&pcidev->dev, "%s DFL for BAR %d already specified\n",
0188                 __func__, bir);
0189             return -EINVAL;
0190         }
0191 
0192         bars |= BIT(bir);
0193 
0194         len = pci_resource_len(pcidev, bir);
0195         offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
0196         if (offset >= len) {
0197             dev_err(&pcidev->dev, "%s bad offset %u >= %pa\n",
0198                 __func__, offset, &len);
0199             return -EINVAL;
0200         }
0201 
0202         dev_dbg(&pcidev->dev, "%s BAR %d offset 0x%x\n", __func__, bir, offset);
0203 
0204         len -= offset;
0205 
0206         start = pci_resource_start(pcidev, bir) + offset;
0207 
0208         dfl_fpga_enum_info_add_dfl(info, start, len);
0209     }
0210 
0211     return 0;
0212 }
0213 
0214 /* default method of finding dfls starting at offset 0 of bar 0 */
0215 static int find_dfls_by_default(struct pci_dev *pcidev,
0216                 struct dfl_fpga_enum_info *info)
0217 {
0218     int port_num, bar, i, ret = 0;
0219     resource_size_t start, len;
0220     void __iomem *base;
0221     u32 offset;
0222     u64 v;
0223 
0224     /* start to find Device Feature List from Bar 0 */
0225     base = cci_pci_ioremap_bar0(pcidev);
0226     if (!base)
0227         return -ENOMEM;
0228 
0229     /*
0230      * PF device has FME and Ports/AFUs, and VF device only has one
0231      * Port/AFU. Check them and add related "Device Feature List" info
0232      * for the next step enumeration.
0233      */
0234     if (dfl_feature_is_fme(base)) {
0235         start = pci_resource_start(pcidev, 0);
0236         len = pci_resource_len(pcidev, 0);
0237 
0238         dfl_fpga_enum_info_add_dfl(info, start, len);
0239 
0240         /*
0241          * find more Device Feature Lists (e.g. Ports) per information
0242          * indicated by FME module.
0243          */
0244         v = readq(base + FME_HDR_CAP);
0245         port_num = FIELD_GET(FME_CAP_NUM_PORTS, v);
0246 
0247         WARN_ON(port_num > MAX_DFL_FPGA_PORT_NUM);
0248 
0249         for (i = 0; i < port_num; i++) {
0250             v = readq(base + FME_HDR_PORT_OFST(i));
0251 
0252             /* skip ports which are not implemented. */
0253             if (!(v & FME_PORT_OFST_IMP))
0254                 continue;
0255 
0256             /*
0257              * add Port's Device Feature List information for next
0258              * step enumeration.
0259              */
0260             bar = FIELD_GET(FME_PORT_OFST_BAR_ID, v);
0261             offset = FIELD_GET(FME_PORT_OFST_DFH_OFST, v);
0262             if (bar == FME_PORT_OFST_BAR_SKIP) {
0263                 continue;
0264             } else if (bar >= PCI_STD_NUM_BARS) {
0265                 dev_err(&pcidev->dev, "bad BAR %d for port %d\n",
0266                     bar, i);
0267                 ret = -EINVAL;
0268                 break;
0269             }
0270 
0271             start = pci_resource_start(pcidev, bar) + offset;
0272             len = pci_resource_len(pcidev, bar) - offset;
0273 
0274             dfl_fpga_enum_info_add_dfl(info, start, len);
0275         }
0276     } else if (dfl_feature_is_port(base)) {
0277         start = pci_resource_start(pcidev, 0);
0278         len = pci_resource_len(pcidev, 0);
0279 
0280         dfl_fpga_enum_info_add_dfl(info, start, len);
0281     } else {
0282         ret = -ENODEV;
0283     }
0284 
0285     /* release I/O mappings for next step enumeration */
0286     pcim_iounmap_regions(pcidev, BIT(0));
0287 
0288     return ret;
0289 }
0290 
0291 /* enumerate feature devices under pci device */
0292 static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
0293 {
0294     struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
0295     struct dfl_fpga_enum_info *info;
0296     struct dfl_fpga_cdev *cdev;
0297     int nvec, ret = 0;
0298     int *irq_table;
0299 
0300     /* allocate enumeration info via pci_dev */
0301     info = dfl_fpga_enum_info_alloc(&pcidev->dev);
0302     if (!info)
0303         return -ENOMEM;
0304 
0305     /* add irq info for enumeration if the device support irq */
0306     nvec = cci_pci_alloc_irq(pcidev);
0307     if (nvec < 0) {
0308         dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec);
0309         ret = nvec;
0310         goto enum_info_free_exit;
0311     } else if (nvec) {
0312         irq_table = cci_pci_create_irq_table(pcidev, nvec);
0313         if (!irq_table) {
0314             ret = -ENOMEM;
0315             goto irq_free_exit;
0316         }
0317 
0318         ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table);
0319         kfree(irq_table);
0320         if (ret)
0321             goto irq_free_exit;
0322     }
0323 
0324     ret = find_dfls_by_vsec(pcidev, info);
0325     if (ret == -ENODEV)
0326         ret = find_dfls_by_default(pcidev, info);
0327 
0328     if (ret)
0329         goto irq_free_exit;
0330 
0331     /* start enumeration with prepared enumeration information */
0332     cdev = dfl_fpga_feature_devs_enumerate(info);
0333     if (IS_ERR(cdev)) {
0334         dev_err(&pcidev->dev, "Enumeration failure\n");
0335         ret = PTR_ERR(cdev);
0336         goto irq_free_exit;
0337     }
0338 
0339     drvdata->cdev = cdev;
0340 
0341 irq_free_exit:
0342     if (ret)
0343         cci_pci_free_irq(pcidev);
0344 enum_info_free_exit:
0345     dfl_fpga_enum_info_free(info);
0346 
0347     return ret;
0348 }
0349 
0350 static
0351 int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
0352 {
0353     int ret;
0354 
0355     ret = pcim_enable_device(pcidev);
0356     if (ret < 0) {
0357         dev_err(&pcidev->dev, "Failed to enable device %d.\n", ret);
0358         return ret;
0359     }
0360 
0361     ret = pci_enable_pcie_error_reporting(pcidev);
0362     if (ret && ret != -EINVAL)
0363         dev_info(&pcidev->dev, "PCIE AER unavailable %d.\n", ret);
0364 
0365     pci_set_master(pcidev);
0366 
0367     ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(64));
0368     if (ret)
0369         ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32));
0370     if (ret) {
0371         dev_err(&pcidev->dev, "No suitable DMA support available.\n");
0372         goto disable_error_report_exit;
0373     }
0374 
0375     ret = cci_init_drvdata(pcidev);
0376     if (ret) {
0377         dev_err(&pcidev->dev, "Fail to init drvdata %d.\n", ret);
0378         goto disable_error_report_exit;
0379     }
0380 
0381     ret = cci_enumerate_feature_devs(pcidev);
0382     if (!ret)
0383         return ret;
0384 
0385     dev_err(&pcidev->dev, "enumeration failure %d.\n", ret);
0386 
0387 disable_error_report_exit:
0388     pci_disable_pcie_error_reporting(pcidev);
0389     return ret;
0390 }
0391 
0392 static int cci_pci_sriov_configure(struct pci_dev *pcidev, int num_vfs)
0393 {
0394     struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
0395     struct dfl_fpga_cdev *cdev = drvdata->cdev;
0396 
0397     if (!num_vfs) {
0398         /*
0399          * disable SRIOV and then put released ports back to default
0400          * PF access mode.
0401          */
0402         pci_disable_sriov(pcidev);
0403 
0404         dfl_fpga_cdev_config_ports_pf(cdev);
0405 
0406     } else {
0407         int ret;
0408 
0409         /*
0410          * before enable SRIOV, put released ports into VF access mode
0411          * first of all.
0412          */
0413         ret = dfl_fpga_cdev_config_ports_vf(cdev, num_vfs);
0414         if (ret)
0415             return ret;
0416 
0417         ret = pci_enable_sriov(pcidev, num_vfs);
0418         if (ret) {
0419             dfl_fpga_cdev_config_ports_pf(cdev);
0420             return ret;
0421         }
0422     }
0423 
0424     return num_vfs;
0425 }
0426 
0427 static void cci_pci_remove(struct pci_dev *pcidev)
0428 {
0429     if (dev_is_pf(&pcidev->dev))
0430         cci_pci_sriov_configure(pcidev, 0);
0431 
0432     cci_remove_feature_devs(pcidev);
0433     pci_disable_pcie_error_reporting(pcidev);
0434 }
0435 
0436 static struct pci_driver cci_pci_driver = {
0437     .name = DRV_NAME,
0438     .id_table = cci_pcie_id_tbl,
0439     .probe = cci_pci_probe,
0440     .remove = cci_pci_remove,
0441     .sriov_configure = cci_pci_sriov_configure,
0442 };
0443 
0444 module_pci_driver(cci_pci_driver);
0445 
0446 MODULE_DESCRIPTION("FPGA DFL PCIe Device Driver");
0447 MODULE_AUTHOR("Intel Corporation");
0448 MODULE_LICENSE("GPL v2");