1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for FPGA Management Engine (FME) 4 * 5 * Copyright (C) 2017-2018 Intel Corporation, Inc. 6 * 7 * Authors: 8 * Kang Luwei <luwei.kang@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> 15 */ 16 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/uaccess.h> 20 #include <linux/fpga-dfl.h> 21 22 #include "dfl.h" 23 #include "dfl-fme.h" 24 25 static ssize_t ports_num_show(struct device *dev, 26 struct device_attribute *attr, char *buf) 27 { 28 void __iomem *base; 29 u64 v; 30 31 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); 32 33 v = readq(base + FME_HDR_CAP); 34 35 return scnprintf(buf, PAGE_SIZE, "%u\n", 36 (unsigned int)FIELD_GET(FME_CAP_NUM_PORTS, v)); 37 } 38 static DEVICE_ATTR_RO(ports_num); 39 40 /* 41 * Bitstream (static FPGA region) identifier number. It contains the 42 * detailed version and other information of this static FPGA region. 43 */ 44 static ssize_t bitstream_id_show(struct device *dev, 45 struct device_attribute *attr, char *buf) 46 { 47 void __iomem *base; 48 u64 v; 49 50 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); 51 52 v = readq(base + FME_HDR_BITSTREAM_ID); 53 54 return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v); 55 } 56 static DEVICE_ATTR_RO(bitstream_id); 57 58 /* 59 * Bitstream (static FPGA region) meta data. It contains the synthesis 60 * date, seed and other information of this static FPGA region. 61 */ 62 static ssize_t bitstream_metadata_show(struct device *dev, 63 struct device_attribute *attr, char *buf) 64 { 65 void __iomem *base; 66 u64 v; 67 68 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER); 69 70 v = readq(base + FME_HDR_BITSTREAM_MD); 71 72 return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v); 73 } 74 static DEVICE_ATTR_RO(bitstream_metadata); 75 76 static 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 } 89 static DEVICE_ATTR_RO(cache_size); 90 91 static 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 } 104 static DEVICE_ATTR_RO(fabric_version); 105 106 static 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 } 119 static DEVICE_ATTR_RO(socket_id); 120 121 static struct attribute *fme_hdr_attrs[] = { 122 &dev_attr_ports_num.attr, 123 &dev_attr_bitstream_id.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, 128 NULL, 129 }; 130 ATTRIBUTE_GROUPS(fme_hdr); 131 132 static int fme_hdr_init(struct platform_device *pdev, 133 struct dfl_feature *feature) 134 { 135 void __iomem *base = feature->ioaddr; 136 int ret; 137 138 dev_dbg(&pdev->dev, "FME HDR Init.\n"); 139 dev_dbg(&pdev->dev, "FME cap %llx.\n", 140 (unsigned long long)readq(base + FME_HDR_CAP)); 141 142 ret = device_add_groups(&pdev->dev, fme_hdr_groups); 143 if (ret) 144 return ret; 145 146 return 0; 147 } 148 149 static void fme_hdr_uinit(struct platform_device *pdev, 150 struct dfl_feature *feature) 151 { 152 dev_dbg(&pdev->dev, "FME HDR UInit.\n"); 153 device_remove_groups(&pdev->dev, fme_hdr_groups); 154 } 155 156 static 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 168 static 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); 178 } 179 180 static 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 196 static const struct dfl_feature_id fme_hdr_id_table[] = { 197 {.id = FME_FEATURE_ID_HEADER,}, 198 {0,} 199 }; 200 201 static const struct dfl_feature_ops fme_hdr_ops = { 202 .init = fme_hdr_init, 203 .uinit = fme_hdr_uinit, 204 .ioctl = fme_hdr_ioctl, 205 }; 206 207 static struct dfl_feature_driver fme_feature_drvs[] = { 208 { 209 .id_table = fme_hdr_id_table, 210 .ops = &fme_hdr_ops, 211 }, 212 { 213 .id_table = fme_pr_mgmt_id_table, 214 .ops = &fme_pr_mgmt_ops, 215 }, 216 { 217 .ops = NULL, 218 }, 219 }; 220 221 static long fme_ioctl_check_extension(struct dfl_feature_platform_data *pdata, 222 unsigned long arg) 223 { 224 /* No extension support for now */ 225 return 0; 226 } 227 228 static int fme_open(struct inode *inode, struct file *filp) 229 { 230 struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode); 231 struct dfl_feature_platform_data *pdata = dev_get_platdata(&fdev->dev); 232 int ret; 233 234 if (WARN_ON(!pdata)) 235 return -ENODEV; 236 237 ret = dfl_feature_dev_use_begin(pdata); 238 if (ret) 239 return ret; 240 241 dev_dbg(&fdev->dev, "Device File Open\n"); 242 filp->private_data = pdata; 243 244 return 0; 245 } 246 247 static int fme_release(struct inode *inode, struct file *filp) 248 { 249 struct dfl_feature_platform_data *pdata = filp->private_data; 250 struct platform_device *pdev = pdata->dev; 251 252 dev_dbg(&pdev->dev, "Device File Release\n"); 253 dfl_feature_dev_use_end(pdata); 254 255 return 0; 256 } 257 258 static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 259 { 260 struct dfl_feature_platform_data *pdata = filp->private_data; 261 struct platform_device *pdev = pdata->dev; 262 struct dfl_feature *f; 263 long ret; 264 265 dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd); 266 267 switch (cmd) { 268 case DFL_FPGA_GET_API_VERSION: 269 return DFL_FPGA_API_VERSION; 270 case DFL_FPGA_CHECK_EXTENSION: 271 return fme_ioctl_check_extension(pdata, arg); 272 default: 273 /* 274 * Let sub-feature's ioctl function to handle the cmd. 275 * Sub-feature's ioctl returns -ENODEV when cmd is not 276 * handled in this sub feature, and returns 0 or other 277 * error code if cmd is handled. 278 */ 279 dfl_fpga_dev_for_each_feature(pdata, f) { 280 if (f->ops && f->ops->ioctl) { 281 ret = f->ops->ioctl(pdev, f, cmd, arg); 282 if (ret != -ENODEV) 283 return ret; 284 } 285 } 286 } 287 288 return -EINVAL; 289 } 290 291 static int fme_dev_init(struct platform_device *pdev) 292 { 293 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 294 struct dfl_fme *fme; 295 296 fme = devm_kzalloc(&pdev->dev, sizeof(*fme), GFP_KERNEL); 297 if (!fme) 298 return -ENOMEM; 299 300 fme->pdata = pdata; 301 302 mutex_lock(&pdata->lock); 303 dfl_fpga_pdata_set_private(pdata, fme); 304 mutex_unlock(&pdata->lock); 305 306 return 0; 307 } 308 309 static void fme_dev_destroy(struct platform_device *pdev) 310 { 311 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); 312 struct dfl_fme *fme; 313 314 mutex_lock(&pdata->lock); 315 fme = dfl_fpga_pdata_get_private(pdata); 316 dfl_fpga_pdata_set_private(pdata, NULL); 317 mutex_unlock(&pdata->lock); 318 } 319 320 static const struct file_operations fme_fops = { 321 .owner = THIS_MODULE, 322 .open = fme_open, 323 .release = fme_release, 324 .unlocked_ioctl = fme_ioctl, 325 }; 326 327 static int fme_probe(struct platform_device *pdev) 328 { 329 int ret; 330 331 ret = fme_dev_init(pdev); 332 if (ret) 333 goto exit; 334 335 ret = dfl_fpga_dev_feature_init(pdev, fme_feature_drvs); 336 if (ret) 337 goto dev_destroy; 338 339 ret = dfl_fpga_dev_ops_register(pdev, &fme_fops, THIS_MODULE); 340 if (ret) 341 goto feature_uinit; 342 343 return 0; 344 345 feature_uinit: 346 dfl_fpga_dev_feature_uinit(pdev); 347 dev_destroy: 348 fme_dev_destroy(pdev); 349 exit: 350 return ret; 351 } 352 353 static int fme_remove(struct platform_device *pdev) 354 { 355 dfl_fpga_dev_ops_unregister(pdev); 356 dfl_fpga_dev_feature_uinit(pdev); 357 fme_dev_destroy(pdev); 358 359 return 0; 360 } 361 362 static struct platform_driver fme_driver = { 363 .driver = { 364 .name = DFL_FPGA_FEATURE_DEV_FME, 365 }, 366 .probe = fme_probe, 367 .remove = fme_remove, 368 }; 369 370 module_platform_driver(fme_driver); 371 372 MODULE_DESCRIPTION("FPGA Management Engine driver"); 373 MODULE_AUTHOR("Intel Corporation"); 374 MODULE_LICENSE("GPL v2"); 375 MODULE_ALIAS("platform:dfl-fme"); 376