1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for FPGA Device Feature List (DFL) PCIe device
5 * Copyright (C) 2017-2018 Intel Corporation, Inc.
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>
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>
27 #define DRV_VERSION "0.8"
28 #define DRV_NAME "dfl-pci"
30 #define PCI_VSEC_ID_INTEL_DFLS 0x43
32 #define PCI_VNDR_DFLS_CNT 0x8
33 #define PCI_VNDR_DFLS_RES 0xc
35 #define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0)
36 #define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
39 struct dfl_fpga_cdev
*cdev
; /* container device */
42 static void __iomem
*cci_pci_ioremap_bar0(struct pci_dev
*pcidev
)
44 if (pcim_iomap_regions(pcidev
, BIT(0), DRV_NAME
))
47 return pcim_iomap_table(pcidev
)[0];
50 static int cci_pci_alloc_irq(struct pci_dev
*pcidev
)
52 int ret
, nvec
= pci_msix_vec_count(pcidev
);
55 dev_dbg(&pcidev
->dev
, "fpga interrupt not supported\n");
59 ret
= pci_alloc_irq_vectors(pcidev
, nvec
, nvec
, PCI_IRQ_MSIX
);
66 static void cci_pci_free_irq(struct pci_dev
*pcidev
)
68 pci_free_irq_vectors(pcidev
);
72 #define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD
73 #define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0
74 #define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4
75 #define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30
76 #define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B
78 #define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF
79 #define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1
80 #define PCIE_DEVICE_ID_VF_DSC_1_X 0x09C5
81 #define PCIE_DEVICE_ID_INTEL_PAC_D5005_VF 0x0B2C
83 static struct pci_device_id cci_pcie_id_tbl
[] = {
84 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCIE_DEVICE_ID_PF_INT_5_X
),},
85 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCIE_DEVICE_ID_VF_INT_5_X
),},
86 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCIE_DEVICE_ID_PF_INT_6_X
),},
87 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCIE_DEVICE_ID_VF_INT_6_X
),},
88 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCIE_DEVICE_ID_PF_DSC_1_X
),},
89 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCIE_DEVICE_ID_VF_DSC_1_X
),},
90 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCIE_DEVICE_ID_INTEL_PAC_N3000
),},
91 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCIE_DEVICE_ID_INTEL_PAC_D5005
),},
92 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF
),},
95 MODULE_DEVICE_TABLE(pci
, cci_pcie_id_tbl
);
97 static int cci_init_drvdata(struct pci_dev
*pcidev
)
99 struct cci_drvdata
*drvdata
;
101 drvdata
= devm_kzalloc(&pcidev
->dev
, sizeof(*drvdata
), GFP_KERNEL
);
105 pci_set_drvdata(pcidev
, drvdata
);
110 static void cci_remove_feature_devs(struct pci_dev
*pcidev
)
112 struct cci_drvdata
*drvdata
= pci_get_drvdata(pcidev
);
114 /* remove all children feature devices */
115 dfl_fpga_feature_devs_remove(drvdata
->cdev
);
116 cci_pci_free_irq(pcidev
);
119 static int *cci_pci_create_irq_table(struct pci_dev
*pcidev
, unsigned int nvec
)
124 table
= kcalloc(nvec
, sizeof(int), GFP_KERNEL
);
128 for (i
= 0; i
< nvec
; i
++)
129 table
[i
] = pci_irq_vector(pcidev
, i
);
134 static int find_dfls_by_vsec(struct pci_dev
*pcidev
, struct dfl_fpga_enum_info
*info
)
136 u32 bir
, offset
, vndr_hdr
, dfl_cnt
, dfl_res
;
137 int dfl_res_off
, i
, bars
, voff
= 0;
138 resource_size_t start
, len
;
140 while ((voff
= pci_find_next_ext_capability(pcidev
, voff
, PCI_EXT_CAP_ID_VNDR
))) {
142 pci_read_config_dword(pcidev
, voff
+ PCI_VNDR_HEADER
, &vndr_hdr
);
144 if (PCI_VNDR_HEADER_ID(vndr_hdr
) == PCI_VSEC_ID_INTEL_DFLS
&&
145 pcidev
->vendor
== PCI_VENDOR_ID_INTEL
)
150 dev_dbg(&pcidev
->dev
, "%s no DFL VSEC found\n", __func__
);
155 pci_read_config_dword(pcidev
, voff
+ PCI_VNDR_DFLS_CNT
, &dfl_cnt
);
156 if (dfl_cnt
> PCI_STD_NUM_BARS
) {
157 dev_err(&pcidev
->dev
, "%s too many DFLs %d > %d\n",
158 __func__
, dfl_cnt
, PCI_STD_NUM_BARS
);
162 dfl_res_off
= voff
+ PCI_VNDR_DFLS_RES
;
163 if (dfl_res_off
+ (dfl_cnt
* sizeof(u32
)) > PCI_CFG_SPACE_EXP_SIZE
) {
164 dev_err(&pcidev
->dev
, "%s DFL VSEC too big for PCIe config space\n",
169 for (i
= 0, bars
= 0; i
< dfl_cnt
; i
++, dfl_res_off
+= sizeof(u32
)) {
170 dfl_res
= GENMASK(31, 0);
171 pci_read_config_dword(pcidev
, dfl_res_off
, &dfl_res
);
173 bir
= dfl_res
& PCI_VNDR_DFLS_RES_BAR_MASK
;
174 if (bir
>= PCI_STD_NUM_BARS
) {
175 dev_err(&pcidev
->dev
, "%s bad bir number %d\n",
180 if (bars
& BIT(bir
)) {
181 dev_err(&pcidev
->dev
, "%s DFL for BAR %d already specified\n",
188 len
= pci_resource_len(pcidev
, bir
);
189 offset
= dfl_res
& PCI_VNDR_DFLS_RES_OFF_MASK
;
191 dev_err(&pcidev
->dev
, "%s bad offset %u >= %pa\n",
192 __func__
, offset
, &len
);
196 dev_dbg(&pcidev
->dev
, "%s BAR %d offset 0x%x\n", __func__
, bir
, offset
);
200 start
= pci_resource_start(pcidev
, bir
) + offset
;
202 dfl_fpga_enum_info_add_dfl(info
, start
, len
);
208 /* default method of finding dfls starting at offset 0 of bar 0 */
209 static int find_dfls_by_default(struct pci_dev
*pcidev
,
210 struct dfl_fpga_enum_info
*info
)
212 int port_num
, bar
, i
, ret
= 0;
213 resource_size_t start
, len
;
218 /* start to find Device Feature List from Bar 0 */
219 base
= cci_pci_ioremap_bar0(pcidev
);
224 * PF device has FME and Ports/AFUs, and VF device only has one
225 * Port/AFU. Check them and add related "Device Feature List" info
226 * for the next step enumeration.
228 if (dfl_feature_is_fme(base
)) {
229 start
= pci_resource_start(pcidev
, 0);
230 len
= pci_resource_len(pcidev
, 0);
232 dfl_fpga_enum_info_add_dfl(info
, start
, len
);
235 * find more Device Feature Lists (e.g. Ports) per information
236 * indicated by FME module.
238 v
= readq(base
+ FME_HDR_CAP
);
239 port_num
= FIELD_GET(FME_CAP_NUM_PORTS
, v
);
241 WARN_ON(port_num
> MAX_DFL_FPGA_PORT_NUM
);
243 for (i
= 0; i
< port_num
; i
++) {
244 v
= readq(base
+ FME_HDR_PORT_OFST(i
));
246 /* skip ports which are not implemented. */
247 if (!(v
& FME_PORT_OFST_IMP
))
251 * add Port's Device Feature List information for next
254 bar
= FIELD_GET(FME_PORT_OFST_BAR_ID
, v
);
255 offset
= FIELD_GET(FME_PORT_OFST_DFH_OFST
, v
);
256 start
= pci_resource_start(pcidev
, bar
) + offset
;
257 len
= pci_resource_len(pcidev
, bar
) - offset
;
259 dfl_fpga_enum_info_add_dfl(info
, start
, len
);
261 } else if (dfl_feature_is_port(base
)) {
262 start
= pci_resource_start(pcidev
, 0);
263 len
= pci_resource_len(pcidev
, 0);
265 dfl_fpga_enum_info_add_dfl(info
, start
, len
);
270 /* release I/O mappings for next step enumeration */
271 pcim_iounmap_regions(pcidev
, BIT(0));
276 /* enumerate feature devices under pci device */
277 static int cci_enumerate_feature_devs(struct pci_dev
*pcidev
)
279 struct cci_drvdata
*drvdata
= pci_get_drvdata(pcidev
);
280 struct dfl_fpga_enum_info
*info
;
281 struct dfl_fpga_cdev
*cdev
;
285 /* allocate enumeration info via pci_dev */
286 info
= dfl_fpga_enum_info_alloc(&pcidev
->dev
);
290 /* add irq info for enumeration if the device support irq */
291 nvec
= cci_pci_alloc_irq(pcidev
);
293 dev_err(&pcidev
->dev
, "Fail to alloc irq %d.\n", nvec
);
295 goto enum_info_free_exit
;
297 irq_table
= cci_pci_create_irq_table(pcidev
, nvec
);
303 ret
= dfl_fpga_enum_info_add_irq(info
, nvec
, irq_table
);
309 ret
= find_dfls_by_vsec(pcidev
, info
);
311 ret
= find_dfls_by_default(pcidev
, info
);
316 /* start enumeration with prepared enumeration information */
317 cdev
= dfl_fpga_feature_devs_enumerate(info
);
319 dev_err(&pcidev
->dev
, "Enumeration failure\n");
324 drvdata
->cdev
= cdev
;
328 cci_pci_free_irq(pcidev
);
330 dfl_fpga_enum_info_free(info
);
336 int cci_pci_probe(struct pci_dev
*pcidev
, const struct pci_device_id
*pcidevid
)
340 ret
= pcim_enable_device(pcidev
);
342 dev_err(&pcidev
->dev
, "Failed to enable device %d.\n", ret
);
346 ret
= pci_enable_pcie_error_reporting(pcidev
);
347 if (ret
&& ret
!= -EINVAL
)
348 dev_info(&pcidev
->dev
, "PCIE AER unavailable %d.\n", ret
);
350 pci_set_master(pcidev
);
352 if (!pci_set_dma_mask(pcidev
, DMA_BIT_MASK(64))) {
353 ret
= pci_set_consistent_dma_mask(pcidev
, DMA_BIT_MASK(64));
355 goto disable_error_report_exit
;
356 } else if (!pci_set_dma_mask(pcidev
, DMA_BIT_MASK(32))) {
357 ret
= pci_set_consistent_dma_mask(pcidev
, DMA_BIT_MASK(32));
359 goto disable_error_report_exit
;
362 dev_err(&pcidev
->dev
, "No suitable DMA support available.\n");
363 goto disable_error_report_exit
;
366 ret
= cci_init_drvdata(pcidev
);
368 dev_err(&pcidev
->dev
, "Fail to init drvdata %d.\n", ret
);
369 goto disable_error_report_exit
;
372 ret
= cci_enumerate_feature_devs(pcidev
);
376 dev_err(&pcidev
->dev
, "enumeration failure %d.\n", ret
);
378 disable_error_report_exit
:
379 pci_disable_pcie_error_reporting(pcidev
);
383 static int cci_pci_sriov_configure(struct pci_dev
*pcidev
, int num_vfs
)
385 struct cci_drvdata
*drvdata
= pci_get_drvdata(pcidev
);
386 struct dfl_fpga_cdev
*cdev
= drvdata
->cdev
;
390 * disable SRIOV and then put released ports back to default
393 pci_disable_sriov(pcidev
);
395 dfl_fpga_cdev_config_ports_pf(cdev
);
401 * before enable SRIOV, put released ports into VF access mode
404 ret
= dfl_fpga_cdev_config_ports_vf(cdev
, num_vfs
);
408 ret
= pci_enable_sriov(pcidev
, num_vfs
);
410 dfl_fpga_cdev_config_ports_pf(cdev
);
418 static void cci_pci_remove(struct pci_dev
*pcidev
)
420 if (dev_is_pf(&pcidev
->dev
))
421 cci_pci_sriov_configure(pcidev
, 0);
423 cci_remove_feature_devs(pcidev
);
424 pci_disable_pcie_error_reporting(pcidev
);
427 static struct pci_driver cci_pci_driver
= {
429 .id_table
= cci_pcie_id_tbl
,
430 .probe
= cci_pci_probe
,
431 .remove
= cci_pci_remove
,
432 .sriov_configure
= cci_pci_sriov_configure
,
435 module_pci_driver(cci_pci_driver
);
437 MODULE_DESCRIPTION("FPGA DFL PCIe Device Driver");
438 MODULE_AUTHOR("Intel Corporation");
439 MODULE_LICENSE("GPL v2");