Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fpga: dfl: fme: add DFL_FPGA_FME_PORT_RELEASE/ASSIGN ioctl support.

In order to support virtualization usage via PCIe SRIOV, this patch
adds two ioctls under FPGA Management Engine (FME) to release and
assign back the port device. In order to safely turn Port from PF
into VF and enable PCIe SRIOV, it requires user to invoke this
PORT_RELEASE ioctl to release port firstly to remove userspace
interfaces, and then configure the PF/VF access register in FME.
After disable SRIOV, it requires user to invoke this PORT_ASSIGN
ioctl to attach the port back to PF.

Ioctl interfaces:
* DFL_FPGA_FME_PORT_RELEASE
Release platform device of given port, it deletes port platform
device to remove related userspace interfaces on PF. After this
function, then it's safe to configure PF/VF access mode to VF,
and enable VFs via SRIOV.

* DFL_FPGA_FME_PORT_ASSIGN
Assign platform device of given port back to PF. After configure
PF/VF access mode to PF, this ioctl adds port platform device
back to re-enable related userspace interfaces on PF.

Signed-off-by: Zhang Yi Z <yi.z.zhang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@intel.com>
Signed-off-by: Wu Hao <hao.wu@intel.com>
Acked-by: Alan Tull <atull@kernel.org>
Acked-by: Moritz Fischer <mdf@kernel.org>
Signed-off-by: Moritz Fischer <mdf@kernel.org>
Link: https://lore.kernel.org/r/1564914022-3710-2-git-send-email-hao.wu@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Wu Hao and committed by
Greg Kroah-Hartman
69bb18dd 7008aff2

