Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for FPGA Accelerated Function Unit (AFU) MMIO Region Management
0004  *
0005  * Copyright (C) 2017-2018 Intel Corporation, Inc.
0006  *
0007  * Authors:
0008  *   Wu Hao <hao.wu@intel.com>
0009  *   Xiao Guangrong <guangrong.xiao@linux.intel.com>
0010  */
0011 #include "dfl-afu.h"
0012 
0013 /**
0014  * afu_mmio_region_init - init function for afu mmio region support
0015  * @pdata: afu platform device's pdata.
0016  */
0017 void afu_mmio_region_init(struct dfl_feature_platform_data *pdata)
0018 {
0019     struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata);
0020 
0021     INIT_LIST_HEAD(&afu->regions);
0022 }
0023 
0024 #define for_each_region(region, afu)    \
0025     list_for_each_entry((region), &(afu)->regions, node)
0026 
0027 static struct dfl_afu_mmio_region *get_region_by_index(struct dfl_afu *afu,
0028                                u32 region_index)
0029 {
0030     struct dfl_afu_mmio_region *region;
0031 
0032     for_each_region(region, afu)
0033         if (region->index == region_index)
0034             return region;
0035 
0036     return NULL;
0037 }
0038 
0039 /**
0040  * afu_mmio_region_add - add a mmio region to given feature dev.
0041  *
0042  * @region_index: region index.
0043  * @region_size: region size.
0044  * @phys: region's physical address of this region.
0045  * @flags: region flags (access permission).
0046  *
0047  * Return: 0 on success, negative error code otherwise.
0048  */
0049 int afu_mmio_region_add(struct dfl_feature_platform_data *pdata,
0050             u32 region_index, u64 region_size, u64 phys, u32 flags)
0051 {
0052     struct dfl_afu_mmio_region *region;
0053     struct dfl_afu *afu;
0054     int ret = 0;
0055 
0056     region = devm_kzalloc(&pdata->dev->dev, sizeof(*region), GFP_KERNEL);
0057     if (!region)
0058         return -ENOMEM;
0059 
0060     region->index = region_index;
0061     region->size = region_size;
0062     region->phys = phys;
0063     region->flags = flags;
0064 
0065     mutex_lock(&pdata->lock);
0066 
0067     afu = dfl_fpga_pdata_get_private(pdata);
0068 
0069     /* check if @index already exists */
0070     if (get_region_by_index(afu, region_index)) {
0071         mutex_unlock(&pdata->lock);
0072         ret = -EEXIST;
0073         goto exit;
0074     }
0075 
0076     region_size = PAGE_ALIGN(region_size);
0077     region->offset = afu->region_cur_offset;
0078     list_add(&region->node, &afu->regions);
0079 
0080     afu->region_cur_offset += region_size;
0081     afu->num_regions++;
0082     mutex_unlock(&pdata->lock);
0083 
0084     return 0;
0085 
0086 exit:
0087     devm_kfree(&pdata->dev->dev, region);
0088     return ret;
0089 }
0090 
0091 /**
0092  * afu_mmio_region_destroy - destroy all mmio regions under given feature dev.
0093  * @pdata: afu platform device's pdata.
0094  */
0095 void afu_mmio_region_destroy(struct dfl_feature_platform_data *pdata)
0096 {
0097     struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata);
0098     struct dfl_afu_mmio_region *tmp, *region;
0099 
0100     list_for_each_entry_safe(region, tmp, &afu->regions, node)
0101         devm_kfree(&pdata->dev->dev, region);
0102 }
0103 
0104 /**
0105  * afu_mmio_region_get_by_index - find an afu region by index.
0106  * @pdata: afu platform device's pdata.
0107  * @region_index: region index.
0108  * @pregion: ptr to region for result.
0109  *
0110  * Return: 0 on success, negative error code otherwise.
0111  */
0112 int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata,
0113                  u32 region_index,
0114                  struct dfl_afu_mmio_region *pregion)
0115 {
0116     struct dfl_afu_mmio_region *region;
0117     struct dfl_afu *afu;
0118     int ret = 0;
0119 
0120     mutex_lock(&pdata->lock);
0121     afu = dfl_fpga_pdata_get_private(pdata);
0122     region = get_region_by_index(afu, region_index);
0123     if (!region) {
0124         ret = -EINVAL;
0125         goto exit;
0126     }
0127     *pregion = *region;
0128 exit:
0129     mutex_unlock(&pdata->lock);
0130     return ret;
0131 }
0132 
0133 /**
0134  * afu_mmio_region_get_by_offset - find an afu mmio region by offset and size
0135  *
0136  * @pdata: afu platform device's pdata.
0137  * @offset: region offset from start of the device fd.
0138  * @size: region size.
0139  * @pregion: ptr to region for result.
0140  *
0141  * Find the region which fully contains the region described by input
0142  * parameters (offset and size) from the feature dev's region linked list.
0143  *
0144  * Return: 0 on success, negative error code otherwise.
0145  */
0146 int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata,
0147                   u64 offset, u64 size,
0148                   struct dfl_afu_mmio_region *pregion)
0149 {
0150     struct dfl_afu_mmio_region *region;
0151     struct dfl_afu *afu;
0152     int ret = 0;
0153 
0154     mutex_lock(&pdata->lock);
0155     afu = dfl_fpga_pdata_get_private(pdata);
0156     for_each_region(region, afu)
0157         if (region->offset <= offset &&
0158             region->offset + region->size >= offset + size) {
0159             *pregion = *region;
0160             goto exit;
0161         }
0162     ret = -EINVAL;
0163 exit:
0164     mutex_unlock(&pdata->lock);
0165     return ret;
0166 }