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