+/*
+ * Call the low level driver's write_init function. This will do the
+ * device-specific things to get the FPGA into the state where it is ready to
+ * receive an FPGA image. The low level driver only gets to see the first
+ * initial_header_size bytes in the buffer.
+ */
+static int fpga_mgr_write_init_buf(struct fpga_manager *mgr,
+ struct fpga_image_info *info,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ mgr->state = FPGA_MGR_STATE_WRITE_INIT;
+ if (!mgr->mops->initial_header_size)
+ ret = mgr->mops->write_init(mgr, info, NULL, 0);
+ else
+ ret = mgr->mops->write_init(
+ mgr, info, buf, min(mgr->mops->initial_header_size, count));
+
+ if (ret) {
+ dev_err(&mgr->dev, "Error preparing FPGA for writing\n");
+ mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fpga_mgr_write_init_sg(struct fpga_manager *mgr,
+ struct fpga_image_info *info,
+ struct sg_table *sgt)
+{
+ struct sg_mapping_iter miter;
+ size_t len;
+ char *buf;
+ int ret;
+
+ if (!mgr->mops->initial_header_size)
+ return fpga_mgr_write_init_buf(mgr, info, NULL, 0);
+
+ /*
+ * First try to use miter to map the first fragment to access the
+ * header, this is the typical path.
+ */
+ sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG);
+ if (sg_miter_next(&miter) &&
+ miter.length >= mgr->mops->initial_header_size) {
+ ret = fpga_mgr_write_init_buf(mgr, info, miter.addr,
+ miter.length);
+ sg_miter_stop(&miter);
+ return ret;
+ }
+ sg_miter_stop(&miter);
+
+ /* Otherwise copy the fragments into temporary memory. */
+ buf = kmalloc(mgr->mops->initial_header_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len = sg_copy_to_buffer(sgt->sgl, sgt->nents, buf,
+ mgr->mops->initial_header_size);
+ ret = fpga_mgr_write_init_buf(mgr, info, buf, len);
+
+ kfree(buf);
+
+ return ret;
+}
+
+/*
+ * After all the FPGA image has been written, do the device specific steps to
+ * finish and set the FPGA into operating mode.
+ */
+static int fpga_mgr_write_complete(struct fpga_manager *mgr,
+ struct fpga_image_info *info)
+{
+ int ret;
+
+ mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE;
+ ret = mgr->mops->write_complete(mgr, info);
+ if (ret) {
+ dev_err(&mgr->dev, "Error after writing image data to FPGA\n");
+ mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR;
+ return ret;
+ }
+ mgr->state = FPGA_MGR_STATE_OPERATING;
+
+ return 0;
+}
+