diff options
Diffstat (limited to 'drivers/fpga/fpga-mgr.c')
-rw-r--r-- | drivers/fpga/fpga-mgr.c | 236 |
1 files changed, 206 insertions, 30 deletions
diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index f0a69d3e60a5..86d2cb203533 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c | |||
@@ -25,16 +25,106 @@ | |||
25 | #include <linux/of.h> | 25 | #include <linux/of.h> |
26 | #include <linux/mutex.h> | 26 | #include <linux/mutex.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/scatterlist.h> | ||
29 | #include <linux/highmem.h> | ||
28 | 30 | ||
29 | static DEFINE_IDA(fpga_mgr_ida); | 31 | static DEFINE_IDA(fpga_mgr_ida); |
30 | static struct class *fpga_mgr_class; | 32 | static struct class *fpga_mgr_class; |
31 | 33 | ||
34 | /* | ||
35 | * Call the low level driver's write_init function. This will do the | ||
36 | * device-specific things to get the FPGA into the state where it is ready to | ||
37 | * receive an FPGA image. The low level driver only gets to see the first | ||
38 | * initial_header_size bytes in the buffer. | ||
39 | */ | ||
40 | static int fpga_mgr_write_init_buf(struct fpga_manager *mgr, | ||
41 | struct fpga_image_info *info, | ||
42 | const char *buf, size_t count) | ||
43 | { | ||
44 | int ret; | ||
45 | |||
46 | mgr->state = FPGA_MGR_STATE_WRITE_INIT; | ||
47 | if (!mgr->mops->initial_header_size) | ||
48 | ret = mgr->mops->write_init(mgr, info, NULL, 0); | ||
49 | else | ||
50 | ret = mgr->mops->write_init( | ||
51 | mgr, info, buf, min(mgr->mops->initial_header_size, count)); | ||
52 | |||
53 | if (ret) { | ||
54 | dev_err(&mgr->dev, "Error preparing FPGA for writing\n"); | ||
55 | mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR; | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int fpga_mgr_write_init_sg(struct fpga_manager *mgr, | ||
63 | struct fpga_image_info *info, | ||
64 | struct sg_table *sgt) | ||
65 | { | ||
66 | struct sg_mapping_iter miter; | ||
67 | size_t len; | ||
68 | char *buf; | ||
69 | int ret; | ||
70 | |||
71 | if (!mgr->mops->initial_header_size) | ||
72 | return fpga_mgr_write_init_buf(mgr, info, NULL, 0); | ||
73 | |||
74 | /* | ||
75 | * First try to use miter to map the first fragment to access the | ||
76 | * header, this is the typical path. | ||
77 | */ | ||
78 | sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); | ||
79 | if (sg_miter_next(&miter) && | ||
80 | miter.length >= mgr->mops->initial_header_size) { | ||
81 | ret = fpga_mgr_write_init_buf(mgr, info, miter.addr, | ||
82 | miter.length); | ||
83 | sg_miter_stop(&miter); | ||
84 | return ret; | ||
85 | } | ||
86 | sg_miter_stop(&miter); | ||
87 | |||
88 | /* Otherwise copy the fragments into temporary memory. */ | ||
89 | buf = kmalloc(mgr->mops->initial_header_size, GFP_KERNEL); | ||
90 | if (!buf) | ||
91 | return -ENOMEM; | ||
92 | |||
93 | len = sg_copy_to_buffer(sgt->sgl, sgt->nents, buf, | ||
94 | mgr->mops->initial_header_size); | ||
95 | ret = fpga_mgr_write_init_buf(mgr, info, buf, len); | ||
96 | |||
97 | kfree(buf); | ||
98 | |||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * After all the FPGA image has been written, do the device specific steps to | ||
104 | * finish and set the FPGA into operating mode. | ||
105 | */ | ||
106 | static int fpga_mgr_write_complete(struct fpga_manager *mgr, | ||
107 | struct fpga_image_info *info) | ||
108 | { | ||
109 | int ret; | ||
110 | |||
111 | mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE; | ||
112 | ret = mgr->mops->write_complete(mgr, info); | ||
113 | if (ret) { | ||
114 | dev_err(&mgr->dev, "Error after writing image data to FPGA\n"); | ||
115 | mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR; | ||
116 | return ret; | ||
117 | } | ||
118 | mgr->state = FPGA_MGR_STATE_OPERATING; | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
32 | /** | 123 | /** |
33 | * fpga_mgr_buf_load - load fpga from image in buffer | 124 | * fpga_mgr_buf_load_sg - load fpga from image in buffer from a scatter list |
34 | * @mgr: fpga manager | 125 | * @mgr: fpga manager |
35 | * @info: fpga image specific information | 126 | * @info: fpga image specific information |
36 | * @buf: buffer contain fpga image | 127 | * @sgt: scatterlist table |
37 | * @count: byte count of buf | ||
38 | * | 128 | * |
39 | * Step the low level fpga manager through the device-specific steps of getting | 129 | * Step the low level fpga manager through the device-specific steps of getting |
40 | * an FPGA ready to be configured, writing the image to it, then doing whatever | 130 | * an FPGA ready to be configured, writing the image to it, then doing whatever |
@@ -42,54 +132,139 @@ static struct class *fpga_mgr_class; | |||
42 | * mgr pointer from of_fpga_mgr_get() or fpga_mgr_get() and checked that it is | 132 | * mgr pointer from of_fpga_mgr_get() or fpga_mgr_get() and checked that it is |
43 | * not an error code. | 133 | * not an error code. |
44 | * | 134 | * |
135 | * This is the preferred entry point for FPGA programming, it does not require | ||
136 | * any contiguous kernel memory. | ||
137 | * | ||
45 | * Return: 0 on success, negative error code otherwise. | 138 | * Return: 0 on success, negative error code otherwise. |
46 | */ | 139 | */ |
47 | int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, | 140 | int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, struct fpga_image_info *info, |
48 | const char *buf, size_t count) | 141 | struct sg_table *sgt) |
49 | { | 142 | { |
50 | struct device *dev = &mgr->dev; | ||
51 | int ret; | 143 | int ret; |
52 | 144 | ||
53 | /* | 145 | ret = fpga_mgr_write_init_sg(mgr, info, sgt); |
54 | * Call the low level driver's write_init function. This will do the | 146 | if (ret) |
55 | * device-specific things to get the FPGA into the state where it is | 147 | return ret; |
56 | * ready to receive an FPGA image. The low level driver only gets to | 148 | |
57 | * see the first initial_header_size bytes in the buffer. | 149 | /* Write the FPGA image to the FPGA. */ |
58 | */ | 150 | mgr->state = FPGA_MGR_STATE_WRITE; |
59 | mgr->state = FPGA_MGR_STATE_WRITE_INIT; | 151 | if (mgr->mops->write_sg) { |
60 | ret = mgr->mops->write_init(mgr, info, buf, | 152 | ret = mgr->mops->write_sg(mgr, sgt); |
61 | min(mgr->mops->initial_header_size, count)); | 153 | } else { |
154 | struct sg_mapping_iter miter; | ||
155 | |||
156 | sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); | ||
157 | while (sg_miter_next(&miter)) { | ||
158 | ret = mgr->mops->write(mgr, miter.addr, miter.length); | ||
159 | if (ret) | ||
160 | break; | ||
161 | } | ||
162 | sg_miter_stop(&miter); | ||
163 | } | ||
164 | |||
62 | if (ret) { | 165 | if (ret) { |
63 | dev_err(dev, "Error preparing FPGA for writing\n"); | 166 | dev_err(&mgr->dev, "Error while writing image data to FPGA\n"); |
64 | mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR; | 167 | mgr->state = FPGA_MGR_STATE_WRITE_ERR; |
65 | return ret; | 168 | return ret; |
66 | } | 169 | } |
67 | 170 | ||
171 | return fpga_mgr_write_complete(mgr, info); | ||
172 | } | ||
173 | EXPORT_SYMBOL_GPL(fpga_mgr_buf_load_sg); | ||
174 | |||
175 | static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, | ||
176 | struct fpga_image_info *info, | ||
177 | const char *buf, size_t count) | ||
178 | { | ||
179 | int ret; | ||
180 | |||
181 | ret = fpga_mgr_write_init_buf(mgr, info, buf, count); | ||
182 | if (ret) | ||
183 | return ret; | ||
184 | |||
68 | /* | 185 | /* |
69 | * Write the FPGA image to the FPGA. | 186 | * Write the FPGA image to the FPGA. |
70 | */ | 187 | */ |
71 | mgr->state = FPGA_MGR_STATE_WRITE; | 188 | mgr->state = FPGA_MGR_STATE_WRITE; |
72 | ret = mgr->mops->write(mgr, buf, count); | 189 | ret = mgr->mops->write(mgr, buf, count); |
73 | if (ret) { | 190 | if (ret) { |
74 | dev_err(dev, "Error while writing image data to FPGA\n"); | 191 | dev_err(&mgr->dev, "Error while writing image data to FPGA\n"); |
75 | mgr->state = FPGA_MGR_STATE_WRITE_ERR; | 192 | mgr->state = FPGA_MGR_STATE_WRITE_ERR; |
76 | return ret; | 193 | return ret; |
77 | } | 194 | } |
78 | 195 | ||
196 | return fpga_mgr_write_complete(mgr, info); | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * fpga_mgr_buf_load - load fpga from image in buffer | ||
201 | * @mgr: fpga manager | ||
202 | * @flags: flags setting fpga confuration modes | ||
203 | * @buf: buffer contain fpga image | ||
204 | * @count: byte count of buf | ||
205 | * | ||
206 | * Step the low level fpga manager through the device-specific steps of getting | ||
207 | * an FPGA ready to be configured, writing the image to it, then doing whatever | ||
208 | * post-configuration steps necessary. This code assumes the caller got the | ||
209 | * mgr pointer from of_fpga_mgr_get() and checked that it is not an error code. | ||
210 | * | ||
211 | * Return: 0 on success, negative error code otherwise. | ||
212 | */ | ||
213 | int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, | ||
214 | const char *buf, size_t count) | ||
215 | { | ||
216 | struct page **pages; | ||
217 | struct sg_table sgt; | ||
218 | const void *p; | ||
219 | int nr_pages; | ||
220 | int index; | ||
221 | int rc; | ||
222 | |||
79 | /* | 223 | /* |
80 | * After all the FPGA image has been written, do the device specific | 224 | * This is just a fast path if the caller has already created a |
81 | * steps to finish and set the FPGA into operating mode. | 225 | * contiguous kernel buffer and the driver doesn't require SG, non-SG |
226 | * drivers will still work on the slow path. | ||
82 | */ | 227 | */ |
83 | mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE; | 228 | if (mgr->mops->write) |
84 | ret = mgr->mops->write_complete(mgr, info); | 229 | return fpga_mgr_buf_load_mapped(mgr, info, buf, count); |
85 | if (ret) { | 230 | |
86 | dev_err(dev, "Error after writing image data to FPGA\n"); | 231 | /* |
87 | mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR; | 232 | * Convert the linear kernel pointer into a sg_table of pages for use |
88 | return ret; | 233 | * by the driver. |
234 | */ | ||
235 | nr_pages = DIV_ROUND_UP((unsigned long)buf + count, PAGE_SIZE) - | ||
236 | (unsigned long)buf / PAGE_SIZE; | ||
237 | pages = kmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL); | ||
238 | if (!pages) | ||
239 | return -ENOMEM; | ||
240 | |||
241 | p = buf - offset_in_page(buf); | ||
242 | for (index = 0; index < nr_pages; index++) { | ||
243 | if (is_vmalloc_addr(p)) | ||
244 | pages[index] = vmalloc_to_page(p); | ||
245 | else | ||
246 | pages[index] = kmap_to_page((void *)p); | ||
247 | if (!pages[index]) { | ||
248 | kfree(pages); | ||
249 | return -EFAULT; | ||
250 | } | ||
251 | p += PAGE_SIZE; | ||
89 | } | 252 | } |
90 | mgr->state = FPGA_MGR_STATE_OPERATING; | ||
91 | 253 | ||
92 | return 0; | 254 | /* |
255 | * The temporary pages list is used to code share the merging algorithm | ||
256 | * in sg_alloc_table_from_pages | ||
257 | */ | ||
258 | rc = sg_alloc_table_from_pages(&sgt, pages, index, offset_in_page(buf), | ||
259 | count, GFP_KERNEL); | ||
260 | kfree(pages); | ||
261 | if (rc) | ||
262 | return rc; | ||
263 | |||
264 | rc = fpga_mgr_buf_load_sg(mgr, info, &sgt); | ||
265 | sg_free_table(&sgt); | ||
266 | |||
267 | return rc; | ||
93 | } | 268 | } |
94 | EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); | 269 | EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); |
95 | 270 | ||
@@ -291,8 +466,9 @@ int fpga_mgr_register(struct device *dev, const char *name, | |||
291 | struct fpga_manager *mgr; | 466 | struct fpga_manager *mgr; |
292 | int id, ret; | 467 | int id, ret; |
293 | 468 | ||
294 | if (!mops || !mops->write_init || !mops->write || | 469 | if (!mops || !mops->write_complete || !mops->state || |
295 | !mops->write_complete || !mops->state) { | 470 | !mops->write_init || (!mops->write && !mops->write_sg) || |
471 | (mops->write && mops->write_sg)) { | ||
296 | dev_err(dev, "Attempt to register without fpga_manager_ops\n"); | 472 | dev_err(dev, "Attempt to register without fpga_manager_ops\n"); |
297 | return -EINVAL; | 473 | return -EINVAL; |
298 | } | 474 | } |