From 9dce0287a60d72656a787b075f1b9162ff3cb142 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Tue, 1 Nov 2016 14:14:23 -0500 Subject: fpga: add method to get fpga manager from device The intent is to provide a non-DT method of getting ahold of a FPGA manager to do some FPGA programming. This patch refactors of_fpga_mgr_get() to reuse most of it while adding a new method fpga_mgr_get() for getting a pointer to a fpga manager struct, given the device. Signed-off-by: Alan Tull Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/fpga-mgr.c | 76 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 22 deletions(-) (limited to 'drivers/fpga/fpga-mgr.c') diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 953dc9195937..b690e65d55fe 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -39,7 +39,8 @@ static struct class *fpga_mgr_class; * Step the low level fpga manager through the device-specific steps of getting * an FPGA ready to be configured, writing the image to it, then doing whatever * post-configuration steps necessary. This code assumes the caller got the - * mgr pointer from of_fpga_mgr_get() and checked that it is not an error code. + * 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. */ @@ -99,7 +100,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); * Request 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() and checked that it is not an error code. + * 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. */ @@ -181,30 +183,11 @@ static struct attribute *fpga_mgr_attrs[] = { }; ATTRIBUTE_GROUPS(fpga_mgr); -static int fpga_mgr_of_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - -/** - * of_fpga_mgr_get - get an exclusive reference to a fpga mgr - * @node: device node - * - * Given a device node, get an exclusive reference to a fpga mgr. - * - * Return: fpga manager struct or IS_ERR() condition containing error code. - */ -struct fpga_manager *of_fpga_mgr_get(struct device_node *node) +struct fpga_manager *__fpga_mgr_get(struct device *dev) { struct fpga_manager *mgr; - struct device *dev; int ret = -ENODEV; - dev = class_find_device(fpga_mgr_class, NULL, node, - fpga_mgr_of_node_match); - if (!dev) - return ERR_PTR(-ENODEV); - mgr = to_fpga_manager(dev); if (!mgr) goto err_dev; @@ -226,6 +209,55 @@ err_dev: put_device(dev); return ERR_PTR(ret); } + +static int fpga_mgr_dev_match(struct device *dev, const void *data) +{ + return dev->parent == data; +} + +/** + * fpga_mgr_get - get an exclusive reference to a fpga mgr + * @dev: parent device that fpga mgr was registered with + * + * Given a device, get an exclusive reference to a fpga mgr. + * + * Return: fpga manager struct or IS_ERR() condition containing error code. + */ +struct fpga_manager *fpga_mgr_get(struct device *dev) +{ + struct device *mgr_dev = class_find_device(fpga_mgr_class, NULL, dev, + fpga_mgr_dev_match); + if (!mgr_dev) + return ERR_PTR(-ENODEV); + + return __fpga_mgr_get(mgr_dev); +} +EXPORT_SYMBOL_GPL(fpga_mgr_get); + +static int fpga_mgr_of_node_match(struct device *dev, const void *data) +{ + return dev->of_node == data; +} + +/** + * of_fpga_mgr_get - get an exclusive reference to a fpga mgr + * @node: device node + * + * Given a device node, get an exclusive reference to a fpga mgr. + * + * Return: fpga manager struct or IS_ERR() condition containing error code. + */ +struct fpga_manager *of_fpga_mgr_get(struct device_node *node) +{ + struct device *dev; + + dev = class_find_device(fpga_mgr_class, NULL, node, + fpga_mgr_of_node_match); + if (!dev) + return ERR_PTR(-ENODEV); + + return __fpga_mgr_get(dev); +} EXPORT_SYMBOL_GPL(of_fpga_mgr_get); /** -- cgit v1.2.3 From 1df2865f8dd9d56cb76aa7aa1298921e7bece2af Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Tue, 1 Nov 2016 14:14:26 -0500 Subject: fpga-mgr: add fpga image information struct This patch adds a minor change in the FPGA Manager API to hold information that is specific to an FPGA image file. This change is expected to bring little, if any, pain. The socfpga and zynq drivers are fixed up in this patch. An FPGA image file will have particulars that affect how the image is programmed to the FPGA. One example is that current 'flags' currently has one bit which shows whether the FPGA image was built for full reconfiguration or partial reconfiguration. Another example is timeout values for enabling or disabling the bridges in the FPGA. As the complexity of the FPGA design increases, the bridges in the FPGA may take longer times to enable or disable. This patch adds a new 'struct fpga_image_info', moves the current 'u32 flags' to it. Two other image-specific u32's are added for the bridge enable/disable timeouts. The FPGA Manager API functions are changed, replacing the 'u32 flag' parameter with a pointer to struct fpga_image_info. Subsequent patches fix the existing low level FPGA manager drivers. Signed-off-by: Alan Tull Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/fpga-mgr.c | 17 +++++++++-------- drivers/fpga/socfpga.c | 7 ++++--- drivers/fpga/zynq-fpga.c | 10 ++++++---- include/linux/fpga/fpga-mgr.h | 23 +++++++++++++++++++---- 4 files changed, 38 insertions(+), 19 deletions(-) (limited to 'drivers/fpga/fpga-mgr.c') diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index b690e65d55fe..79ce2eea44db 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -32,7 +32,7 @@ static struct class *fpga_mgr_class; /** * fpga_mgr_buf_load - load fpga from image in buffer * @mgr: fpga manager - * @flags: flags setting fpga confuration modes + * @info: fpga image specific information * @buf: buffer contain fpga image * @count: byte count of buf * @@ -44,8 +44,8 @@ static struct class *fpga_mgr_class; * * Return: 0 on success, negative error code otherwise. */ -int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, const char *buf, - size_t count) +int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, + const char *buf, size_t count) { struct device *dev = &mgr->dev; int ret; @@ -56,7 +56,7 @@ int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, const char *buf, * ready to receive an FPGA image. */ mgr->state = FPGA_MGR_STATE_WRITE_INIT; - ret = mgr->mops->write_init(mgr, flags, buf, count); + ret = mgr->mops->write_init(mgr, info, buf, count); if (ret) { dev_err(dev, "Error preparing FPGA for writing\n"); mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR; @@ -79,7 +79,7 @@ int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, const char *buf, * steps to finish and set the FPGA into operating mode. */ mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE; - ret = mgr->mops->write_complete(mgr, flags); + ret = mgr->mops->write_complete(mgr, info); if (ret) { dev_err(dev, "Error after writing image data to FPGA\n"); mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR; @@ -94,7 +94,7 @@ EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); /** * fpga_mgr_firmware_load - request firmware and load to fpga * @mgr: fpga manager - * @flags: flags setting fpga confuration modes + * @info: fpga image specific information * @image_name: name of image file on the firmware search path * * Request an FPGA image using the firmware class, then write out to the FPGA. @@ -105,7 +105,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); * * Return: 0 on success, negative error code otherwise. */ -int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags, +int fpga_mgr_firmware_load(struct fpga_manager *mgr, + struct fpga_image_info *info, const char *image_name) { struct device *dev = &mgr->dev; @@ -123,7 +124,7 @@ int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags, return ret; } - ret = fpga_mgr_buf_load(mgr, flags, fw->data, fw->size); + ret = fpga_mgr_buf_load(mgr, info, fw->data, fw->size); release_firmware(fw); diff --git a/drivers/fpga/socfpga.c b/drivers/fpga/socfpga.c index 27d2ff28132c..b6672e66cda6 100644 --- a/drivers/fpga/socfpga.c +++ b/drivers/fpga/socfpga.c @@ -407,13 +407,14 @@ static int socfpga_fpga_reset(struct fpga_manager *mgr) /* * Prepare the FPGA to receive the configuration data. */ -static int socfpga_fpga_ops_configure_init(struct fpga_manager *mgr, u32 flags, +static int socfpga_fpga_ops_configure_init(struct fpga_manager *mgr, + struct fpga_image_info *info, const char *buf, size_t count) { struct socfpga_fpga_priv *priv = mgr->priv; int ret; - if (flags & FPGA_MGR_PARTIAL_RECONFIG) { + if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); return -EINVAL; } @@ -478,7 +479,7 @@ static int socfpga_fpga_ops_configure_write(struct fpga_manager *mgr, } static int socfpga_fpga_ops_configure_complete(struct fpga_manager *mgr, - u32 flags) + struct fpga_image_info *info) { struct socfpga_fpga_priv *priv = mgr->priv; u32 status; diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index c2fb4120bd62..249682e92502 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c @@ -175,7 +175,8 @@ static irqreturn_t zynq_fpga_isr(int irq, void *data) return IRQ_HANDLED; } -static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags, +static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, const char *buf, size_t count) { struct zynq_fpga_priv *priv; @@ -189,7 +190,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags, return err; /* don't globally reset PL if we're doing partial reconfig */ - if (!(flags & FPGA_MGR_PARTIAL_RECONFIG)) { + if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { /* assert AXI interface resets */ regmap_write(priv->slcr, SLCR_FPGA_RST_CTRL_OFFSET, FPGA_RST_ALL_MASK); @@ -343,7 +344,8 @@ out_free: return err; } -static int zynq_fpga_ops_write_complete(struct fpga_manager *mgr, u32 flags) +static int zynq_fpga_ops_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) { struct zynq_fpga_priv *priv = mgr->priv; int err; @@ -364,7 +366,7 @@ static int zynq_fpga_ops_write_complete(struct fpga_manager *mgr, u32 flags) return err; /* for the partial reconfig case we didn't touch the level shifters */ - if (!(flags & FPGA_MGR_PARTIAL_RECONFIG)) { + if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { /* enable level shifters from PL to PS */ regmap_write(priv->slcr, SLCR_LVL_SHFTR_EN_OFFSET, LVL_SHFTR_ENABLE_PL_TO_PS); diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h index 957b5ac9428a..55803186e0ea 100644 --- a/include/linux/fpga/fpga-mgr.h +++ b/include/linux/fpga/fpga-mgr.h @@ -68,6 +68,18 @@ enum fpga_mgr_states { */ #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) +/** + * struct fpga_image_info - information specific to a FPGA image + * @flags: boolean flags as defined above + * @enable_timeout_us: maximum time to enable traffic through bridge (uSec) + * @disable_timeout_us: maximum time to disable traffic through bridge (uSec) + */ +struct fpga_image_info { + u32 flags; + u32 enable_timeout_us; + u32 disable_timeout_us; +}; + /** * struct fpga_manager_ops - ops for low level fpga manager drivers * @state: returns an enum value of the FPGA's state @@ -82,10 +94,12 @@ enum fpga_mgr_states { */ struct fpga_manager_ops { enum fpga_mgr_states (*state)(struct fpga_manager *mgr); - int (*write_init)(struct fpga_manager *mgr, u32 flags, + int (*write_init)(struct fpga_manager *mgr, + struct fpga_image_info *info, const char *buf, size_t count); int (*write)(struct fpga_manager *mgr, const char *buf, size_t count); - int (*write_complete)(struct fpga_manager *mgr, u32 flags); + int (*write_complete)(struct fpga_manager *mgr, + struct fpga_image_info *info); void (*fpga_remove)(struct fpga_manager *mgr); }; @@ -109,10 +123,11 @@ struct fpga_manager { #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev) -int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, +int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, const char *buf, size_t count); -int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags, +int fpga_mgr_firmware_load(struct fpga_manager *mgr, + struct fpga_image_info *info, const char *image_name); struct fpga_manager *of_fpga_mgr_get(struct device_node *node); -- cgit v1.2.3 From 1d7f1589d341344c0c598b00de44891a7968c6a0 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Nov 2016 18:22:09 +0000 Subject: fpga: Clarify how write_init works streaming modes This interface was designed for streaming, but write_init's buf argument has an unclear purpose. Define it to be the first bytes of the bitstream. Each driver gets to set how many bytes (at most) it wants to see. Short bitstreams will be passed through as-is, while long ones will be truncated. The intent is to allow drivers to peek at the header before the transfer actually starts. Signed-off-by: Jason Gunthorpe Acked-by: Alan Tull --- Documentation/fpga/fpga-mgr.txt | 5 ++++- drivers/fpga/fpga-mgr.c | 6 ++++-- drivers/fpga/socfpga-a10.c | 1 + include/linux/fpga/fpga-mgr.h | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/fpga/fpga-mgr.c') diff --git a/Documentation/fpga/fpga-mgr.txt b/Documentation/fpga/fpga-mgr.txt index 087924f2b20c..86ee5078fd03 100644 --- a/Documentation/fpga/fpga-mgr.txt +++ b/Documentation/fpga/fpga-mgr.txt @@ -169,7 +169,10 @@ The programming sequence is: 2. .write (may be called once or multiple times) 3. .write_complete -The .write_init function will prepare the FPGA to receive the image data. +The .write_init function will prepare the FPGA to receive the image data. The +buffer passed into .write_init will be atmost .initial_header_size bytes long, +if the whole bitstream is not immediately available then the core code will +buffer up at least this much before starting. The .write function writes a buffer to the FPGA. The buffer may be contain the whole FPGA image or may be a smaller chunk of an FPGA image. In the latter diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 79ce2eea44db..f0a69d3e60a5 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -53,10 +53,12 @@ int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, /* * 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. + * ready to receive an FPGA image. The low level driver only gets to + * see the first initial_header_size bytes in the buffer. */ mgr->state = FPGA_MGR_STATE_WRITE_INIT; - ret = mgr->mops->write_init(mgr, info, buf, count); + ret = mgr->mops->write_init(mgr, info, buf, + min(mgr->mops->initial_header_size, count)); if (ret) { dev_err(dev, "Error preparing FPGA for writing\n"); mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR; diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c index ccd9fb23bd52..f8770af0f6b5 100644 --- a/drivers/fpga/socfpga-a10.c +++ b/drivers/fpga/socfpga-a10.c @@ -470,6 +470,7 @@ static enum fpga_mgr_states socfpga_a10_fpga_state(struct fpga_manager *mgr) } static const struct fpga_manager_ops socfpga_a10_fpga_mgr_ops = { + .initial_header_size = (RBF_DECOMPRESS_OFFSET + 1) * 4, .state = socfpga_a10_fpga_state, .write_init = socfpga_a10_fpga_write_init, .write = socfpga_a10_fpga_write, diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h index 96a1a3311649..16551d5eac36 100644 --- a/include/linux/fpga/fpga-mgr.h +++ b/include/linux/fpga/fpga-mgr.h @@ -84,6 +84,7 @@ struct fpga_image_info { /** * struct fpga_manager_ops - ops for low level fpga manager drivers + * @initial_header_size: Maximum number of bytes that should be passed into write_init * @state: returns an enum value of the FPGA's state * @write_init: prepare the FPGA to receive confuration data * @write: write count bytes of configuration data to the FPGA @@ -95,6 +96,7 @@ struct fpga_image_info { * called, so leaving them out is fine. */ struct fpga_manager_ops { + size_t initial_header_size; enum fpga_mgr_states (*state)(struct fpga_manager *mgr); int (*write_init)(struct fpga_manager *mgr, struct fpga_image_info *info, -- cgit v1.2.3