+171 -12
+42
drivers/fpga/dfl-fme-main.c
··· 16 16 17 17 #include <linux/kernel.h> 18 18 #include <linux/module.h> 19 + #include <linux/uaccess.h> 19 20 #include <linux/fpga-dfl.h> 20 21 21 22 #include "dfl.h" ··· 105 104 device_remove_groups(&pdev->dev, fme_hdr_groups); 106 105 } 107 106 107 + static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata, 108 + unsigned long arg) 109 + { 110 + struct dfl_fpga_cdev *cdev = pdata->dfl_cdev; 111 + int port_id; 112 + 113 + if (get_user(port_id, (int __user *)arg)) 114 + return -EFAULT; 115 + 116 + return dfl_fpga_cdev_release_port(cdev, port_id); 117 + } 118 + 119 + static long fme_hdr_ioctl_assign_port(struct dfl_feature_platform_data *pdata, 120 + unsigned long arg) 121 + { 122 + struct dfl_fpga_cdev *cdev = pdata->dfl_cdev; 123 + int port_id; 124 + 125 + if (get_user(port_id, (int __user *)arg)) 126 + return -EFAULT; 127 + 128 + return dfl_fpga_cdev_assign_port(cdev, port_id); 129 + } 130 + 131 + static long fme_hdr_ioctl(struct platform_device *pdev, 132 + struct dfl_feature *feature, 133 + unsigned int cmd, unsigned long arg) 134 + { 135 + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 136 + 137 + switch (cmd) { 138 + case DFL_FPGA_FME_PORT_RELEASE: 139 + return fme_hdr_ioctl_release_port(pdata, arg); 140 + case DFL_FPGA_FME_PORT_ASSIGN: 141 + return fme_hdr_ioctl_assign_port(pdata, arg); 142 + } 143 + 144 + return -ENODEV; 145 + } 146 + 108 147 static const struct dfl_feature_ops fme_hdr_ops = { 109 148 .init = fme_hdr_init, 110 149 .uinit = fme_hdr_uinit, 150 + .ioctl = fme_hdr_ioctl, 111 151 }; 112 152 113 153 static struct dfl_feature_driver fme_feature_drvs[] = {
+101 -12
drivers/fpga/dfl.c
··· 231 231 */ 232 232 int 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); 235 - int port_id; 234 + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 235 + struct dfl_fpga_port_ops *port_ops; 236 236 237 + if (pdata->id != FEATURE_DEV_ID_UNUSED) 238 + return pdata->id == *(int *)pport_id; 239 + 240 + port_ops = dfl_fpga_port_ops_get(pdev); 237 241 if (!port_ops || !port_ops->get_id) 238 242 return 0; 239 243 240 - port_id = port_ops->get_id(pdev); 244 + pdata->id = port_ops->get_id(pdev); 241 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 } 245 249 EXPORT_SYMBOL_GPL(dfl_fpga_check_port_id); 246 250 ··· 478 474 pdata->dev = fdev; 479 475 pdata->num = binfo->feature_num; 480 476 pdata->dfl_cdev = binfo->cdev; 477 + pdata->id = FEATURE_DEV_ID_UNUSED; 481 478 mutex_init(&pdata->lock); 482 479 lockdep_set_class_and_name(&pdata->lock, &dfl_pdata_keys[type], 483 480 dfl_pdata_key_strings[type]); ··· 978 973 { 979 974 struct dfl_feature_platform_data *pdata, *ptmp; 980 975 981 - remove_feature_devs(cdev); 982 - 983 976 mutex_lock(&cdev->lock); 984 - if (cdev->fme_dev) { 985 - /* the fme should be unregistered. */ 986 - WARN_ON(device_is_registered(cdev->fme_dev)); 977 + if (cdev->fme_dev) 987 978 put_device(cdev->fme_dev); 988 - } 989 979 990 980 list_for_each_entry_safe(pdata, ptmp, &cdev->port_dev_list, node) { 991 981 struct platform_device *port_dev = pdata->dev; 992 982 993 - /* the port should be unregistered. */ 994 - WARN_ON(device_is_registered(&port_dev->dev)); 983 + /* remove released ports */ 984 + if (!device_is_registered(&port_dev->dev)) { 985 + dfl_id_free(feature_dev_id_type(port_dev), 986 + port_dev->id); 987 + platform_device_put(port_dev); 988 + } 989 + 995 990 list_del(&pdata->node); 996 991 put_device(&port_dev->dev); 997 992 } 998 993 mutex_unlock(&cdev->lock); 994 + 995 + remove_feature_devs(cdev); 999 996 1000 997 fpga_region_unregister(cdev->region); 1001 998 devm_kfree(cdev->parent, cdev); ··· 1048 1041 1049 1042 return ret; 1050 1043 } 1044 + 1045 + /** 1046 + * dfl_fpga_cdev_release_port - release a port platform device 1047 + * 1048 + * @cdev: parent container device. 1049 + * @port_id: id of the port platform device. 1050 + * 1051 + * This function allows user to release a port platform device. This is a 1052 + * mandatory step before turn a port from PF into VF for SRIOV support. 1053 + * 1054 + * Return: 0 on success, negative error code otherwise. 1055 + */ 1056 + int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id) 1057 + { 1058 + struct platform_device *port_pdev; 1059 + int ret = -ENODEV; 1060 + 1061 + mutex_lock(&cdev->lock); 1062 + port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id, 1063 + dfl_fpga_check_port_id); 1064 + if (!port_pdev) 1065 + goto unlock_exit; 1066 + 1067 + if (!device_is_registered(&port_pdev->dev)) { 1068 + ret = -EBUSY; 1069 + goto put_dev_exit; 1070 + } 1071 + 1072 + ret = dfl_feature_dev_use_begin(dev_get_platdata(&port_pdev->dev)); 1073 + if (ret) 1074 + goto put_dev_exit; 1075 + 1076 + platform_device_del(port_pdev); 1077 + cdev->released_port_num++; 1078 + put_dev_exit: 1079 + put_device(&port_pdev->dev); 1080 + unlock_exit: 1081 + mutex_unlock(&cdev->lock); 1082 + return ret; 1083 + } 1084 + EXPORT_SYMBOL_GPL(dfl_fpga_cdev_release_port); 1085 + 1086 + /** 1087 + * dfl_fpga_cdev_assign_port - assign a port platform device back 1088 + * 1089 + * @cdev: parent container device. 1090 + * @port_id: id of the port platform device. 1091 + * 1092 + * This function allows user to assign a port platform device back. This is 1093 + * a mandatory step after disable SRIOV support. 1094 + * 1095 + * Return: 0 on success, negative error code otherwise. 1096 + */ 1097 + int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id) 1098 + { 1099 + struct platform_device *port_pdev; 1100 + int ret = -ENODEV; 1101 + 1102 + mutex_lock(&cdev->lock); 1103 + port_pdev = __dfl_fpga_cdev_find_port(cdev, &port_id, 1104 + dfl_fpga_check_port_id); 1105 + if (!port_pdev) 1106 + goto unlock_exit; 1107 + 1108 + if (device_is_registered(&port_pdev->dev)) { 1109 + ret = -EBUSY; 1110 + goto put_dev_exit; 1111 + } 1112 + 1113 + ret = platform_device_add(port_pdev); 1114 + if (ret) 1115 + goto put_dev_exit; 1116 + 1117 + dfl_feature_dev_use_end(dev_get_platdata(&port_pdev->dev)); 1118 + cdev->released_port_num--; 1119 + put_dev_exit: 1120 + put_device(&port_pdev->dev); 1121 + unlock_exit: 1122 + mutex_unlock(&cdev->lock); 1123 + return ret; 1124 + } 1125 + EXPORT_SYMBOL_GPL(dfl_fpga_cdev_assign_port); 1051 1126 1052 1127 static void __exit dfl_fpga_exit(void) 1053 1128 {
+10
drivers/fpga/dfl.h
··· 183 183 184 184 #define DEV_STATUS_IN_USE 0 185 185 186 + #define FEATURE_DEV_ID_UNUSED (-1) 187 + 186 188 /** 187 189 * struct dfl_feature_platform_data - platform data for feature devices 188 190 * ··· 193 191 * @cdev: cdev of feature dev. 194 192 * @dev: ptr to platform device linked with this platform data. 195 193 * @dfl_cdev: ptr to container device. 194 + * @id: id used for this feature device. 196 195 * @disable_count: count for port disable. 197 196 * @num: number for sub features. 198 197 * @dev_status: dev status (e.g. DEV_STATUS_IN_USE). ··· 206 203 struct cdev cdev; 207 204 struct platform_device *dev; 208 205 struct dfl_fpga_cdev *dfl_cdev; 206 + int id; 209 207 unsigned int disable_count; 210 208 unsigned long dev_status; 211 209 void *private; ··· 377 373 * @fme_dev: FME feature device under this container device. 378 374 * @lock: mutex lock to protect the port device list. 379 375 * @port_dev_list: list of all port feature devices under this container device. 376 + * @released_port_num: released port number under this container device. 380 377 */ 381 378 struct dfl_fpga_cdev { 382 379 struct device *parent; ··· 385 380 struct device *fme_dev; 386 381 struct mutex lock; 387 382 struct list_head port_dev_list; 383 + int released_port_num; 388 384 }; 389 385 390 386 struct dfl_fpga_cdev * ··· 413 407 414 408 return pdev; 415 409 } 410 + 411 + int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id); 412 + int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id); 413 + 416 414 #endif /* __FPGA_DFL_H */
+18
include/uapi/linux/fpga-dfl.h
··· 176 176 177 177 #define DFL_FPGA_FME_PORT_PR _IO(DFL_FPGA_MAGIC, DFL_FME_BASE + 0) 178 178 179 + /** 180 + * DFL_FPGA_FME_PORT_RELEASE - _IOW(DFL_FPGA_MAGIC, DFL_FME_BASE + 1, 181 + * int port_id) 182 + * 183 + * Driver releases the port per Port ID provided by caller. 184 + * Return: 0 on success, -errno on failure. 185 + */ 186 + #define DFL_FPGA_FME_PORT_RELEASE _IOW(DFL_FPGA_MAGIC, DFL_FME_BASE + 1, int) 187 + 188 + /** 189 + * DFL_FPGA_FME_PORT_ASSIGN - _IOW(DFL_FPGA_MAGIC, DFL_FME_BASE + 2, 190 + * int port_id) 191 + * 192 + * Driver assigns the port back per Port ID provided by caller. 193 + * Return: 0 on success, -errno on failure. 194 + */ 195 + #define DFL_FPGA_FME_PORT_ASSIGN _IOW(DFL_FPGA_MAGIC, DFL_FME_BASE + 2, int) 196 + 179 197 #endif /* _UAPI_LINUX_FPGA_DFL_H */