Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fpga: fpga-mgr: support bitstream offset in image buffer

At the moment FPGA manager core loads to the device entire image
provided to fpga_mgr_load(). But it is not always whole FPGA image
buffer meant to be written to the device. In particular, .dat formatted
image for Microchip MPF contains meta info in the header that is not
meant to be written to the device. This is issue for those low level
drivers that loads data to the device with write() fpga_manager_ops
callback, since write() can be called in iterator over scatter-gather
table, not only linear image buffer. On the other hand, write_sg()
callback is provided with whole image in scatter-gather form and can
decide itself which part should be sent to the device.

Add header_size and data_size to the fpga_image_info struct, add
skip_header to the fpga_manager_ops struct and adjust fpga_mgr_write()
callers with respect to them.

* info->header_size indicates part at the beginning of image buffer
that contains some meta info. It is optional and can be 0,
initialized with mops->initial_header_size.

* mops->skip_header tells fpga-mgr core whether write should start
from the beginning of image buffer or at the offset of header_size.

* info->data_size is the size of bitstream data that is meant to be
written to the device. It is also optional and can be 0, which
means bitstream data is up to the end of image buffer.

Also add parse_header() callback to fpga_manager_ops, which purpose is
to set info->header_size and info->data_size. At least
initial_header_size bytes of image buffer will be passed into
parse_header() first time. If it is not enough, parse_header() should
set desired size into info->header_size and return -EAGAIN, then it will
be called again with greater part of image buffer on the input.

Suggested-by: Xu Yilun <yilun.xu@intel.com>
Signed-off-by: Ivan Bornyakov <i.bornyakov@metrotek.ru>
Acked-by: Xu Yilun <yilun.xu@intel.com>
Link: https://lore.kernel.org/r/20220623163248.3672-2-i.bornyakov@metrotek.ru
Signed-off-by: Xu Yilun <yilun.xu@intel.com>

authored by

Ivan Bornyakov and committed by
Xu Yilun
3cc624be 2df84a75

