summaryrefslogtreecommitdiffstats
path: root/drivers/fpga
diff options
context:
space:
mode:
authorWu Hao <hao.wu@intel.com>2018-06-29 20:53:20 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-07-15 07:55:45 -0400
commit968b8199e2585ac4435e2b73af81201e20859c36 (patch)
treee8b75826b7e02a87f8efdccceaad279691ea57da /drivers/fpga
parent72ddd9f34040a49a221c0d5d1754061e007a10e6 (diff)
fpga: dfl-pci: add enumeration for feature devices
The Device Feature List (DFL) is implemented in MMIO and features are linked via the DFLs. This patch enables pcie driver to prepare enumeration information (e.g. locations of all device feature lists in MMIO) and use common APIs provided by the Device Feature List framework to enumerate each feature device linked. Signed-off-by: Tim Whisonant <tim.whisonant@intel.com> Signed-off-by: Enno Luebbers <enno.luebbers@intel.com> Signed-off-by: Shiva Rao <shiva.rao@intel.com> Signed-off-by: Christopher Rauer <christopher.rauer@intel.com> Signed-off-by: Zhang Yi <yi.z.zhang@intel.com> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com> Signed-off-by: Wu Hao <hao.wu@intel.com> Acked-by: Alan Tull <atull@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/fpga')
-rw-r--r--drivers/fpga/dfl-pci.c144
1 files changed, 142 insertions, 2 deletions
diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c
index e1e1f0fbe98c..66b5720582bb 100644
--- a/drivers/fpga/dfl-pci.c
+++ b/drivers/fpga/dfl-pci.c
@@ -22,9 +22,23 @@
22#include <linux/errno.h> 22#include <linux/errno.h>
23#include <linux/aer.h> 23#include <linux/aer.h>
24 24
25#include "dfl.h"
26
25#define DRV_VERSION "0.8" 27#define DRV_VERSION "0.8"
26#define DRV_NAME "dfl-pci" 28#define DRV_NAME "dfl-pci"
27 29
30struct cci_drvdata {
31 struct dfl_fpga_cdev *cdev; /* container device */
32};
33
34static 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
28/* PCI Device ID */ 42/* PCI Device ID */
29#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD 43#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD
30#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 44#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0
@@ -45,6 +59,120 @@ static struct pci_device_id cci_pcie_id_tbl[] = {
45}; 59};
46MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl); 60MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl);
47 61
62static 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
75static 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 */
84static 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
170enum_info_free_exit:
171 dfl_fpga_enum_info_free(info);
172
173 return ret;
174}
175
48static 176static
49int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid) 177int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
50{ 178{
@@ -76,8 +204,19 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
76 goto disable_error_report_exit; 204 goto disable_error_report_exit;
77 } 205 }
78 206
79 /* TODO: create and add the platform device per feature list */ 207 ret = cci_init_drvdata(pcidev);
80 return 0; 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;
81 220
82disable_error_report_exit: 221disable_error_report_exit:
83 pci_disable_pcie_error_reporting(pcidev); 222 pci_disable_pcie_error_reporting(pcidev);
@@ -86,6 +225,7 @@ disable_error_report_exit:
86 225
87static void cci_pci_remove(struct pci_dev *pcidev) 226static void cci_pci_remove(struct pci_dev *pcidev)
88{ 227{
228 cci_remove_feature_devs(pcidev);
89 pci_disable_pcie_error_reporting(pcidev); 229 pci_disable_pcie_error_reporting(pcidev);
90} 230}
91 231