Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/fpga/dfl-afu-region.c
26378 views
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 <[email protected]>
9
* Xiao Guangrong <[email protected]>
10
*/
11
#include "dfl-afu.h"
12
13
/**
14
* afu_mmio_region_init - init function for afu mmio region support
15
* @fdata: afu feature dev data
16
*/
17
void afu_mmio_region_init(struct dfl_feature_dev_data *fdata)
18
{
19
struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata);
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
* @fdata: afu feature dev data
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
*/
50
int afu_mmio_region_add(struct dfl_feature_dev_data *fdata,
51
u32 region_index, u64 region_size, u64 phys, u32 flags)
52
{
53
struct device *dev = &fdata->dev->dev;
54
struct dfl_afu_mmio_region *region;
55
struct dfl_afu *afu;
56
int ret = 0;
57
58
region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL);
59
if (!region)
60
return -ENOMEM;
61
62
region->index = region_index;
63
region->size = region_size;
64
region->phys = phys;
65
region->flags = flags;
66
67
mutex_lock(&fdata->lock);
68
69
afu = dfl_fpga_fdata_get_private(fdata);
70
71
/* check if @index already exists */
72
if (get_region_by_index(afu, region_index)) {
73
mutex_unlock(&fdata->lock);
74
ret = -EEXIST;
75
goto exit;
76
}
77
78
region_size = PAGE_ALIGN(region_size);
79
region->offset = afu->region_cur_offset;
80
list_add(&region->node, &afu->regions);
81
82
afu->region_cur_offset += region_size;
83
afu->num_regions++;
84
mutex_unlock(&fdata->lock);
85
86
return 0;
87
88
exit:
89
devm_kfree(dev, region);
90
return ret;
91
}
92
93
/**
94
* afu_mmio_region_destroy - destroy all mmio regions under given feature dev.
95
* @fdata: afu feature dev data
96
*/
97
void afu_mmio_region_destroy(struct dfl_feature_dev_data *fdata)
98
{
99
struct dfl_afu *afu = dfl_fpga_fdata_get_private(fdata);
100
struct dfl_afu_mmio_region *tmp, *region;
101
102
list_for_each_entry_safe(region, tmp, &afu->regions, node)
103
devm_kfree(&fdata->dev->dev, region);
104
}
105
106
/**
107
* afu_mmio_region_get_by_index - find an afu region by index.
108
* @fdata: afu feature dev data
109
* @region_index: region index.
110
* @pregion: ptr to region for result.
111
*
112
* Return: 0 on success, negative error code otherwise.
113
*/
114
int afu_mmio_region_get_by_index(struct dfl_feature_dev_data *fdata,
115
u32 region_index,
116
struct dfl_afu_mmio_region *pregion)
117
{
118
struct dfl_afu_mmio_region *region;
119
struct dfl_afu *afu;
120
int ret = 0;
121
122
mutex_lock(&fdata->lock);
123
afu = dfl_fpga_fdata_get_private(fdata);
124
region = get_region_by_index(afu, region_index);
125
if (!region) {
126
ret = -EINVAL;
127
goto exit;
128
}
129
*pregion = *region;
130
exit:
131
mutex_unlock(&fdata->lock);
132
return ret;
133
}
134
135
/**
136
* afu_mmio_region_get_by_offset - find an afu mmio region by offset and size
137
*
138
* @fdata: afu feature dev data
139
* @offset: region offset from start of the device fd.
140
* @size: region size.
141
* @pregion: ptr to region for result.
142
*
143
* Find the region which fully contains the region described by input
144
* parameters (offset and size) from the feature dev's region linked list.
145
*
146
* Return: 0 on success, negative error code otherwise.
147
*/
148
int afu_mmio_region_get_by_offset(struct dfl_feature_dev_data *fdata,
149
u64 offset, u64 size,
150
struct dfl_afu_mmio_region *pregion)
151
{
152
struct dfl_afu_mmio_region *region;
153
struct dfl_afu *afu;
154
int ret = 0;
155
156
mutex_lock(&fdata->lock);
157
afu = dfl_fpga_fdata_get_private(fdata);
158
for_each_region(region, afu)
159
if (region->offset <= offset &&
160
region->offset + region->size >= offset + size) {
161
*pregion = *region;
162
goto exit;
163
}
164
ret = -EINVAL;
165
exit:
166
mutex_unlock(&fdata->lock);
167
return ret;
168
}
169
170