18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for FPGA Accelerated Function Unit (AFU) MMIO Region Management 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 Intel Corporation, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: 88c2ecf20Sopenharmony_ci * Wu Hao <hao.wu@intel.com> 98c2ecf20Sopenharmony_ci * Xiao Guangrong <guangrong.xiao@linux.intel.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include "dfl-afu.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/** 148c2ecf20Sopenharmony_ci * afu_mmio_region_init - init function for afu mmio region support 158c2ecf20Sopenharmony_ci * @pdata: afu platform device's pdata. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_civoid afu_mmio_region_init(struct dfl_feature_platform_data *pdata) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&afu->regions); 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define for_each_region(region, afu) \ 258c2ecf20Sopenharmony_ci list_for_each_entry((region), &(afu)->regions, node) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic struct dfl_afu_mmio_region *get_region_by_index(struct dfl_afu *afu, 288c2ecf20Sopenharmony_ci u32 region_index) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct dfl_afu_mmio_region *region; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci for_each_region(region, afu) 338c2ecf20Sopenharmony_ci if (region->index == region_index) 348c2ecf20Sopenharmony_ci return region; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return NULL; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/** 408c2ecf20Sopenharmony_ci * afu_mmio_region_add - add a mmio region to given feature dev. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * @region_index: region index. 438c2ecf20Sopenharmony_ci * @region_size: region size. 448c2ecf20Sopenharmony_ci * @phys: region's physical address of this region. 458c2ecf20Sopenharmony_ci * @flags: region flags (access permission). 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * Return: 0 on success, negative error code otherwise. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ciint afu_mmio_region_add(struct dfl_feature_platform_data *pdata, 508c2ecf20Sopenharmony_ci u32 region_index, u64 region_size, u64 phys, u32 flags) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct dfl_afu_mmio_region *region; 538c2ecf20Sopenharmony_ci struct dfl_afu *afu; 548c2ecf20Sopenharmony_ci int ret = 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci region = devm_kzalloc(&pdata->dev->dev, sizeof(*region), GFP_KERNEL); 578c2ecf20Sopenharmony_ci if (!region) 588c2ecf20Sopenharmony_ci return -ENOMEM; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci region->index = region_index; 618c2ecf20Sopenharmony_ci region->size = region_size; 628c2ecf20Sopenharmony_ci region->phys = phys; 638c2ecf20Sopenharmony_ci region->flags = flags; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci mutex_lock(&pdata->lock); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci afu = dfl_fpga_pdata_get_private(pdata); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* check if @index already exists */ 708c2ecf20Sopenharmony_ci if (get_region_by_index(afu, region_index)) { 718c2ecf20Sopenharmony_ci mutex_unlock(&pdata->lock); 728c2ecf20Sopenharmony_ci ret = -EEXIST; 738c2ecf20Sopenharmony_ci goto exit; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci region_size = PAGE_ALIGN(region_size); 778c2ecf20Sopenharmony_ci region->offset = afu->region_cur_offset; 788c2ecf20Sopenharmony_ci list_add(®ion->node, &afu->regions); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci afu->region_cur_offset += region_size; 818c2ecf20Sopenharmony_ci afu->num_regions++; 828c2ecf20Sopenharmony_ci mutex_unlock(&pdata->lock); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciexit: 878c2ecf20Sopenharmony_ci devm_kfree(&pdata->dev->dev, region); 888c2ecf20Sopenharmony_ci return ret; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/** 928c2ecf20Sopenharmony_ci * afu_mmio_region_destroy - destroy all mmio regions under given feature dev. 938c2ecf20Sopenharmony_ci * @pdata: afu platform device's pdata. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_civoid afu_mmio_region_destroy(struct dfl_feature_platform_data *pdata) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata); 988c2ecf20Sopenharmony_ci struct dfl_afu_mmio_region *tmp, *region; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci list_for_each_entry_safe(region, tmp, &afu->regions, node) 1018c2ecf20Sopenharmony_ci devm_kfree(&pdata->dev->dev, region); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/** 1058c2ecf20Sopenharmony_ci * afu_mmio_region_get_by_index - find an afu region by index. 1068c2ecf20Sopenharmony_ci * @pdata: afu platform device's pdata. 1078c2ecf20Sopenharmony_ci * @region_index: region index. 1088c2ecf20Sopenharmony_ci * @pregion: ptr to region for result. 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * Return: 0 on success, negative error code otherwise. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ciint afu_mmio_region_get_by_index(struct dfl_feature_platform_data *pdata, 1138c2ecf20Sopenharmony_ci u32 region_index, 1148c2ecf20Sopenharmony_ci struct dfl_afu_mmio_region *pregion) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct dfl_afu_mmio_region *region; 1178c2ecf20Sopenharmony_ci struct dfl_afu *afu; 1188c2ecf20Sopenharmony_ci int ret = 0; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci mutex_lock(&pdata->lock); 1218c2ecf20Sopenharmony_ci afu = dfl_fpga_pdata_get_private(pdata); 1228c2ecf20Sopenharmony_ci region = get_region_by_index(afu, region_index); 1238c2ecf20Sopenharmony_ci if (!region) { 1248c2ecf20Sopenharmony_ci ret = -EINVAL; 1258c2ecf20Sopenharmony_ci goto exit; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci *pregion = *region; 1288c2ecf20Sopenharmony_ciexit: 1298c2ecf20Sopenharmony_ci mutex_unlock(&pdata->lock); 1308c2ecf20Sopenharmony_ci return ret; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/** 1348c2ecf20Sopenharmony_ci * afu_mmio_region_get_by_offset - find an afu mmio region by offset and size 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * @pdata: afu platform device's pdata. 1378c2ecf20Sopenharmony_ci * @offset: region offset from start of the device fd. 1388c2ecf20Sopenharmony_ci * @size: region size. 1398c2ecf20Sopenharmony_ci * @pregion: ptr to region for result. 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * Find the region which fully contains the region described by input 1428c2ecf20Sopenharmony_ci * parameters (offset and size) from the feature dev's region linked list. 1438c2ecf20Sopenharmony_ci * 1448c2ecf20Sopenharmony_ci * Return: 0 on success, negative error code otherwise. 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ciint afu_mmio_region_get_by_offset(struct dfl_feature_platform_data *pdata, 1478c2ecf20Sopenharmony_ci u64 offset, u64 size, 1488c2ecf20Sopenharmony_ci struct dfl_afu_mmio_region *pregion) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct dfl_afu_mmio_region *region; 1518c2ecf20Sopenharmony_ci struct dfl_afu *afu; 1528c2ecf20Sopenharmony_ci int ret = 0; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci mutex_lock(&pdata->lock); 1558c2ecf20Sopenharmony_ci afu = dfl_fpga_pdata_get_private(pdata); 1568c2ecf20Sopenharmony_ci for_each_region(region, afu) 1578c2ecf20Sopenharmony_ci if (region->offset <= offset && 1588c2ecf20Sopenharmony_ci region->offset + region->size >= offset + size) { 1598c2ecf20Sopenharmony_ci *pregion = *region; 1608c2ecf20Sopenharmony_ci goto exit; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci ret = -EINVAL; 1638c2ecf20Sopenharmony_ciexit: 1648c2ecf20Sopenharmony_ci mutex_unlock(&pdata->lock); 1658c2ecf20Sopenharmony_ci return ret; 1668c2ecf20Sopenharmony_ci} 167