summaryrefslogtreecommitdiffstats
path: root/drivers/fpga
diff options
context:
space:
mode:
authorMoritz Fischer <mdf@kernel.org>2019-09-03 22:35:07 -0400
committerMoritz Fischer <mdf@kernel.org>2019-09-03 22:35:07 -0400
commitaf9ca4b0bd0502bb134f18d394a613be371d2352 (patch)
tree37b1159d4456e223981dddde4795f2061c83d14c /drivers/fpga
parentcbb4a74478e9eef0f8ef437e95ef7645008988f7 (diff)
parent99097a214b0c15f7595ac8f2788662f3941c1992 (diff)
Merge branch 'char-misc-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc into fpga-dfl-for-5.4
Diffstat (limited to 'drivers/fpga')
-rw-r--r--drivers/fpga/Kconfig1
-rw-r--r--drivers/fpga/altera-ps-spi.c11
-rw-r--r--drivers/fpga/dfl-afu-main.c165
-rw-r--r--drivers/fpga/dfl-fme-main.c108
-rw-r--r--drivers/fpga/dfl-fme-pr.c7
-rw-r--r--drivers/fpga/dfl-fme.h3
-rw-r--r--drivers/fpga/dfl-pci.c36
-rw-r--r--drivers/fpga/dfl.c216
-rw-r--r--drivers/fpga/dfl.h43
9 files changed, 549 insertions, 41 deletions
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index f50956ec1300..73c779e920ed 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -40,6 +40,7 @@ config ALTERA_PR_IP_CORE_PLAT
40config FPGA_MGR_ALTERA_PS_SPI 40config FPGA_MGR_ALTERA_PS_SPI
41 tristate "Altera FPGA Passive Serial over SPI" 41 tristate "Altera FPGA Passive Serial over SPI"
42 depends on SPI 42 depends on SPI
43 select BITREVERSE
43 help 44 help
44 FPGA manager driver support for Altera Arria/Cyclone/Stratix 45 FPGA manager driver support for Altera Arria/Cyclone/Stratix
45 using the passive serial interface over SPI. 46 using the passive serial interface over SPI.
diff --git a/drivers/fpga/altera-ps-spi.c b/drivers/fpga/altera-ps-spi.c
index a13f224303c6..0221dee8dd4c 100644
--- a/drivers/fpga/altera-ps-spi.c
+++ b/drivers/fpga/altera-ps-spi.c
@@ -210,7 +210,7 @@ static int altera_ps_write_complete(struct fpga_manager *mgr,
210 return -EIO; 210 return -EIO;
211 } 211 }
212 212
213 if (!IS_ERR(conf->confd)) { 213 if (conf->confd) {
214 if (!gpiod_get_raw_value_cansleep(conf->confd)) { 214 if (!gpiod_get_raw_value_cansleep(conf->confd)) {
215 dev_err(&mgr->dev, "CONF_DONE is inactive!\n"); 215 dev_err(&mgr->dev, "CONF_DONE is inactive!\n");
216 return -EIO; 216 return -EIO;
@@ -289,10 +289,13 @@ static int altera_ps_probe(struct spi_device *spi)
289 return PTR_ERR(conf->status); 289 return PTR_ERR(conf->status);
290 } 290 }
291 291
292 conf->confd = devm_gpiod_get(&spi->dev, "confd", GPIOD_IN); 292 conf->confd = devm_gpiod_get_optional(&spi->dev, "confd", GPIOD_IN);
293 if (IS_ERR(conf->confd)) { 293 if (IS_ERR(conf->confd)) {
294 dev_warn(&spi->dev, "Not using confd gpio: %ld\n", 294 dev_err(&spi->dev, "Failed to get confd gpio: %ld\n",
295 PTR_ERR(conf->confd)); 295 PTR_ERR(conf->confd));
296 return PTR_ERR(conf->confd);
297 } else if (!conf->confd) {
298 dev_warn(&spi->dev, "Not using confd gpio");
296 } 299 }
297 300
298 /* Register manager with unique name */ 301 /* Register manager with unique name */
diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c
index 02baa6a227c0..e50c45ed40ac 100644
--- a/drivers/fpga/dfl-afu-main.c
+++ b/drivers/fpga/dfl-afu-main.c
@@ -141,10 +141,148 @@ id_show(struct device *dev, struct device_attribute *attr, char *buf)
141} 141}
142static DEVICE_ATTR_RO(id); 142static DEVICE_ATTR_RO(id);
143 143
144static const struct attribute *port_hdr_attrs[] = { 144static ssize_t
145ltr_show(struct device *dev, struct device_attribute *attr, char *buf)
146{
147 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
148 void __iomem *base;
149 u64 v;
150
151 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
152
153 mutex_lock(&pdata->lock);
154 v = readq(base + PORT_HDR_CTRL);
155 mutex_unlock(&pdata->lock);
156
157 return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_CTRL_LATENCY, v));
158}
159
160static ssize_t
161ltr_store(struct device *dev, struct device_attribute *attr,
162 const char *buf, size_t count)
163{
164 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
165 void __iomem *base;
166 bool ltr;
167 u64 v;
168
169 if (kstrtobool(buf, &ltr))
170 return -EINVAL;
171
172 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
173
174 mutex_lock(&pdata->lock);
175 v = readq(base + PORT_HDR_CTRL);
176 v &= ~PORT_CTRL_LATENCY;
177 v |= FIELD_PREP(PORT_CTRL_LATENCY, ltr ? 1 : 0);
178 writeq(v, base + PORT_HDR_CTRL);
179 mutex_unlock(&pdata->lock);
180
181 return count;
182}
183static DEVICE_ATTR_RW(ltr);
184
185static ssize_t
186ap1_event_show(struct device *dev, struct device_attribute *attr, char *buf)
187{
188 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
189 void __iomem *base;
190 u64 v;
191
192 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
193
194 mutex_lock(&pdata->lock);
195 v = readq(base + PORT_HDR_STS);
196 mutex_unlock(&pdata->lock);
197
198 return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP1_EVT, v));
199}
200
201static ssize_t
202ap1_event_store(struct device *dev, struct device_attribute *attr,
203 const char *buf, size_t count)
204{
205 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
206 void __iomem *base;
207 bool clear;
208
209 if (kstrtobool(buf, &clear) || !clear)
210 return -EINVAL;
211
212 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
213
214 mutex_lock(&pdata->lock);
215 writeq(PORT_STS_AP1_EVT, base + PORT_HDR_STS);
216 mutex_unlock(&pdata->lock);
217
218 return count;
219}
220static DEVICE_ATTR_RW(ap1_event);
221
222static ssize_t
223ap2_event_show(struct device *dev, struct device_attribute *attr,
224 char *buf)
225{
226 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
227 void __iomem *base;
228 u64 v;
229
230 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
231
232 mutex_lock(&pdata->lock);
233 v = readq(base + PORT_HDR_STS);
234 mutex_unlock(&pdata->lock);
235
236 return sprintf(buf, "%x\n", (u8)FIELD_GET(PORT_STS_AP2_EVT, v));
237}
238
239static ssize_t
240ap2_event_store(struct device *dev, struct device_attribute *attr,
241 const char *buf, size_t count)
242{
243 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
244 void __iomem *base;
245 bool clear;
246
247 if (kstrtobool(buf, &clear) || !clear)
248 return -EINVAL;
249
250 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
251
252 mutex_lock(&pdata->lock);
253 writeq(PORT_STS_AP2_EVT, base + PORT_HDR_STS);
254 mutex_unlock(&pdata->lock);
255
256 return count;
257}
258static DEVICE_ATTR_RW(ap2_event);
259
260static ssize_t
261power_state_show(struct device *dev, struct device_attribute *attr, char *buf)
262{
263 struct dfl_feature_platform_data *pdata = dev_get_platdata(dev);
264 void __iomem *base;
265 u64 v;
266
267 base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER);
268
269 mutex_lock(&pdata->lock);
270 v = readq(base + PORT_HDR_STS);
271 mutex_unlock(&pdata->lock);
272
273 return sprintf(buf, "0x%x\n", (u8)FIELD_GET(PORT_STS_PWR_STATE, v));
274}
275static DEVICE_ATTR_RO(power_state);
276
277static struct attribute *port_hdr_attrs[] = {
145 &dev_attr_id.attr, 278 &dev_attr_id.attr,
279 &dev_attr_ltr.attr,
280 &dev_attr_ap1_event.attr,
281 &dev_attr_ap2_event.attr,
282 &dev_attr_power_state.attr,
146 NULL, 283 NULL,
147}; 284};
285ATTRIBUTE_GROUPS(port_hdr);
148 286
149static int port_hdr_init(struct platform_device *pdev, 287static int port_hdr_init(struct platform_device *pdev,
150 struct dfl_feature *feature) 288 struct dfl_feature *feature)
@@ -153,7 +291,7 @@ static int port_hdr_init(struct platform_device *pdev,
153 291
154 port_reset(pdev); 292 port_reset(pdev);
155 293
156 return sysfs_create_files(&pdev->dev.kobj, port_hdr_attrs); 294 return device_add_groups(&pdev->dev, port_hdr_groups);
157} 295}
158 296
159static void port_hdr_uinit(struct platform_device *pdev, 297static void port_hdr_uinit(struct platform_device *pdev,
@@ -161,7 +299,7 @@ static void port_hdr_uinit(struct platform_device *pdev,
161{ 299{
162 dev_dbg(&pdev->dev, "PORT HDR UInit.\n"); 300 dev_dbg(&pdev->dev, "PORT HDR UInit.\n");
163 301
164 sysfs_remove_files(&pdev->dev.kobj, port_hdr_attrs); 302 device_remove_groups(&pdev->dev, port_hdr_groups);
165} 303}
166 304
167static long 305static long
@@ -185,6 +323,11 @@ port_hdr_ioctl(struct platform_device *pdev, struct dfl_feature *feature,
185 return ret; 323 return ret;
186} 324}
187 325
326static const struct dfl_feature_id port_hdr_id_table[] = {
327 {.id = PORT_FEATURE_ID_HEADER,},
328 {0,}
329};
330
188static const struct dfl_feature_ops port_hdr_ops = { 331static const struct dfl_feature_ops port_hdr_ops = {
189 .init = port_hdr_init, 332 .init = port_hdr_init,
190 .uinit = port_hdr_uinit, 333 .uinit = port_hdr_uinit,
@@ -214,10 +357,11 @@ afu_id_show(struct device *dev, struct device_attribute *attr, char *buf)
214} 357}
215static DEVICE_ATTR_RO(afu_id); 358static DEVICE_ATTR_RO(afu_id);
216 359
217static const struct attribute *port_afu_attrs[] = { 360static struct attribute *port_afu_attrs[] = {
218 &dev_attr_afu_id.attr, 361 &dev_attr_afu_id.attr,
219 NULL 362 NULL
220}; 363};
364ATTRIBUTE_GROUPS(port_afu);
221 365
222static int port_afu_init(struct platform_device *pdev, 366static int port_afu_init(struct platform_device *pdev,
223 struct dfl_feature *feature) 367 struct dfl_feature *feature)
@@ -234,7 +378,7 @@ static int port_afu_init(struct platform_device *pdev,
234 if (ret) 378 if (ret)
235 return ret; 379 return ret;
236 380
237 return sysfs_create_files(&pdev->dev.kobj, port_afu_attrs); 381 return device_add_groups(&pdev->dev, port_afu_groups);
238} 382}
239 383
240static void port_afu_uinit(struct platform_device *pdev, 384static void port_afu_uinit(struct platform_device *pdev,
@@ -242,9 +386,14 @@ static void port_afu_uinit(struct platform_device *pdev,
242{ 386{
243 dev_dbg(&pdev->dev, "PORT AFU UInit.\n"); 387 dev_dbg(&pdev->dev, "PORT AFU UInit.\n");
244 388
245 sysfs_remove_files(&pdev->dev.kobj, port_afu_attrs); 389 device_remove_groups(&pdev->dev, port_afu_groups);
246} 390}
247 391
392static const struct dfl_feature_id port_afu_id_table[] = {
393 {.id = PORT_FEATURE_ID_AFU,},
394 {0,}
395};
396
248static const struct dfl_feature_ops port_afu_ops = { 397static const struct dfl_feature_ops port_afu_ops = {
249 .init = port_afu_init, 398 .init = port_afu_init,
250 .uinit = port_afu_uinit, 399 .uinit = port_afu_uinit,
@@ -252,11 +401,11 @@ static const struct dfl_feature_ops port_afu_ops = {
252 401
253static struct dfl_feature_driver port_feature_drvs[] = { 402static struct dfl_feature_driver port_feature_drvs[] = {
254 { 403 {
255 .id = PORT_FEATURE_ID_HEADER, 404 .id_table = port_hdr_id_table,
256 .ops = &port_hdr_ops, 405 .ops = &port_hdr_ops,
257 }, 406 },
258 { 407 {
259 .id = PORT_FEATURE_ID_AFU, 408 .id_table = port_afu_id_table,
260 .ops = &port_afu_ops, 409 .ops = &port_afu_ops,
261 }, 410 },
262 { 411 {
diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c
index 086ad2420ade..f033f1cfd3ed 100644
--- a/drivers/fpga/dfl-fme-main.c
+++ b/drivers/fpga/dfl-fme-main.c
@@ -16,6 +16,7 @@
16 16
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/uaccess.h>
19#include <linux/fpga-dfl.h> 20#include <linux/fpga-dfl.h>
20 21
21#include "dfl.h" 22#include "dfl.h"
@@ -72,12 +73,61 @@ static ssize_t bitstream_metadata_show(struct device *dev,
72} 73}
73static DEVICE_ATTR_RO(bitstream_metadata); 74static DEVICE_ATTR_RO(bitstream_metadata);
74 75
75static const struct attribute *fme_hdr_attrs[] = { 76static ssize_t cache_size_show(struct device *dev,
77 struct device_attribute *attr, char *buf)
78{
79 void __iomem *base;
80 u64 v;
81
82 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
83
84 v = readq(base + FME_HDR_CAP);
85
86 return sprintf(buf, "%u\n",
87 (unsigned int)FIELD_GET(FME_CAP_CACHE_SIZE, v));
88}
89static DEVICE_ATTR_RO(cache_size);
90
91static ssize_t fabric_version_show(struct device *dev,
92 struct device_attribute *attr, char *buf)
93{
94 void __iomem *base;
95 u64 v;
96
97 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
98
99 v = readq(base + FME_HDR_CAP);
100
101 return sprintf(buf, "%u\n",
102 (unsigned int)FIELD_GET(FME_CAP_FABRIC_VERID, v));
103}
104static DEVICE_ATTR_RO(fabric_version);
105
106static ssize_t socket_id_show(struct device *dev,
107 struct device_attribute *attr, char *buf)
108{
109 void __iomem *base;
110 u64 v;
111
112 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
113
114 v = readq(base + FME_HDR_CAP);
115
116 return sprintf(buf, "%u\n",
117 (unsigned int)FIELD_GET(FME_CAP_SOCKET_ID, v));
118}
119static DEVICE_ATTR_RO(socket_id);
120
121static struct attribute *fme_hdr_attrs[] = {
76 &dev_attr_ports_num.attr, 122 &dev_attr_ports_num.attr,
77 &dev_attr_bitstream_id.attr, 123 &dev_attr_bitstream_id.attr,
78 &dev_attr_bitstream_metadata.attr, 124 &dev_attr_bitstream_metadata.attr,
125 &dev_attr_cache_size.attr,
126 &dev_attr_fabric_version.attr,
127 &dev_attr_socket_id.attr,
79 NULL, 128 NULL,
80}; 129};
130ATTRIBUTE_GROUPS(fme_hdr);
81 131
82static int fme_hdr_init(struct platform_device *pdev, 132static int fme_hdr_init(struct platform_device *pdev,
83 struct dfl_feature *feature) 133 struct dfl_feature *feature)
@@ -89,7 +139,7 @@ static int fme_hdr_init(struct platform_device *pdev,
89 dev_dbg(&pdev->dev, "FME cap %llx.\n", 139 dev_dbg(&pdev->dev, "FME cap %llx.\n",
90 (unsigned long long)readq(base + FME_HDR_CAP)); 140 (unsigned long long)readq(base + FME_HDR_CAP));
91 141
92 ret = sysfs_create_files(&pdev->dev.kobj, fme_hdr_attrs); 142 ret = device_add_groups(&pdev->dev, fme_hdr_groups);
93 if (ret) 143 if (ret)
94 return ret; 144 return ret;
95 145
@@ -100,22 +150,68 @@ static void fme_hdr_uinit(struct platform_device *pdev,
100 struct dfl_feature *feature) 150 struct dfl_feature *feature)
101{ 151{
102 dev_dbg(&pdev->dev, "FME HDR UInit.\n"); 152 dev_dbg(&pdev->dev, "FME HDR UInit.\n");
103 sysfs_remove_files(&pdev->dev.kobj, fme_hdr_attrs); 153 device_remove_groups(&pdev->dev, fme_hdr_groups);
154}
155
156static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata,
157 unsigned long arg)
158{
159 struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
160 int port_id;
161
162 if (get_user(port_id, (int __user *)arg))
163 return -EFAULT;
164
165 return dfl_fpga_cdev_release_port(cdev, port_id);
166}
167
168static long fme_hdr_ioctl_assign_port(struct dfl_feature_platform_data *pdata,
169 unsigned long arg)
170{
171 struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
172 int port_id;
173
174 if (get_user(port_id, (int __user *)arg))
175 return -EFAULT;
176
177 return dfl_fpga_cdev_assign_port(cdev, port_id);
104} 178}
105 179
180static long fme_hdr_ioctl(struct platform_device *pdev,
181 struct dfl_feature *feature,
182 unsigned int cmd, unsigned long arg)
183{
184 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
185
186 switch (cmd) {
187 case DFL_FPGA_FME_PORT_RELEASE:
188 return fme_hdr_ioctl_release_port(pdata, arg);
189 case DFL_FPGA_FME_PORT_ASSIGN:
190 return fme_hdr_ioctl_assign_port(pdata, arg);
191 }
192
193 return -ENODEV;
194}
195
196static const struct dfl_feature_id fme_hdr_id_table[] = {
197 {.id = FME_FEATURE_ID_HEADER,},
198 {0,}
199};
200
106static const struct dfl_feature_ops fme_hdr_ops = { 201static const struct dfl_feature_ops fme_hdr_ops = {
107 .init = fme_hdr_init, 202 .init = fme_hdr_init,
108 .uinit = fme_hdr_uinit, 203 .uinit = fme_hdr_uinit,
204 .ioctl = fme_hdr_ioctl,
109}; 205};
110 206
111static struct dfl_feature_driver fme_feature_drvs[] = { 207static struct dfl_feature_driver fme_feature_drvs[] = {
112 { 208 {
113 .id = FME_FEATURE_ID_HEADER, 209 .id_table = fme_hdr_id_table,
114 .ops = &fme_hdr_ops, 210 .ops = &fme_hdr_ops,
115 }, 211 },
116 { 212 {
117 .id = FME_FEATURE_ID_PR_MGMT, 213 .id_table = fme_pr_mgmt_id_table,
118 .ops = &pr_mgmt_ops, 214 .ops = &fme_pr_mgmt_ops,
119 }, 215 },
120 { 216 {
121 .ops = NULL, 217 .ops = NULL,
diff --git a/drivers/fpga/dfl-fme-pr.c b/drivers/fpga/dfl-fme-pr.c
index 3c71dc3faaf5..a233a53db708 100644
--- a/drivers/fpga/dfl-fme-pr.c
+++ b/drivers/fpga/dfl-fme-pr.c
@@ -470,7 +470,12 @@ static long fme_pr_ioctl(struct platform_device *pdev,
470 return ret; 470 return ret;
471} 471}
472 472
473const struct dfl_feature_ops pr_mgmt_ops = { 473const struct dfl_feature_id fme_pr_mgmt_id_table[] = {
474 {.id = FME_FEATURE_ID_PR_MGMT,},
475 {0}
476};
477
478const struct dfl_feature_ops fme_pr_mgmt_ops = {
474 .init = pr_mgmt_init, 479 .init = pr_mgmt_init,
475 .uinit = pr_mgmt_uinit, 480 .uinit = pr_mgmt_uinit,
476 .ioctl = fme_pr_ioctl, 481 .ioctl = fme_pr_ioctl,
diff --git a/drivers/fpga/dfl-fme.h b/drivers/fpga/dfl-fme.h
index 5394a216c5c0..e4131e857dae 100644
--- a/drivers/fpga/dfl-fme.h
+++ b/drivers/fpga/dfl-fme.h
@@ -33,6 +33,7 @@ struct dfl_fme {
33 struct dfl_feature_platform_data *pdata; 33 struct dfl_feature_platform_data *pdata;
34}; 34};
35 35
36extern const struct dfl_feature_ops pr_mgmt_ops; 36extern const struct dfl_feature_ops fme_pr_mgmt_ops;
37extern const struct dfl_feature_id fme_pr_mgmt_id_table[];
37 38
38#endif /* __DFL_FME_H */ 39#endif /* __DFL_FME_H */
diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c
index 66b5720582bb..89ca292236ad 100644
--- a/drivers/fpga/dfl-pci.c
+++ b/drivers/fpga/dfl-pci.c
@@ -223,8 +223,43 @@ disable_error_report_exit:
223 return ret; 223 return ret;
224} 224}
225 225
226static 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 }
254
255 return ret;
256}
257
226static void cci_pci_remove(struct pci_dev *pcidev) 258static void cci_pci_remove(struct pci_dev *pcidev)
227{ 259{
260 if (dev_is_pf(&pcidev->dev))
261 cci_pci_sriov_configure(pcidev, 0);
262
228 cci_remove_feature_devs(pcidev); 263 cci_remove_feature_devs(pcidev);
229 pci_disable_pcie_error_reporting(pcidev); 264 pci_disable_pcie_error_reporting(pcidev);
230} 265}
@@ -234,6 +269,7 @@ static struct pci_driver cci_pci_driver = {
234 .id_table = cci_pcie_id_tbl, 269 .id_table = cci_pcie_id_tbl,
235 .probe = cci_pci_probe, 270 .probe = cci_pci_probe,
236 .remove = cci_pci_remove, 271 .remove = cci_pci_remove,
272 .sriov_configure = cci_pci_sriov_configure,
237}; 273};
238 274
239module_pci_driver(cci_pci_driver); 275module_pci_driver(cci_pci_driver);
diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c
index 4b66aaa32b5a..c0512afc4ed7 100644
--- a/drivers/fpga/dfl.c
+++ b/drivers/fpga/dfl.c
@@ -231,16 +231,20 @@ EXPORT_SYMBOL_GPL(dfl_fpga_port_ops_del);
231 */ 231 */
232int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id) 232int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id)
233{ 233{
234 struct dfl_fpga_port_ops *port_ops = dfl_fpga_port_ops_get(pdev); 234 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
235 int port_id; 235 struct dfl_fpga_port_ops *port_ops;
236
237 if (pdata->id != FEATURE_DEV_ID_UNUSED)
238 return pdata->id == *(int *)pport_id;
236 239
240 port_ops = dfl_fpga_port_ops_get(pdev);
237 if (!port_ops || !port_ops->get_id) 241 if (!port_ops || !port_ops->get_id)
238 return 0; 242 return 0;
239 243
240 port_id = port_ops->get_id(pdev); 244 pdata->id = port_ops->get_id(pdev);
241 dfl_fpga_port_ops_put(port_ops); 245 dfl_fpga_port_ops_put(port_ops);
242 246
243 return port_id == *(int *)pport_id; 247 return pdata->id == *(int *)pport_id;
244} 248}
245EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id); 249EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id);
246 250
@@ -255,7 +259,8 @@ void dfl_fpga_dev_feature_uinit(struct platform_device *pdev)
255 259
256 dfl_fpga_dev_for_each_feature(pdata, feature) 260 dfl_fpga_dev_for_each_feature(pdata, feature)
257 if (feature->ops) { 261 if (feature->ops) {
258 feature->ops->uinit(pdev, feature); 262 if (feature->ops->uinit)
263 feature->ops->uinit(pdev, feature);
259 feature->ops = NULL; 264 feature->ops = NULL;
260 } 265 }
261} 266}
@@ -277,6 +282,21 @@ static int dfl_feature_instance_init(struct platform_device *pdev,
277 return ret; 282 return ret;
278} 283}
279 284
285static bool dfl_feature_drv_match(struct dfl_feature *feature,
286 struct dfl_feature_driver *driver)
287{
288 const struct dfl_feature_id *ids = driver->id_table;
289
290 if (ids) {
291 while (ids->id) {
292 if (ids->id == feature->id)
293 return true;
294 ids++;
295 }
296 }
297 return false;
298}
299
280/** 300/**
281 * dfl_fpga_dev_feature_init - init for sub features of dfl feature device 301 * dfl_fpga_dev_feature_init - init for sub features of dfl feature device
282 * @pdev: feature device. 302 * @pdev: feature device.
@@ -297,8 +317,7 @@ int dfl_fpga_dev_feature_init(struct platform_device *pdev,
297 317
298 while (drv->ops) { 318 while (drv->ops) {
299 dfl_fpga_dev_for_each_feature(pdata, feature) { 319 dfl_fpga_dev_for_each_feature(pdata, feature) {
300 /* match feature and drv using id */ 320 if (dfl_feature_drv_match(feature, drv)) {
301 if (feature->id == drv->id) {
302 ret = dfl_feature_instance_init(pdev, pdata, 321 ret = dfl_feature_instance_init(pdev, pdata,
303 feature, drv); 322 feature, drv);
304 if (ret) 323 if (ret)
@@ -474,6 +493,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
474 pdata->dev = fdev; 493 pdata->dev = fdev;
475 pdata->num = binfo->feature_num; 494 pdata->num = binfo->feature_num;
476 pdata->dfl_cdev = binfo->cdev; 495 pdata->dfl_cdev = binfo->cdev;
496 pdata->id = FEATURE_DEV_ID_UNUSED;
477 mutex_init(&pdata->lock); 497 mutex_init(&pdata->lock);
478 lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type], 498 lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type],
479 dfl_pdata_key_strings[type]); 499 dfl_pdata_key_strings[type]);
@@ -973,25 +993,27 @@ void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev)
973{ 993{
974 struct dfl_feature_platform_data *pdata, *ptmp; 994 struct dfl_feature_platform_data *pdata, *ptmp;
975 995
976 remove_feature_devs(cdev);
977
978 mutex_lock(&cdev->lock); 996 mutex_lock(&cdev->lock);
979 if (cdev->fme_dev) { 997 if (cdev->fme_dev)
980 /* the fme should be unregistered. */
981 WARN_ON(device_is_registered(cdev->fme_dev));
982 put_device(cdev->fme_dev); 998 put_device(cdev->fme_dev);
983 }
984 999
985 list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) { 1000 list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) {
986 struct platform_device *port_dev = pdata->dev; 1001 struct platform_device *port_dev = pdata->dev;
987 1002
988 /* the port should be unregistered. */ 1003 /* remove released ports */
989 WARN_ON(device_is_registered(&port_dev->dev)); 1004 if (!device_is_registered(&port_dev->dev)) {
1005 dfl_id_free(feature_dev_id_type(port_dev),
1006 port_dev->id);
1007 platform_device_put(port_dev);
1008 }
1009
990 list_del(&pdata->node); 1010 list_del(&pdata->node);
991 put_device(&port_dev->dev); 1011 put_device(&port_dev->dev);
992 } 1012 }
993 mutex_unlock(&cdev->lock); 1013 mutex_unlock(&cdev->lock);
994 1014
1015 remove_feature_devs(cdev);
1016
995 fpga_region_unregister(cdev->region); 1017 fpga_region_unregister(cdev->region);
996 devm_kfree(cdev->parent, cdev); 1018 devm_kfree(cdev->parent, cdev);
997} 1019}
@@ -1042,6 +1064,170 @@ static int __init dfl_fpga_init(void)
1042 return ret; 1064 return ret;
1043} 1065}
1044 1066
1067/**
1068 * dfl_fpga_cdev_release_port - release a port platform device
1069 *
1070 * @cdev: parent container device.
1071 * @port_id: id of the port platform device.
1072 *
1073 * This function allows user to release a port platform device. This is a
1074 * mandatory step before turn a port from PF into VF for SRIOV support.
1075 *
1076 * Return: 0 on success, negative error code otherwise.
1077 */
1078int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id)
1079{
1080 struct platform_device *port_pdev;
1081 int ret = -ENODEV;
1082
1083 mutex_lock(&cdev->lock);
1084 port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id,
1085 dfl_fpga_check_port_id);
1086 if (!port_pdev)
1087 goto unlock_exit;
1088
1089 if (!device_is_registered(&port_pdev->dev)) {
1090 ret = -EBUSY;
1091 goto put_dev_exit;
1092 }
1093
1094 ret = dfl_feature_dev_use_begin(dev_get_platdata(&port_pdev->dev));
1095 if (ret)
1096 goto put_dev_exit;
1097
1098 platform_device_del(port_pdev);
1099 cdev->released_port_num++;
1100put_dev_exit:
1101 put_device(&port_pdev->dev);
1102unlock_exit:
1103 mutex_unlock(&cdev->lock);
1104 return ret;
1105}
1106EXPORT_SYMBOL_GPL(dfl_fpga_cdev_release_port);
1107
1108/**
1109 * dfl_fpga_cdev_assign_port - assign a port platform device back
1110 *
1111 * @cdev: parent container device.
1112 * @port_id: id of the port platform device.
1113 *
1114 * This function allows user to assign a port platform device back. This is
1115 * a mandatory step after disable SRIOV support.
1116 *
1117 * Return: 0 on success, negative error code otherwise.
1118 */
1119int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id)
1120{
1121 struct platform_device *port_pdev;
1122 int ret = -ENODEV;
1123
1124 mutex_lock(&cdev->lock);
1125 port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id,
1126 dfl_fpga_check_port_id);
1127 if (!port_pdev)
1128 goto unlock_exit;
1129
1130 if (device_is_registered(&port_pdev->dev)) {
1131 ret = -EBUSY;
1132 goto put_dev_exit;
1133 }
1134
1135 ret = platform_device_add(port_pdev);
1136 if (ret)
1137 goto put_dev_exit;
1138
1139 dfl_feature_dev_use_end(dev_get_platdata(&port_pdev->dev));
1140 cdev->released_port_num--;
1141put_dev_exit:
1142 put_device(&port_pdev->dev);
1143unlock_exit:
1144 mutex_unlock(&cdev->lock);
1145 return ret;
1146}
1147EXPORT_SYMBOL_GPL(dfl_fpga_cdev_assign_port);
1148
1149static void config_port_access_mode(struct device *fme_dev, int port_id,
1150 bool is_vf)
1151{
1152 void __iomem *base;
1153 u64 v;
1154
1155 base = dfl_get_feature_ioaddr_by_id(fme_dev, FME_FEATURE_ID_HEADER);
1156
1157 v = readq(base + FME_HDR_PORT_OFST(port_id));
1158
1159 v &= ~FME_PORT_OFST_ACC_CTRL;
1160 v |= FIELD_PREP(FME_PORT_OFST_ACC_CTRL,
1161 is_vf ? FME_PORT_OFST_ACC_VF : FME_PORT_OFST_ACC_PF);
1162
1163 writeq(v, base + FME_HDR_PORT_OFST(port_id));
1164}
1165
1166#define config_port_vf_mode(dev, id) config_port_access_mode(dev, id, true)
1167#define config_port_pf_mode(dev, id) config_port_access_mode(dev, id, false)
1168
1169/**
1170 * dfl_fpga_cdev_config_ports_pf - configure ports to PF access mode
1171 *
1172 * @cdev: parent container device.
1173 *
1174 * This function is needed in sriov configuration routine. It could be used to
1175 * configure the all released ports from VF access mode to PF.
1176 */
1177void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev)
1178{
1179 struct dfl_feature_platform_data *pdata;
1180
1181 mutex_lock(&cdev->lock);
1182 list_for_each_entry(pdata, &cdev->port_dev_list, node) {
1183 if (device_is_registered(&pdata->dev->dev))
1184 continue;
1185
1186 config_port_pf_mode(cdev->fme_dev, pdata->id);
1187 }
1188 mutex_unlock(&cdev->lock);
1189}
1190EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_pf);
1191
1192/**
1193 * dfl_fpga_cdev_config_ports_vf - configure ports to VF access mode
1194 *
1195 * @cdev: parent container device.
1196 * @num_vfs: VF device number.
1197 *
1198 * This function is needed in sriov configuration routine. It could be used to
1199 * configure the released ports from PF access mode to VF.
1200 *
1201 * Return: 0 on success, negative error code otherwise.
1202 */
1203int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs)
1204{
1205 struct dfl_feature_platform_data *pdata;
1206 int ret = 0;
1207
1208 mutex_lock(&cdev->lock);
1209 /*
1210 * can't turn multiple ports into 1 VF device, only 1 port for 1 VF
1211 * device, so if released port number doesn't match VF device number,
1212 * then reject the request with -EINVAL error code.
1213 */
1214 if (cdev->released_port_num != num_vfs) {
1215 ret = -EINVAL;
1216 goto done;
1217 }
1218
1219 list_for_each_entry(pdata, &cdev->port_dev_list, node) {
1220 if (device_is_registered(&pdata->dev->dev))
1221 continue;
1222
1223 config_port_vf_mode(cdev->fme_dev, pdata->id);
1224 }
1225done:
1226 mutex_unlock(&cdev->lock);
1227 return ret;
1228}
1229EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_vf);
1230
1045static void __exit dfl_fpga_exit(void) 1231static void __exit dfl_fpga_exit(void)
1046{ 1232{
1047 dfl_chardev_uinit(); 1233 dfl_chardev_uinit();
diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h
index a8b869e9e5b7..856ea4ebc445 100644
--- a/drivers/fpga/dfl.h
+++ b/drivers/fpga/dfl.h
@@ -30,8 +30,8 @@
30/* plus one for fme device */ 30/* plus one for fme device */
31#define MAX_DFL_FEATURE_DEV_NUM (MAX_DFL_FPGA_PORT_NUM + 1) 31#define MAX_DFL_FEATURE_DEV_NUM (MAX_DFL_FPGA_PORT_NUM + 1)
32 32
33/* Reserved 0x0 for Header Group Register and 0xff for AFU */ 33/* Reserved 0xfe for Header Group Register and 0xff for AFU */
34#define FEATURE_ID_FIU_HEADER 0x0 34#define FEATURE_ID_FIU_HEADER 0xfe
35#define FEATURE_ID_AFU 0xff 35#define FEATURE_ID_AFU 0xff
36 36
37#define FME_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER 37#define FME_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER
@@ -119,6 +119,7 @@
119#define PORT_HDR_NEXT_AFU NEXT_AFU 119#define PORT_HDR_NEXT_AFU NEXT_AFU
120#define PORT_HDR_CAP 0x30 120#define PORT_HDR_CAP 0x30
121#define PORT_HDR_CTRL 0x38 121#define PORT_HDR_CTRL 0x38
122#define PORT_HDR_STS 0x40
122 123
123/* Port Capability Register Bitfield */ 124/* Port Capability Register Bitfield */
124#define PORT_CAP_PORT_NUM GENMASK_ULL(1, 0) /* ID of this port */ 125#define PORT_CAP_PORT_NUM GENMASK_ULL(1, 0) /* ID of this port */
@@ -130,6 +131,16 @@
130/* Latency tolerance reporting. '1' >= 40us, '0' < 40us.*/ 131/* Latency tolerance reporting. '1' >= 40us, '0' < 40us.*/
131#define PORT_CTRL_LATENCY BIT_ULL(2) 132#define PORT_CTRL_LATENCY BIT_ULL(2)
132#define PORT_CTRL_SFTRST_ACK BIT_ULL(4) /* HW ack for reset */ 133#define PORT_CTRL_SFTRST_ACK BIT_ULL(4) /* HW ack for reset */
134
135/* Port Status Register Bitfield */
136#define PORT_STS_AP2_EVT BIT_ULL(13) /* AP2 event detected */
137#define PORT_STS_AP1_EVT BIT_ULL(12) /* AP1 event detected */
138#define PORT_STS_PWR_STATE GENMASK_ULL(11, 8) /* AFU power states */
139#define PORT_STS_PWR_STATE_NORM 0
140#define PORT_STS_PWR_STATE_AP1 1 /* 50% throttling */
141#define PORT_STS_PWR_STATE_AP2 2 /* 90% throttling */
142#define PORT_STS_PWR_STATE_AP6 6 /* 100% throttling */
143
133/** 144/**
134 * struct dfl_fpga_port_ops - port ops 145 * struct dfl_fpga_port_ops - port ops
135 * 146 *
@@ -154,13 +165,22 @@ void dfl_fpga_port_ops_put(struct dfl_fpga_port_ops *ops);
154int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id); 165int dfl_fpga_check_port_id(struct platform_device *pdev, void *pport_id);
155 166
156/** 167/**
157 * struct dfl_feature_driver - sub feature's driver 168 * struct dfl_feature_id - dfl private feature id
158 * 169 *
159 * @id: sub feature id. 170 * @id: unique dfl private feature id.
160 * @ops: ops of this sub feature.
161 */ 171 */
162struct dfl_feature_driver { 172struct dfl_feature_id {
163 u64 id; 173 u64 id;
174};
175
176/**
177 * struct dfl_feature_driver - dfl private feature driver
178 *
179 * @id_table: id_table for dfl private features supported by this driver.
180 * @ops: ops of this dfl private feature driver.
181 */
182struct dfl_feature_driver {
183 const struct dfl_feature_id *id_table;
164 const struct dfl_feature_ops *ops; 184 const struct dfl_feature_ops *ops;
165}; 185};
166 186
@@ -183,6 +203,8 @@ struct dfl_feature {
183 203
184#define DEV_STATUS_IN_USE 0 204#define DEV_STATUS_IN_USE 0
185 205
206#define FEATURE_DEV_ID_UNUSED (-1)
207
186/** 208/**
187 * struct dfl_feature_platform_data - platform data for feature devices 209 * struct dfl_feature_platform_data - platform data for feature devices
188 * 210 *
@@ -191,6 +213,7 @@ struct dfl_feature {
191 * @cdev: cdev of feature dev. 213 * @cdev: cdev of feature dev.
192 * @dev: ptr to platform device linked with this platform data. 214 * @dev: ptr to platform device linked with this platform data.
193 * @dfl_cdev: ptr to container device. 215 * @dfl_cdev: ptr to container device.
216 * @id: id used for this feature device.
194 * @disable_count: count for port disable. 217 * @disable_count: count for port disable.
195 * @num: number for sub features. 218 * @num: number for sub features.
196 * @dev_status: dev status (e.g. DEV_STATUS_IN_USE). 219 * @dev_status: dev status (e.g. DEV_STATUS_IN_USE).
@@ -203,6 +226,7 @@ struct dfl_feature_platform_data {
203 struct cdev cdev; 226 struct cdev cdev;
204 struct platform_device *dev; 227 struct platform_device *dev;
205 struct dfl_fpga_cdev *dfl_cdev; 228 struct dfl_fpga_cdev *dfl_cdev;
229 int id;
206 unsigned int disable_count; 230 unsigned int disable_count;
207 unsigned long dev_status; 231 unsigned long dev_status;
208 void *private; 232 void *private;
@@ -373,6 +397,7 @@ void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info);
373 * @fme_dev: FME feature device under this container device. 397 * @fme_dev: FME feature device under this container device.
374 * @lock: mutex lock to protect the port device list. 398 * @lock: mutex lock to protect the port device list.
375 * @port_dev_list: list of all port feature devices under this container device. 399 * @port_dev_list: list of all port feature devices under this container device.
400 * @released_port_num: released port number under this container device.
376 */ 401 */
377struct dfl_fpga_cdev { 402struct dfl_fpga_cdev {
378 struct device *parent; 403 struct device *parent;
@@ -380,6 +405,7 @@ struct dfl_fpga_cdev {
380 struct device *fme_dev; 405 struct device *fme_dev;
381 struct mutex lock; 406 struct mutex lock;
382 struct list_head port_dev_list; 407 struct list_head port_dev_list;
408 int released_port_num;
383}; 409};
384 410
385struct dfl_fpga_cdev * 411struct dfl_fpga_cdev *
@@ -407,4 +433,9 @@ dfl_fpga_cdev_find_port(struct dfl_fpga_cdev *cdev, void *data,
407 433
408 return pdev; 434 return pdev;
409} 435}
436
437int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id);
438int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id);
439void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev);
440int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vf);
410#endif /* __FPGA_DFL_H */ 441#endif /* __FPGA_DFL_H */