summaryrefslogtreecommitdiffstats
path: root/drivers/fpga/dfl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/fpga/dfl.c')
-rw-r--r--drivers/fpga/dfl.c226
1 files changed, 207 insertions, 19 deletions
diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c
index 4b66aaa32b5a..96a2b8274a33 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}
@@ -266,17 +271,34 @@ static int dfl_feature_instance_init(struct platform_device *pdev,
266 struct dfl_feature *feature, 271 struct dfl_feature *feature,
267 struct dfl_feature_driver *drv) 272 struct dfl_feature_driver *drv)
268{ 273{
269 int ret; 274 int ret = 0;
270 275
271 ret = drv->ops->init(pdev, feature); 276 if (drv->ops->init) {
272 if (ret) 277 ret = drv->ops->init(pdev, feature);
273 return ret; 278 if (ret)
279 return ret;
280 }
274 281
275 feature->ops = drv->ops; 282 feature->ops = drv->ops;
276 283
277 return ret; 284 return ret;
278} 285}
279 286
287static bool dfl_feature_drv_match(struct dfl_feature *feature,
288 struct dfl_feature_driver *driver)
289{
290 const struct dfl_feature_id *ids = driver->id_table;
291
292 if (ids) {
293 while (ids->id) {
294 if (ids->id == feature->id)
295 return true;
296 ids++;
297 }
298 }
299 return false;
300}
301
280/** 302/**
281 * dfl_fpga_dev_feature_init - init for sub features of dfl feature device 303 * dfl_fpga_dev_feature_init - init for sub features of dfl feature device
282 * @pdev: feature device. 304 * @pdev: feature device.
@@ -297,8 +319,7 @@ int dfl_fpga_dev_feature_init(struct platform_device *pdev,
297 319
298 while (drv->ops) { 320 while (drv->ops) {
299 dfl_fpga_dev_for_each_feature(pdata, feature) { 321 dfl_fpga_dev_for_each_feature(pdata, feature) {
300 /* match feature and drv using id */ 322 if (dfl_feature_drv_match(feature, drv)) {
301 if (feature->id == drv->id) {
302 ret = dfl_feature_instance_init(pdev, pdata, 323 ret = dfl_feature_instance_init(pdev, pdata,
303 feature, drv); 324 feature, drv);
304 if (ret) 325 if (ret)
@@ -474,6 +495,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
474 pdata->dev = fdev; 495 pdata->dev = fdev;
475 pdata->num = binfo->feature_num; 496 pdata->num = binfo->feature_num;
476 pdata->dfl_cdev = binfo->cdev; 497 pdata->dfl_cdev = binfo->cdev;
498 pdata->id = FEATURE_DEV_ID_UNUSED;
477 mutex_init(&pdata->lock); 499 mutex_init(&pdata->lock);
478 lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type], 500 lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type],
479 dfl_pdata_key_strings[type]); 501 dfl_pdata_key_strings[type]);
@@ -973,25 +995,27 @@ void dfl_fpga_feature_devs_remove(struct dfl_fpga_cdev *cdev)
973{ 995{
974 struct dfl_feature_platform_data *pdata, *ptmp; 996 struct dfl_feature_platform_data *pdata, *ptmp;
975 997
976 remove_feature_devs(cdev);
977
978 mutex_lock(&cdev->lock); 998 mutex_lock(&cdev->lock);
979 if (cdev->fme_dev) { 999 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); 1000 put_device(cdev->fme_dev);
983 }
984 1001
985 list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) { 1002 list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) {
986 struct platform_device *port_dev = pdata->dev; 1003 struct platform_device *port_dev = pdata->dev;
987 1004
988 /* the port should be unregistered. */ 1005 /* remove released ports */
989 WARN_ON(device_is_registered(&port_dev->dev)); 1006 if (!device_is_registered(&port_dev->dev)) {
1007 dfl_id_free(feature_dev_id_type(port_dev),
1008 port_dev->id);
1009 platform_device_put(port_dev);
1010 }
1011
990 list_del(&pdata->node); 1012 list_del(&pdata->node);
991 put_device(&port_dev->dev); 1013 put_device(&port_dev->dev);
992 } 1014 }
993 mutex_unlock(&cdev->lock); 1015 mutex_unlock(&cdev->lock);
994 1016
1017 remove_feature_devs(cdev);
1018
995 fpga_region_unregister(cdev->region); 1019 fpga_region_unregister(cdev->region);
996 devm_kfree(cdev->parent, cdev); 1020 devm_kfree(cdev->parent, cdev);
997} 1021}
@@ -1042,6 +1066,170 @@ static int __init dfl_fpga_init(void)
1042 return ret; 1066 return ret;
1043} 1067}
1044 1068
1069/**
1070 * dfl_fpga_cdev_release_port - release a port platform device
1071 *
1072 * @cdev: parent container device.
1073 * @port_id: id of the port platform device.
1074 *
1075 * This function allows user to release a port platform device. This is a
1076 * mandatory step before turn a port from PF into VF for SRIOV support.
1077 *
1078 * Return: 0 on success, negative error code otherwise.
1079 */
1080int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id)
1081{
1082 struct platform_device *port_pdev;
1083 int ret = -ENODEV;
1084
1085 mutex_lock(&cdev->lock);
1086 port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id,
1087 dfl_fpga_check_port_id);
1088 if (!port_pdev)
1089 goto unlock_exit;
1090
1091 if (!device_is_registered(&port_pdev->dev)) {
1092 ret = -EBUSY;
1093 goto put_dev_exit;
1094 }
1095
1096 ret = dfl_feature_dev_use_begin(dev_get_platdata(&port_pdev->dev));
1097 if (ret)
1098 goto put_dev_exit;
1099
1100 platform_device_del(port_pdev);
1101 cdev->released_port_num++;
1102put_dev_exit:
1103 put_device(&port_pdev->dev);
1104unlock_exit:
1105 mutex_unlock(&cdev->lock);
1106 return ret;
1107}
1108EXPORT_SYMBOL_GPL(dfl_fpga_cdev_release_port);
1109
1110/**
1111 * dfl_fpga_cdev_assign_port - assign a port platform device back
1112 *
1113 * @cdev: parent container device.
1114 * @port_id: id of the port platform device.
1115 *
1116 * This function allows user to assign a port platform device back. This is
1117 * a mandatory step after disable SRIOV support.
1118 *
1119 * Return: 0 on success, negative error code otherwise.
1120 */
1121int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id)
1122{
1123 struct platform_device *port_pdev;
1124 int ret = -ENODEV;
1125
1126 mutex_lock(&cdev->lock);
1127 port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id,
1128 dfl_fpga_check_port_id);
1129 if (!port_pdev)
1130 goto unlock_exit;
1131
1132 if (device_is_registered(&port_pdev->dev)) {
1133 ret = -EBUSY;
1134 goto put_dev_exit;
1135 }
1136
1137 ret = platform_device_add(port_pdev);
1138 if (ret)
1139 goto put_dev_exit;
1140
1141 dfl_feature_dev_use_end(dev_get_platdata(&port_pdev->dev));
1142 cdev->released_port_num--;
1143put_dev_exit:
1144 put_device(&port_pdev->dev);
1145unlock_exit:
1146 mutex_unlock(&cdev->lock);
1147 return ret;
1148}
1149EXPORT_SYMBOL_GPL(dfl_fpga_cdev_assign_port);
1150
1151static void config_port_access_mode(struct device *fme_dev, int port_id,
1152 bool is_vf)
1153{
1154 void __iomem *base;
1155 u64 v;
1156
1157 base = dfl_get_feature_ioaddr_by_id(fme_dev, FME_FEATURE_ID_HEADER);
1158
1159 v = readq(base + FME_HDR_PORT_OFST(port_id));
1160
1161 v &= ~FME_PORT_OFST_ACC_CTRL;
1162 v |= FIELD_PREP(FME_PORT_OFST_ACC_CTRL,
1163 is_vf ? FME_PORT_OFST_ACC_VF : FME_PORT_OFST_ACC_PF);
1164
1165 writeq(v, base + FME_HDR_PORT_OFST(port_id));
1166}
1167
1168#define config_port_vf_mode(dev, id) config_port_access_mode(dev, id, true)
1169#define config_port_pf_mode(dev, id) config_port_access_mode(dev, id, false)
1170
1171/**
1172 * dfl_fpga_cdev_config_ports_pf - configure ports to PF access mode
1173 *
1174 * @cdev: parent container device.
1175 *
1176 * This function is needed in sriov configuration routine. It could be used to
1177 * configure the all released ports from VF access mode to PF.
1178 */
1179void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev)
1180{
1181 struct dfl_feature_platform_data *pdata;
1182
1183 mutex_lock(&cdev->lock);
1184 list_for_each_entry(pdata, &cdev->port_dev_list, node) {
1185 if (device_is_registered(&pdata->dev->dev))
1186 continue;
1187
1188 config_port_pf_mode(cdev->fme_dev, pdata->id);
1189 }
1190 mutex_unlock(&cdev->lock);
1191}
1192EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_pf);
1193
1194/**
1195 * dfl_fpga_cdev_config_ports_vf - configure ports to VF access mode
1196 *
1197 * @cdev: parent container device.
1198 * @num_vfs: VF device number.
1199 *
1200 * This function is needed in sriov configuration routine. It could be used to
1201 * configure the released ports from PF access mode to VF.
1202 *
1203 * Return: 0 on success, negative error code otherwise.
1204 */
1205int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vfs)
1206{
1207 struct dfl_feature_platform_data *pdata;
1208 int ret = 0;
1209
1210 mutex_lock(&cdev->lock);
1211 /*
1212 * can't turn multiple ports into 1 VF device, only 1 port for 1 VF
1213 * device, so if released port number doesn't match VF device number,
1214 * then reject the request with -EINVAL error code.
1215 */
1216 if (cdev->released_port_num != num_vfs) {
1217 ret = -EINVAL;
1218 goto done;
1219 }
1220
1221 list_for_each_entry(pdata, &cdev->port_dev_list, node) {
1222 if (device_is_registered(&pdata->dev->dev))
1223 continue;
1224
1225 config_port_vf_mode(cdev->fme_dev, pdata->id);
1226 }
1227done:
1228 mutex_unlock(&cdev->lock);
1229 return ret;
1230}
1231EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_vf);
1232
1045static void __exit dfl_fpga_exit(void) 1233static void __exit dfl_fpga_exit(void)
1046{ 1234{
1047 dfl_chardev_uinit(); 1235 dfl_chardev_uinit();