+220 -27
+198 -25
drivers/fpga/fpga-mgr.c
··· 74 74 return 0; 75 75 } 76 76 77 + static inline int fpga_mgr_parse_header(struct fpga_manager *mgr, 78 + struct fpga_image_info *info, 79 + const char *buf, size_t count) 80 + { 81 + if (mgr->mops->parse_header) 82 + return mgr->mops->parse_header(mgr, info, buf, count); 83 + return 0; 84 + } 85 + 77 86 static inline int fpga_mgr_write_init(struct fpga_manager *mgr, 78 87 struct fpga_image_info *info, 79 88 const char *buf, size_t count) ··· 145 136 EXPORT_SYMBOL_GPL(fpga_image_info_free); 146 137 147 138 /* 148 - * Call the low level driver's write_init function. This will do the 139 + * Call the low level driver's parse_header function with entire FPGA image 140 + * buffer on the input. This will set info->header_size and info->data_size. 141 + */ 142 + static int fpga_mgr_parse_header_mapped(struct fpga_manager *mgr, 143 + struct fpga_image_info *info, 144 + const char *buf, size_t count) 145 + { 146 + int ret; 147 + 148 + mgr->state = FPGA_MGR_STATE_PARSE_HEADER; 149 + ret = fpga_mgr_parse_header(mgr, info, buf, count); 150 + 151 + if (info->header_size + info->data_size > count) { 152 + dev_err(&mgr->dev, "Bitsream data outruns FPGA image\n"); 153 + ret = -EINVAL; 154 + } 155 + 156 + if (ret) { 157 + dev_err(&mgr->dev, "Error while parsing FPGA image header\n"); 158 + mgr->state = FPGA_MGR_STATE_PARSE_HEADER_ERR; 159 + } 160 + 161 + return ret; 162 + } 163 + 164 + /* 165 + * Call the low level driver's parse_header function with first fragment of 166 + * scattered FPGA image on the input. If header fits first fragment, 167 + * parse_header will set info->header_size and info->data_size. If it is not, 168 + * parse_header will set desired size to info->header_size and -EAGAIN will be 169 + * returned. 170 + */ 171 + static int fpga_mgr_parse_header_sg_first(struct fpga_manager *mgr, 172 + struct fpga_image_info *info, 173 + struct sg_table *sgt) 174 + { 175 + struct sg_mapping_iter miter; 176 + int ret; 177 + 178 + mgr->state = FPGA_MGR_STATE_PARSE_HEADER; 179 + 180 + sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); 181 + if (sg_miter_next(&miter) && 182 + miter.length >= info->header_size) 183 + ret = fpga_mgr_parse_header(mgr, info, miter.addr, miter.length); 184 + else 185 + ret = -EAGAIN; 186 + sg_miter_stop(&miter); 187 + 188 + if (ret && ret != -EAGAIN) { 189 + dev_err(&mgr->dev, "Error while parsing FPGA image header\n"); 190 + mgr->state = FPGA_MGR_STATE_PARSE_HEADER_ERR; 191 + } 192 + 193 + return ret; 194 + } 195 + 196 + /* 197 + * Copy scattered FPGA image fragments to temporary buffer and call the 198 + * low level driver's parse_header function. This should be called after 199 + * fpga_mgr_parse_header_sg_first() returned -EAGAIN. In case of success, 200 + * pointer to the newly allocated image header copy will be returned and 201 + * its size will be set into *ret_size. Returned buffer needs to be freed. 202 + */ 203 + static void *fpga_mgr_parse_header_sg(struct fpga_manager *mgr, 204 + struct fpga_image_info *info, 205 + struct sg_table *sgt, size_t *ret_size) 206 + { 207 + size_t len, new_header_size, header_size = 0; 208 + char *new_buf, *buf = NULL; 209 + int ret; 210 + 211 + do { 212 + new_header_size = info->header_size; 213 + if (new_header_size <= header_size) { 214 + dev_err(&mgr->dev, "Requested invalid header size\n"); 215 + ret = -EFAULT; 216 + break; 217 + } 218 + 219 + new_buf = krealloc(buf, new_header_size, GFP_KERNEL); 220 + if (!new_buf) { 221 + ret = -ENOMEM; 222 + break; 223 + } 224 + 225 + buf = new_buf; 226 + 227 + len = sg_pcopy_to_buffer(sgt->sgl, sgt->nents, 228 + buf + header_size, 229 + new_header_size - header_size, 230 + header_size); 231 + if (len != new_header_size - header_size) { 232 + ret = -EFAULT; 233 + break; 234 + } 235 + 236 + header_size = new_header_size; 237 + ret = fpga_mgr_parse_header(mgr, info, buf, header_size); 238 + } while (ret == -EAGAIN); 239 + 240 + if (ret) { 241 + dev_err(&mgr->dev, "Error while parsing FPGA image header\n"); 242 + mgr->state = FPGA_MGR_STATE_PARSE_HEADER_ERR; 243 + kfree(buf); 244 + buf = ERR_PTR(ret); 245 + } 246 + 247 + *ret_size = header_size; 248 + 249 + return buf; 250 + } 251 + 252 + /* 253 + * Call the low level driver's write_init function. This will do the 149 254 * device-specific things to get the FPGA into the state where it is ready to 150 - * receive an FPGA image. The low level driver only gets to see the first 151 - * initial_header_size bytes in the buffer. 255 + * receive an FPGA image. The low level driver gets to see at least first 256 + * info->header_size bytes in the buffer. If info->header_size is 0, 257 + * write_init will not get any bytes of image buffer. 152 258 */ 153 259 static int fpga_mgr_write_init_buf(struct fpga_manager *mgr, 154 260 struct fpga_image_info *info, 155 261 const char *buf, size_t count) 156 262 { 263 + size_t header_size = info->header_size; 157 264 int ret; 158 265 159 266 mgr->state = FPGA_MGR_STATE_WRITE_INIT; 160 - if (!mgr->mops->initial_header_size) { 267 + 268 + if (header_size > count) 269 + ret = -EINVAL; 270 + else if (!header_size) 161 271 ret = fpga_mgr_write_init(mgr, info, NULL, 0); 162 - } else { 163 - count = min(mgr->mops->initial_header_size, count); 272 + else 164 273 ret = fpga_mgr_write_init(mgr, info, buf, count); 165 - } 166 274 167 275 if (ret) { 168 276 dev_err(&mgr->dev, "Error preparing FPGA for writing\n"); ··· 290 164 return 0; 291 165 } 292 166 293 - static int fpga_mgr_write_init_sg(struct fpga_manager *mgr, 294 - struct fpga_image_info *info, 295 - struct sg_table *sgt) 167 + static int fpga_mgr_prepare_sg(struct fpga_manager *mgr, 168 + struct fpga_image_info *info, 169 + struct sg_table *sgt) 296 170 { 297 171 struct sg_mapping_iter miter; 298 172 size_t len; 299 173 char *buf; 300 174 int ret; 301 175 302 - if (!mgr->mops->initial_header_size) 176 + /* Short path. Low level driver don't care about image header. */ 177 + if (!mgr->mops->initial_header_size && !mgr->mops->parse_header) 303 178 return fpga_mgr_write_init_buf(mgr, info, NULL, 0); 304 179 305 180 /* 306 181 * First try to use miter to map the first fragment to access the 307 182 * header, this is the typical path. 308 183 */ 309 - sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); 310 - if (sg_miter_next(&miter) && 311 - miter.length >= mgr->mops->initial_header_size) { 312 - ret = fpga_mgr_write_init_buf(mgr, info, miter.addr, 313 - miter.length); 184 + ret = fpga_mgr_parse_header_sg_first(mgr, info, sgt); 185 + /* If 0, header fits first fragment, call write_init on it */ 186 + if (!ret) { 187 + sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); 188 + if (sg_miter_next(&miter)) { 189 + ret = fpga_mgr_write_init_buf(mgr, info, miter.addr, 190 + miter.length); 191 + sg_miter_stop(&miter); 192 + return ret; 193 + } 314 194 sg_miter_stop(&miter); 195 + /* 196 + * If -EAGAIN, more sg buffer is needed, 197 + * otherwise an error has occurred. 198 + */ 199 + } else if (ret != -EAGAIN) { 315 200 return ret; 316 201 } 317 - sg_miter_stop(&miter); 318 202 319 - /* Otherwise copy the fragments into temporary memory. */ 320 - buf = kmalloc(mgr->mops->initial_header_size, GFP_KERNEL); 321 - if (!buf) 322 - return -ENOMEM; 203 + /* 204 + * Copy the fragments into temporary memory. 205 + * Copying is done inside fpga_mgr_parse_header_sg(). 206 + */ 207 + buf = fpga_mgr_parse_header_sg(mgr, info, sgt, &len); 208 + if (IS_ERR(buf)) 209 + return PTR_ERR(buf); 323 210 324 - len = sg_copy_to_buffer(sgt->sgl, sgt->nents, buf, 325 - mgr->mops->initial_header_size); 326 211 ret = fpga_mgr_write_init_buf(mgr, info, buf, len); 327 212 328 213 kfree(buf); ··· 364 227 { 365 228 int ret; 366 229 367 - ret = fpga_mgr_write_init_sg(mgr, info, sgt); 230 + ret = fpga_mgr_prepare_sg(mgr, info, sgt); 368 231 if (ret) 369 232 return ret; 370 233 ··· 373 236 if (mgr->mops->write_sg) { 374 237 ret = fpga_mgr_write_sg(mgr, sgt); 375 238 } else { 239 + size_t length, count = 0, data_size = info->data_size; 376 240 struct sg_mapping_iter miter; 377 241 378 242 sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); 243 + 244 + if (mgr->mops->skip_header && 245 + !sg_miter_skip(&miter, info->header_size)) { 246 + ret = -EINVAL; 247 + goto out; 248 + } 249 + 379 250 while (sg_miter_next(&miter)) { 380 - ret = fpga_mgr_write(mgr, miter.addr, miter.length); 251 + if (data_size) 252 + length = min(miter.length, data_size - count); 253 + else 254 + length = miter.length; 255 + 256 + ret = fpga_mgr_write(mgr, miter.addr, length); 381 257 if (ret) 258 + break; 259 + 260 + count += length; 261 + if (data_size && count >= data_size) 382 262 break; 383 263 } 384 264 sg_miter_stop(&miter); 385 265 } 386 266 267 + out: 387 268 if (ret) { 388 269 dev_err(&mgr->dev, "Error while writing image data to FPGA\n"); 389 270 mgr->state = FPGA_MGR_STATE_WRITE_ERR; ··· 417 262 { 418 263 int ret; 419 264 265 + ret = fpga_mgr_parse_header_mapped(mgr, info, buf, count); 266 + if (ret) 267 + return ret; 268 + 420 269 ret = fpga_mgr_write_init_buf(mgr, info, buf, count); 421 270 if (ret) 422 271 return ret; 272 + 273 + if (mgr->mops->skip_header) { 274 + buf += info->header_size; 275 + count -= info->header_size; 276 + } 277 + 278 + if (info->data_size) 279 + count = info->data_size; 423 280 424 281 /* 425 282 * Write the FPGA image to the FPGA. ··· 571 404 */ 572 405 int fpga_mgr_load(struct fpga_manager *mgr, struct fpga_image_info *info) 573 406 { 407 + info->header_size = mgr->mops->initial_header_size; 408 + 574 409 if (info->sgt) 575 410 return fpga_mgr_buf_load_sg(mgr, info, info->sgt); 576 411 if (info->buf && info->count) ··· 592 423 /* requesting FPGA image from firmware */ 593 424 [FPGA_MGR_STATE_FIRMWARE_REQ] = "firmware request", 594 425 [FPGA_MGR_STATE_FIRMWARE_REQ_ERR] = "firmware request error", 426 + 427 + /* Parse FPGA image header */ 428 + [FPGA_MGR_STATE_PARSE_HEADER] = "parse header", 429 + [FPGA_MGR_STATE_PARSE_HEADER_ERR] = "parse header error", 595 430 596 431 /* Preparing FPGA to receive image */ 597 432 [FPGA_MGR_STATE_WRITE_INIT] = "write init",
+22 -2
include/linux/fpga/fpga-mgr.h
··· 22 22 * @FPGA_MGR_STATE_RESET: FPGA in reset state 23 23 * @FPGA_MGR_STATE_FIRMWARE_REQ: firmware request in progress 24 24 * @FPGA_MGR_STATE_FIRMWARE_REQ_ERR: firmware request failed 25 + * @FPGA_MGR_STATE_PARSE_HEADER: parse FPGA image header 26 + * @FPGA_MGR_STATE_PARSE_HEADER_ERR: Error during PARSE_HEADER stage 25 27 * @FPGA_MGR_STATE_WRITE_INIT: preparing FPGA for programming 26 28 * @FPGA_MGR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage 27 29 * @FPGA_MGR_STATE_WRITE: writing image to FPGA ··· 43 41 FPGA_MGR_STATE_FIRMWARE_REQ, 44 42 FPGA_MGR_STATE_FIRMWARE_REQ_ERR, 45 43 46 - /* write sequence: init, write, complete */ 44 + /* write sequence: parse header, init, write, complete */ 45 + FPGA_MGR_STATE_PARSE_HEADER, 46 + FPGA_MGR_STATE_PARSE_HEADER_ERR, 47 47 FPGA_MGR_STATE_WRITE_INIT, 48 48 FPGA_MGR_STATE_WRITE_INIT_ERR, 49 49 FPGA_MGR_STATE_WRITE, ··· 89 85 * @sgt: scatter/gather table containing FPGA image 90 86 * @buf: contiguous buffer containing FPGA image 91 87 * @count: size of buf 88 + * @header_size: size of image header. 89 + * @data_size: size of image data to be sent to the device. If not specified, 90 + * whole image will be used. Header may be skipped in either case. 92 91 * @region_id: id of target region 93 92 * @dev: device that owns this 94 93 * @overlay: Device Tree overlay ··· 105 98 struct sg_table *sgt; 106 99 const char *buf; 107 100 size_t count; 101 + size_t header_size; 102 + size_t data_size; 108 103 int region_id; 109 104 struct device *dev; 110 105 #ifdef CONFIG_OF ··· 146 137 147 138 /** 148 139 * struct fpga_manager_ops - ops for low level fpga manager drivers 149 - * @initial_header_size: Maximum number of bytes that should be passed into write_init 140 + * @initial_header_size: minimum number of bytes that should be passed into 141 + * parse_header and write_init. 142 + * @skip_header: bool flag to tell fpga-mgr core whether it should skip 143 + * info->header_size part at the beginning of the image when invoking 144 + * write callback. 150 145 * @state: returns an enum value of the FPGA's state 151 146 * @status: returns status of the FPGA, including reconfiguration error code 147 + * @parse_header: parse FPGA image header to set info->header_size and 148 + * info->data_size. In case the input buffer is not large enough, set 149 + * required size to info->header_size and return -EAGAIN. 152 150 * @write_init: prepare the FPGA to receive configuration data 153 151 * @write: write count bytes of configuration data to the FPGA 154 152 * @write_sg: write the scatter list of configuration data to the FPGA ··· 169 153 */ 170 154 struct fpga_manager_ops { 171 155 size_t initial_header_size; 156 + bool skip_header; 172 157 enum fpga_mgr_states (*state)(struct fpga_manager *mgr); 173 158 u64 (*status)(struct fpga_manager *mgr); 159 + int (*parse_header)(struct fpga_manager *mgr, 160 + struct fpga_image_info *info, 161 + const char *buf, size_t count); 174 162 int (*write_init)(struct fpga_manager *mgr, 175 163 struct fpga_image_info *info, 176 164 const char *buf, size_t count);