Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for FPGA Management Engine (FME) Partial Reconfiguration
0004  *
0005  * Copyright (C) 2017-2018 Intel Corporation, Inc.
0006  *
0007  * Authors:
0008  *   Kang Luwei <luwei.kang@intel.com>
0009  *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
0010  *   Wu Hao <hao.wu@intel.com>
0011  *   Joseph Grecco <joe.grecco@intel.com>
0012  *   Enno Luebbers <enno.luebbers@intel.com>
0013  *   Tim Whisonant <tim.whisonant@intel.com>
0014  *   Ananda Ravuri <ananda.ravuri@intel.com>
0015  *   Christopher Rauer <christopher.rauer@intel.com>
0016  *   Henry Mitchel <henry.mitchel@intel.com>
0017  */
0018 
0019 #include <linux/types.h>
0020 #include <linux/device.h>
0021 #include <linux/vmalloc.h>
0022 #include <linux/uaccess.h>
0023 #include <linux/fpga/fpga-mgr.h>
0024 #include <linux/fpga/fpga-bridge.h>
0025 #include <linux/fpga/fpga-region.h>
0026 #include <linux/fpga-dfl.h>
0027 
0028 #include "dfl.h"
0029 #include "dfl-fme.h"
0030 #include "dfl-fme-pr.h"
0031 
0032 static struct dfl_fme_region *
0033 dfl_fme_region_find_by_port_id(struct dfl_fme *fme, int port_id)
0034 {
0035     struct dfl_fme_region *fme_region;
0036 
0037     list_for_each_entry(fme_region, &fme->region_list, node)
0038         if (fme_region->port_id == port_id)
0039             return fme_region;
0040 
0041     return NULL;
0042 }
0043 
0044 static int dfl_fme_region_match(struct device *dev, const void *data)
0045 {
0046     return dev->parent == data;
0047 }
0048 
0049 static struct fpga_region *dfl_fme_region_find(struct dfl_fme *fme, int port_id)
0050 {
0051     struct dfl_fme_region *fme_region;
0052     struct fpga_region *region;
0053 
0054     fme_region = dfl_fme_region_find_by_port_id(fme, port_id);
0055     if (!fme_region)
0056         return NULL;
0057 
0058     region = fpga_region_class_find(NULL, &fme_region->region->dev,
0059                     dfl_fme_region_match);
0060     if (!region)
0061         return NULL;
0062 
0063     return region;
0064 }
0065 
0066 static int fme_pr(struct platform_device *pdev, unsigned long arg)
0067 {
0068     struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
0069     void __user *argp = (void __user *)arg;
0070     struct dfl_fpga_fme_port_pr port_pr;
0071     struct fpga_image_info *info;
0072     struct fpga_region *region;
0073     void __iomem *fme_hdr;
0074     struct dfl_fme *fme;
0075     unsigned long minsz;
0076     void *buf = NULL;
0077     size_t length;
0078     int ret = 0;
0079     u64 v;
0080 
0081     minsz = offsetofend(struct dfl_fpga_fme_port_pr, buffer_address);
0082 
0083     if (copy_from_user(&port_pr, argp, minsz))
0084         return -EFAULT;
0085 
0086     if (port_pr.argsz < minsz || port_pr.flags)
0087         return -EINVAL;
0088 
0089     /* get fme header region */
0090     fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev,
0091                            FME_FEATURE_ID_HEADER);
0092 
0093     /* check port id */
0094     v = readq(fme_hdr + FME_HDR_CAP);
0095     if (port_pr.port_id >= FIELD_GET(FME_CAP_NUM_PORTS, v)) {
0096         dev_dbg(&pdev->dev, "port number more than maximum\n");
0097         return -EINVAL;
0098     }
0099 
0100     /*
0101      * align PR buffer per PR bandwidth, as HW ignores the extra padding
0102      * data automatically.
0103      */
0104     length = ALIGN(port_pr.buffer_size, 4);
0105 
0106     buf = vmalloc(length);
0107     if (!buf)
0108         return -ENOMEM;
0109 
0110     if (copy_from_user(buf,
0111                (void __user *)(unsigned long)port_pr.buffer_address,
0112                port_pr.buffer_size)) {
0113         ret = -EFAULT;
0114         goto free_exit;
0115     }
0116 
0117     /* prepare fpga_image_info for PR */
0118     info = fpga_image_info_alloc(&pdev->dev);
0119     if (!info) {
0120         ret = -ENOMEM;
0121         goto free_exit;
0122     }
0123 
0124     info->flags |= FPGA_MGR_PARTIAL_RECONFIG;
0125 
0126     mutex_lock(&pdata->lock);
0127     fme = dfl_fpga_pdata_get_private(pdata);
0128     /* fme device has been unregistered. */
0129     if (!fme) {
0130         ret = -EINVAL;
0131         goto unlock_exit;
0132     }
0133 
0134     region = dfl_fme_region_find(fme, port_pr.port_id);
0135     if (!region) {
0136         ret = -EINVAL;
0137         goto unlock_exit;
0138     }
0139 
0140     fpga_image_info_free(region->info);
0141 
0142     info->buf = buf;
0143     info->count = length;
0144     info->region_id = port_pr.port_id;
0145     region->info = info;
0146 
0147     ret = fpga_region_program_fpga(region);
0148 
0149     /*
0150      * it allows userspace to reset the PR region's logic by disabling and
0151      * reenabling the bridge to clear things out between acceleration runs.
0152      * so no need to hold the bridges after partial reconfiguration.
0153      */
0154     if (region->get_bridges)
0155         fpga_bridges_put(&region->bridge_list);
0156 
0157     put_device(&region->dev);
0158 unlock_exit:
0159     mutex_unlock(&pdata->lock);
0160 free_exit:
0161     vfree(buf);
0162     return ret;
0163 }
0164 
0165 /**
0166  * dfl_fme_create_mgr - create fpga mgr platform device as child device
0167  *
0168  * @pdata: fme platform_device's pdata
0169  *
0170  * Return: mgr platform device if successful, and error code otherwise.
0171  */
0172 static struct platform_device *
0173 dfl_fme_create_mgr(struct dfl_feature_platform_data *pdata,
0174            struct dfl_feature *feature)
0175 {
0176     struct platform_device *mgr, *fme = pdata->dev;
0177     struct dfl_fme_mgr_pdata mgr_pdata;
0178     int ret = -ENOMEM;
0179 
0180     if (!feature->ioaddr)
0181         return ERR_PTR(-ENODEV);
0182 
0183     mgr_pdata.ioaddr = feature->ioaddr;
0184 
0185     /*
0186      * Each FME has only one fpga-mgr, so allocate platform device using
0187      * the same FME platform device id.
0188      */
0189     mgr = platform_device_alloc(DFL_FPGA_FME_MGR, fme->id);
0190     if (!mgr)
0191         return ERR_PTR(ret);
0192 
0193     mgr->dev.parent = &fme->dev;
0194 
0195     ret = platform_device_add_data(mgr, &mgr_pdata, sizeof(mgr_pdata));
0196     if (ret)
0197         goto create_mgr_err;
0198 
0199     ret = platform_device_add(mgr);
0200     if (ret)
0201         goto create_mgr_err;
0202 
0203     return mgr;
0204 
0205 create_mgr_err:
0206     platform_device_put(mgr);
0207     return ERR_PTR(ret);
0208 }
0209 
0210 /**
0211  * dfl_fme_destroy_mgr - destroy fpga mgr platform device
0212  * @pdata: fme platform device's pdata
0213  */
0214 static void dfl_fme_destroy_mgr(struct dfl_feature_platform_data *pdata)
0215 {
0216     struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata);
0217 
0218     platform_device_unregister(priv->mgr);
0219 }
0220 
0221 /**
0222  * dfl_fme_create_bridge - create fme fpga bridge platform device as child
0223  *
0224  * @pdata: fme platform device's pdata
0225  * @port_id: port id for the bridge to be created.
0226  *
0227  * Return: bridge platform device if successful, and error code otherwise.
0228  */
0229 static struct dfl_fme_bridge *
0230 dfl_fme_create_bridge(struct dfl_feature_platform_data *pdata, int port_id)
0231 {
0232     struct device *dev = &pdata->dev->dev;
0233     struct dfl_fme_br_pdata br_pdata;
0234     struct dfl_fme_bridge *fme_br;
0235     int ret = -ENOMEM;
0236 
0237     fme_br = devm_kzalloc(dev, sizeof(*fme_br), GFP_KERNEL);
0238     if (!fme_br)
0239         return ERR_PTR(ret);
0240 
0241     br_pdata.cdev = pdata->dfl_cdev;
0242     br_pdata.port_id = port_id;
0243 
0244     fme_br->br = platform_device_alloc(DFL_FPGA_FME_BRIDGE,
0245                        PLATFORM_DEVID_AUTO);
0246     if (!fme_br->br)
0247         return ERR_PTR(ret);
0248 
0249     fme_br->br->dev.parent = dev;
0250 
0251     ret = platform_device_add_data(fme_br->br, &br_pdata, sizeof(br_pdata));
0252     if (ret)
0253         goto create_br_err;
0254 
0255     ret = platform_device_add(fme_br->br);
0256     if (ret)
0257         goto create_br_err;
0258 
0259     return fme_br;
0260 
0261 create_br_err:
0262     platform_device_put(fme_br->br);
0263     return ERR_PTR(ret);
0264 }
0265 
0266 /**
0267  * dfl_fme_destroy_bridge - destroy fpga bridge platform device
0268  * @fme_br: fme bridge to destroy
0269  */
0270 static void dfl_fme_destroy_bridge(struct dfl_fme_bridge *fme_br)
0271 {
0272     platform_device_unregister(fme_br->br);
0273 }
0274 
0275 /**
0276  * dfl_fme_destroy_bridge - destroy all fpga bridge platform device
0277  * @pdata: fme platform device's pdata
0278  */
0279 static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata)
0280 {
0281     struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata);
0282     struct dfl_fme_bridge *fbridge, *tmp;
0283 
0284     list_for_each_entry_safe(fbridge, tmp, &priv->bridge_list, node) {
0285         list_del(&fbridge->node);
0286         dfl_fme_destroy_bridge(fbridge);
0287     }
0288 }
0289 
0290 /**
0291  * dfl_fme_create_region - create fpga region platform device as child
0292  *
0293  * @pdata: fme platform device's pdata
0294  * @mgr: mgr platform device needed for region
0295  * @br: br platform device needed for region
0296  * @port_id: port id
0297  *
0298  * Return: fme region if successful, and error code otherwise.
0299  */
0300 static struct dfl_fme_region *
0301 dfl_fme_create_region(struct dfl_feature_platform_data *pdata,
0302               struct platform_device *mgr,
0303               struct platform_device *br, int port_id)
0304 {
0305     struct dfl_fme_region_pdata region_pdata;
0306     struct device *dev = &pdata->dev->dev;
0307     struct dfl_fme_region *fme_region;
0308     int ret = -ENOMEM;
0309 
0310     fme_region = devm_kzalloc(dev, sizeof(*fme_region), GFP_KERNEL);
0311     if (!fme_region)
0312         return ERR_PTR(ret);
0313 
0314     region_pdata.mgr = mgr;
0315     region_pdata.br = br;
0316 
0317     /*
0318      * Each FPGA device may have more than one port, so allocate platform
0319      * device using the same port platform device id.
0320      */
0321     fme_region->region = platform_device_alloc(DFL_FPGA_FME_REGION, br->id);
0322     if (!fme_region->region)
0323         return ERR_PTR(ret);
0324 
0325     fme_region->region->dev.parent = dev;
0326 
0327     ret = platform_device_add_data(fme_region->region, &region_pdata,
0328                        sizeof(region_pdata));
0329     if (ret)
0330         goto create_region_err;
0331 
0332     ret = platform_device_add(fme_region->region);
0333     if (ret)
0334         goto create_region_err;
0335 
0336     fme_region->port_id = port_id;
0337 
0338     return fme_region;
0339 
0340 create_region_err:
0341     platform_device_put(fme_region->region);
0342     return ERR_PTR(ret);
0343 }
0344 
0345 /**
0346  * dfl_fme_destroy_region - destroy fme region
0347  * @fme_region: fme region to destroy
0348  */
0349 static void dfl_fme_destroy_region(struct dfl_fme_region *fme_region)
0350 {
0351     platform_device_unregister(fme_region->region);
0352 }
0353 
0354 /**
0355  * dfl_fme_destroy_regions - destroy all fme regions
0356  * @pdata: fme platform device's pdata
0357  */
0358 static void dfl_fme_destroy_regions(struct dfl_feature_platform_data *pdata)
0359 {
0360     struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata);
0361     struct dfl_fme_region *fme_region, *tmp;
0362 
0363     list_for_each_entry_safe(fme_region, tmp, &priv->region_list, node) {
0364         list_del(&fme_region->node);
0365         dfl_fme_destroy_region(fme_region);
0366     }
0367 }
0368 
0369 static int pr_mgmt_init(struct platform_device *pdev,
0370             struct dfl_feature *feature)
0371 {
0372     struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
0373     struct dfl_fme_region *fme_region;
0374     struct dfl_fme_bridge *fme_br;
0375     struct platform_device *mgr;
0376     struct dfl_fme *priv;
0377     void __iomem *fme_hdr;
0378     int ret = -ENODEV, i = 0;
0379     u64 fme_cap, port_offset;
0380 
0381     fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev,
0382                            FME_FEATURE_ID_HEADER);
0383 
0384     mutex_lock(&pdata->lock);
0385     priv = dfl_fpga_pdata_get_private(pdata);
0386 
0387     /* Initialize the region and bridge sub device list */
0388     INIT_LIST_HEAD(&priv->region_list);
0389     INIT_LIST_HEAD(&priv->bridge_list);
0390 
0391     /* Create fpga mgr platform device */
0392     mgr = dfl_fme_create_mgr(pdata, feature);
0393     if (IS_ERR(mgr)) {
0394         dev_err(&pdev->dev, "fail to create fpga mgr pdev\n");
0395         goto unlock;
0396     }
0397 
0398     priv->mgr = mgr;
0399 
0400     /* Read capability register to check number of regions and bridges */
0401     fme_cap = readq(fme_hdr + FME_HDR_CAP);
0402     for (; i < FIELD_GET(FME_CAP_NUM_PORTS, fme_cap); i++) {
0403         port_offset = readq(fme_hdr + FME_HDR_PORT_OFST(i));
0404         if (!(port_offset & FME_PORT_OFST_IMP))
0405             continue;
0406 
0407         /* Create bridge for each port */
0408         fme_br = dfl_fme_create_bridge(pdata, i);
0409         if (IS_ERR(fme_br)) {
0410             ret = PTR_ERR(fme_br);
0411             goto destroy_region;
0412         }
0413 
0414         list_add(&fme_br->node, &priv->bridge_list);
0415 
0416         /* Create region for each port */
0417         fme_region = dfl_fme_create_region(pdata, mgr,
0418                            fme_br->br, i);
0419         if (IS_ERR(fme_region)) {
0420             ret = PTR_ERR(fme_region);
0421             goto destroy_region;
0422         }
0423 
0424         list_add(&fme_region->node, &priv->region_list);
0425     }
0426     mutex_unlock(&pdata->lock);
0427 
0428     return 0;
0429 
0430 destroy_region:
0431     dfl_fme_destroy_regions(pdata);
0432     dfl_fme_destroy_bridges(pdata);
0433     dfl_fme_destroy_mgr(pdata);
0434 unlock:
0435     mutex_unlock(&pdata->lock);
0436     return ret;
0437 }
0438 
0439 static void pr_mgmt_uinit(struct platform_device *pdev,
0440               struct dfl_feature *feature)
0441 {
0442     struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
0443 
0444     mutex_lock(&pdata->lock);
0445 
0446     dfl_fme_destroy_regions(pdata);
0447     dfl_fme_destroy_bridges(pdata);
0448     dfl_fme_destroy_mgr(pdata);
0449     mutex_unlock(&pdata->lock);
0450 }
0451 
0452 static long fme_pr_ioctl(struct platform_device *pdev,
0453              struct dfl_feature *feature,
0454              unsigned int cmd, unsigned long arg)
0455 {
0456     long ret;
0457 
0458     switch (cmd) {
0459     case DFL_FPGA_FME_PORT_PR:
0460         ret = fme_pr(pdev, arg);
0461         break;
0462     default:
0463         ret = -ENODEV;
0464     }
0465 
0466     return ret;
0467 }
0468 
0469 const struct dfl_feature_id fme_pr_mgmt_id_table[] = {
0470     {.id = FME_FEATURE_ID_PR_MGMT,},
0471     {0}
0472 };
0473 
0474 const struct dfl_feature_ops fme_pr_mgmt_ops = {
0475     .init = pr_mgmt_init,
0476     .uinit = pr_mgmt_uinit,
0477     .ioctl = fme_pr_ioctl,
0478 };