168 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for FPGA Accelerated Function Unit (AFU) MMIO Region Management4 *5 * Copyright (C) 2017-2018 Intel Corporation, Inc.6 *7 * Authors:8 * Wu Hao <hao.wu@intel.com>9 * Xiao Guangrong <guangrong.xiao@linux.intel.com>10 */11#include "dfl-afu.h"12 13/**14 * afu_mmio_region_init - init function for afu mmio region support15 * @pdata: afu platform device's pdata.16 */17void afu_mmio_region_init(struct dfl_feature_platform_data *pdata)18{19 struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata);20 21 INIT_LIST_HEAD(&afu->regions);22}23 24#define for_each_region(region, afu) \25 list_for_each_entry((region), &(afu)->regions, node)26 27static struct dfl_afu_mmio_region *get_region_by_index(struct dfl_afu *afu,28 u32 region_index)29{30 struct dfl_afu_mmio_region *region;31 32 for_each_region(region, afu)33 if (region->index == region_index)34 return region;35 36 return NULL;37}38 39/**40 * afu_mmio_region_add - add a mmio region to given feature dev.41 *42 * @pdata: afu platform device's pdata.43 * @region_index: region index.44 * @region_size: region size.45 * @phys: region's physical address of this region.46 * @flags: region flags (access permission).47 *48 * Return: 0 on success, negative error code otherwise.49 */50int afu_mmio_region_add(struct dfl_feature_platform_data *pdata,51 u32 region_index, u64 region_size, u64 phys, u32 flags)52{53 struct dfl_afu_mmio_region *region;54 struct dfl_afu *afu;55 int ret = 0;56 57 region = devm_kzalloc(&pdata->dev->dev, sizeof(*region), GFP_KERNEL);58 if (!region)59 return -ENOMEM;60 61 region->index = region_index;62 region->size = region_size;63 region->phys = phys;64 region->flags = flags;65 66 mutex_lock(&pdata->lock);67 68 afu = dfl_fpga_pdata_get_private(pdata);69 70 /* check if @index already exists */71 if (get_region_by_index(afu, region_index)) {72 mutex_unlock(&pdata->lock);73 ret = -EEXIST;74 goto exit;75 }76 77 region_size = PAGE_ALIGN(region_size);78 region->offset = afu->region_cur_offset;79 list_add(®ion->node, &afu->regions);80 81 afu->region_cur_offset += region_size;82 afu->num_regions++;83 mutex_unlock(&pdata->lock);84 85 return 0;86 87exit:88 devm_kfree(&pdata->dev->dev, region);89 return ret;90}91 92/**93 * afu_mmio_region_destroy - destroy all mmio regions under given feature dev.94 * @pdata: afu platform device's pdata.95 */96void afu_mmio_region_destroy(struct dfl_feature_platform_data *pdata)97{98 struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata);99 struct dfl_afu_mmio_region *tmp, *region;100 101 list_for_each_entry_safe(region, tmp, &afu->regions, node)102 devm_kfree(&pdata->dev->dev, region);103}104 105/**106 * afu_mmio_region_get_by_index - find an afu region by index.107 * @pdata: afu platform device's pdata.108 * @region_index: region index.109 * @pregion: ptr to region for result.110 *111 * Return: 0 on success, negative error code otherwise.112 */113int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata,114 u32 region_index,115 struct dfl_afu_mmio_region *pregion)116{117 struct dfl_afu_mmio_region *region;118 struct dfl_afu *afu;119 int ret = 0;120 121 mutex_lock(&pdata->lock);122 afu = dfl_fpga_pdata_get_private(pdata);123 region = get_region_by_index(afu, region_index);124 if (!region) {125 ret = -EINVAL;126 goto exit;127 }128 *pregion = *region;129exit:130 mutex_unlock(&pdata->lock);131 return ret;132}133 134/**135 * afu_mmio_region_get_by_offset - find an afu mmio region by offset and size136 *137 * @pdata: afu platform device's pdata.138 * @offset: region offset from start of the device fd.139 * @size: region size.140 * @pregion: ptr to region for result.141 *142 * Find the region which fully contains the region described by input143 * parameters (offset and size) from the feature dev's region linked list.144 *145 * Return: 0 on success, negative error code otherwise.146 */147int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata,148 u64 offset, u64 size,149 struct dfl_afu_mmio_region *pregion)150{151 struct dfl_afu_mmio_region *region;152 struct dfl_afu *afu;153 int ret = 0;154 155 mutex_lock(&pdata->lock);156 afu = dfl_fpga_pdata_get_private(pdata);157 for_each_region(region, afu)158 if (region->offset <= offset &&159 region->offset + region->size >= offset + size) {160 *pregion = *region;161 goto exit;162 }163 ret = -EINVAL;164exit:165 mutex_unlock(&pdata->lock);166 return ret;167}168