From: Yi Li <yi1...@linux.intel.com> Since the FPGA image are getting bigger in size, this add an new API fpga_mgr_firmware_stream in FPGA manager, which will stream FPGA image in 4KB trunks.
Signed-off-by: Yi Li <yi1...@linux.intel.com> --- drivers/fpga/fpga-mgr.c | 111 ++++++++++++++++++++++++++++++++++++++++++ include/linux/fpga/fpga-mgr.h | 4 ++ 2 files changed, 115 insertions(+) diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 188ffef..420ee38 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -27,6 +27,8 @@ #include <linux/slab.h> #include <linux/scatterlist.h> #include <linux/highmem.h> +#include <linux/sizes.h> +#include <linux/driver_data.h> static DEFINE_IDA(fpga_mgr_ida); static struct class *fpga_mgr_class; @@ -196,6 +198,115 @@ static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, return fpga_mgr_write_complete(mgr, info); } +struct fpga_mgr_streaming_priv_params { + struct fpga_image_info *info; + struct fpga_manager *mgr; + loff_t offset; + loff_t fw_size; +}; + +static int fpga_mgr_streaming_fw_cb(void *context, const struct firmware *fw, + int err) +{ + int ret = -EINVAL; + struct fpga_mgr_streaming_priv_params *params = + (struct fpga_mgr_streaming_priv_params *)context; + struct fpga_image_info *info = params->info; + struct fpga_manager *mgr = params->mgr; + struct device *dev = &mgr->dev; + + params->fw_size = fw->size; + /* + * init. + */ + if (params->offset == 0) { + ret = fpga_mgr_write_init_buf(mgr, info, fw->data, fw->size); + if (ret) + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + mgr->state = FPGA_MGR_STATE_WRITE; + ret = mgr->mops->write(mgr, fw->data, fw->size); + if (ret) { + dev_err(dev, "Error while writing image data to FPGA\n"); + mgr->state = FPGA_MGR_STATE_WRITE_ERR; + return ret; + } + + if (fw->size < SZ_4K) + ret = fpga_mgr_write_complete(mgr, info); + + return ret; +} + +/** + * fpga_mgr_firmware_stream - streaming firmware and load to fpga + * @mgr: fpga manager + * @info: fpga image specific information + * @image_name: name of image file on the firmware search path + * + * Streaming an FPGA image using the firmware class, then write out to the FPGA. + * Update the state before each step to provide info on what step failed if + * there is a failure. This code assumes the caller got the mgr pointer + * from of_fpga_mgr_get() or fpga_mgr_get() and checked that it is not an error + * code. + * + * Return: 0 on success, negative error code otherwise. + */ +int fpga_mgr_firmware_stream(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *image_name) +{ + int ret; + char *path = NULL; + void *buf; + size_t length = INT_MAX; + struct device *dev = &mgr->dev; + struct fpga_mgr_streaming_priv_params params = { + .info = info, + .mgr = mgr, + .fw_size = 0, + .offset = 0, + }; + + const struct driver_data_req_params req_params = { + DRIVER_DATA_DEFAULT_SYNC(fpga_mgr_streaming_fw_cb, ¶ms), + .reqs = DRIVER_DATA_REQ_NO_CACHE | DRIVER_DATA_REQ_STREAMING, + .alloc_buf_size = SZ_4K, + .alloc_buf = &buf, + .img_offset = ¶ms.offset, + .path = &path, + }; + + buf = kmalloc(SZ_4K, GFP_KERNEL); + if (!buf) { + dev_err(dev, "%s: kmalloc buf failed\n", __func__); + return -ENOMEM; + } + + mgr->state = FPGA_MGR_STATE_FIRMWARE_REQ; + while (length > 0) { + ret = driver_data_request_sync(image_name, &req_params, dev); + if (ret) { + dev_err(dev, "Error reading firmware %d\n", ret); + mgr->state = FPGA_MGR_STATE_FIRMWARE_REQ_ERR; + return ret; + } + + length -= params.fw_size; + params.offset += params.fw_size; + if (params.fw_size < SZ_4K) + break; + } + + kfree(buf); + return ret; +} +EXPORT_SYMBOL_GPL(fpga_mgr_firmware_stream); + /** * fpga_mgr_buf_load - load fpga from image in buffer * @mgr: fpga manager diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h index b4ac24c..083e091 100644 --- a/include/linux/fpga/fpga-mgr.h +++ b/include/linux/fpga/fpga-mgr.h @@ -143,6 +143,10 @@ int fpga_mgr_firmware_load(struct fpga_manager *mgr, struct fpga_image_info *info, const char *image_name); +int fpga_mgr_firmware_stream(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *image_name); + struct fpga_manager *of_fpga_mgr_get(struct device_node *node); struct fpga_manager *fpga_mgr_get(struct device *dev); -- 2.7.4