1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for FPGA Accelerated Function Unit (AFU) MMIO Region Management 4 * 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 support 15 * @pdata: afu platform device's pdata. 16 */ 17 void 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 27 static 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 * @region_index: region index. 43 * @region_size: region size. 44 * @phys: region's physical address of this region. 45 * @flags: region flags (access permission). 46 * 47 * Return: 0 on success, negative error code otherwise. 48 */ 49 int afu_mmio_region_add(struct dfl_feature_platform_data *pdata, 50 u32 region_index, u64 region_size, u64 phys, u32 flags) 51 { 52 struct dfl_afu_mmio_region *region; 53 struct dfl_afu *afu; 54 int ret = 0; 55 56 region = devm_kzalloc(&pdata->dev->dev, sizeof(*region), GFP_KERNEL); 57 if (!region) 58 return -ENOMEM; 59 60 region->index = region_index; 61 region->size = region_size; 62 region->phys = phys; 63 region->flags = flags; 64 65 mutex_lock(&pdata->lock); 66 67 afu = dfl_fpga_pdata_get_private(pdata); 68 69 /* check if @index already exists */ 70 if (get_region_by_index(afu, region_index)) { 71 mutex_unlock(&pdata->lock); 72 ret = -EEXIST; 73 goto exit; 74 } 75 76 region_size = PAGE_ALIGN(region_size); 77 region->offset = afu->region_cur_offset; 78 list_add(®ion->node, &afu->regions); 79 80 afu->region_cur_offset += region_size; 81 afu->num_regions++; 82 mutex_unlock(&pdata->lock); 83 84 return 0; 85 86 exit: 87 devm_kfree(&pdata->dev->dev, region); 88 return ret; 89 } 90 91 /** 92 * afu_mmio_region_destroy - destroy all mmio regions under given feature dev. 93 * @pdata: afu platform device's pdata. 94 */ 95 void afu_mmio_region_destroy(struct dfl_feature_platform_data *pdata) 96 { 97 struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); 98 struct dfl_afu_mmio_region *tmp, *region; 99 100 list_for_each_entry_safe(region, tmp, &afu->regions, node) 101 devm_kfree(&pdata->dev->dev, region); 102 } 103 104 /** 105 * afu_mmio_region_get_by_index - find an afu region by index. 106 * @pdata: afu platform device's pdata. 107 * @region_index: region index. 108 * @pregion: ptr to region for result. 109 * 110 * Return: 0 on success, negative error code otherwise. 111 */ 112 int afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, 113 u32 region_index, 114 struct dfl_afu_mmio_region *pregion) 115 { 116 struct dfl_afu_mmio_region *region; 117 struct dfl_afu *afu; 118 int ret = 0; 119 120 mutex_lock(&pdata->lock); 121 afu = dfl_fpga_pdata_get_private(pdata); 122 region = get_region_by_index(afu, region_index); 123 if (!region) { 124 ret = -EINVAL; 125 goto exit; 126 } 127 *pregion = *region; 128 exit: 129 mutex_unlock(&pdata->lock); 130 return ret; 131 } 132 133 /** 134 * afu_mmio_region_get_by_offset - find an afu mmio region by offset and size 135 * 136 * @pdata: afu platform device's pdata. 137 * @offset: region offset from start of the device fd. 138 * @size: region size. 139 * @pregion: ptr to region for result. 140 * 141 * Find the region which fully contains the region described by input 142 * parameters (offset and size) from the feature dev's region linked list. 143 * 144 * Return: 0 on success, negative error code otherwise. 145 */ 146 int afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, 147 u64 offset, u64 size, 148 struct dfl_afu_mmio_region *pregion) 149 { 150 struct dfl_afu_mmio_region *region; 151 struct dfl_afu *afu; 152 int ret = 0; 153 154 mutex_lock(&pdata->lock); 155 afu = dfl_fpga_pdata_get_private(pdata); 156 for_each_region(region, afu) 157 if (region->offset <= offset && 158 region->offset + region->size >= offset + size) { 159 *pregion = *region; 160 goto exit; 161 } 162 ret = -EINVAL; 163 exit: 164 mutex_unlock(&pdata->lock); 165 return ret; 166 } 167