From 7085e2a94f7df5f419e3cfb2fe809ce6564e9629 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Wed, 16 May 2018 18:49:55 -0500 Subject: fpga: manager: change api, don't use drvdata Change fpga_mgr_register to not set or use drvdata. This supports the case where a PCIe device has more than one manager. Add fpga_mgr_create/free functions. Change fpga_mgr_register and fpga_mgr_unregister functions to take the mgr struct as their only parameter. struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name, const struct fpga_manager_ops *mops, void *priv); void fpga_mgr_free(struct fpga_manager *mgr); int fpga_mgr_register(struct fpga_manager *mgr); void fpga_mgr_unregister(struct fpga_manager *mgr); Update the drivers that call fpga_mgr_register with the new API. Signed-off-by: Alan Tull [Moritz: Fixup whitespace issue] Reported-by: Jiuyue Ma Signed-off-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- Documentation/fpga/fpga-mgr.txt | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'Documentation/fpga') diff --git a/Documentation/fpga/fpga-mgr.txt b/Documentation/fpga/fpga-mgr.txt index cc6413ed6fc9..86b6df66a905 100644 --- a/Documentation/fpga/fpga-mgr.txt +++ b/Documentation/fpga/fpga-mgr.txt @@ -63,17 +63,23 @@ The user should call fpga_mgr_lock and verify that it returns 0 before attempting to program the FPGA. Likewise, the user should call fpga_mgr_unlock when done programming the FPGA. +To alloc/free a FPGA manager struct: +------------------------------------ + + struct fpga_manager *fpga_mgr_create(struct device *dev, + const char *name, + const struct fpga_manager_ops *mops, + void *priv); + void fpga_mgr_free(struct fpga_manager *mgr); To register or unregister the low level FPGA-specific driver: ------------------------------------------------------------- - int fpga_mgr_register(struct device *dev, const char *name, - const struct fpga_manager_ops *mops, - void *priv); + int fpga_mgr_register(struct fpga_manager *mgr); - void fpga_mgr_unregister(struct device *dev); + void fpga_mgr_unregister(struct fpga_manager *mgr); -Use of these two functions is described below in "How To Support a new FPGA +Use of these functions is described below in "How To Support a new FPGA device." @@ -148,6 +154,7 @@ static int socfpga_fpga_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct socfpga_fpga_priv *priv; + struct fpga_manager *mgr; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -157,13 +164,25 @@ static int socfpga_fpga_probe(struct platform_device *pdev) /* ... do ioremaps, get interrupts, etc. and save them in priv... */ - return fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager", - &socfpga_fpga_ops, priv); + mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager", + &socfpga_fpga_ops, priv); + if (!mgr) + return -ENOMEM; + + platform_set_drvdata(pdev, mgr); + + ret = fpga_mgr_register(mgr); + if (ret) + fpga_mgr_free(mgr); + + return ret; } static int socfpga_fpga_remove(struct platform_device *pdev) { - fpga_mgr_unregister(&pdev->dev); + struct fpga_manager *mgr = platform_get_drvdata(pdev); + + fpga_mgr_unregister(mgr); return 0; } -- cgit v1.2.3 From 9f368977b4589e2fe0b9d3a4cbaf11ff6a58ecf5 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Wed, 16 May 2018 18:49:57 -0500 Subject: fpga: region: change api, add fpga_region_create/free Add fpga_region_create/free API functions. Change fpga_region_register to take FPGA region struct as the only parameter. Change fpga_region_unregister to return void. struct fpga_region *fpga_region_create(struct device *dev, struct fpga_manager *mgr, int (*get_bridges)(struct fpga_region *)); void fpga_region_free(struct fpga_region *region); int fpga_region_register(struct fpga_region *region); void fpga_region_unregister(struct fpga_region *region); Remove groups storage from struct fpga_region, it's not needed. Callers can just "region->dev.groups = groups;" after calling fpga_region_create. Update the drivers that call fpga_region_register with the new API. Signed-off-by: Alan Tull Signed-off-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- Documentation/fpga/fpga-region.txt | 3 +- drivers/fpga/fpga-region.c | 68 ++++++++++++++++++++++++++++++-------- drivers/fpga/of-fpga-region.c | 13 +++----- include/linux/fpga/fpga-region.h | 11 +++--- 4 files changed, 68 insertions(+), 27 deletions(-) (limited to 'Documentation/fpga') diff --git a/Documentation/fpga/fpga-region.txt b/Documentation/fpga/fpga-region.txt index 139a02ba1ff6..d38fa3b4154a 100644 --- a/Documentation/fpga/fpga-region.txt +++ b/Documentation/fpga/fpga-region.txt @@ -42,8 +42,7 @@ The FPGA region API To register or unregister a region: ----------------------------------- - int fpga_region_register(struct device *dev, - struct fpga_region *region); + int fpga_region_register(struct fpga_region *region); int fpga_region_unregister(struct fpga_region *region); An example of usage can be seen in the probe function of [3] diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index f634a8ed5e2c..b3ba3e40c44b 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c @@ -167,18 +167,36 @@ err_put_region: } EXPORT_SYMBOL_GPL(fpga_region_program_fpga); -int fpga_region_register(struct device *dev, struct fpga_region *region) +/** + * fpga_region_create - alloc and init a struct fpga_region + * @dev: device parent + * @mgr: manager that programs this region + * @get_bridges: optional function to get bridges to a list + * + * Return: struct fpga_region or NULL + */ +struct fpga_region +*fpga_region_create(struct device *dev, + struct fpga_manager *mgr, + int (*get_bridges)(struct fpga_region *)) { + struct fpga_region *region; int id, ret = 0; + region = kzalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return NULL; + id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); if (id < 0) - return id; + goto err_free; + region->mgr = mgr; + region->get_bridges = get_bridges; mutex_init(®ion->mutex); INIT_LIST_HEAD(®ion->bridge_list); + device_initialize(®ion->dev); - region->dev.groups = region->groups; region->dev.class = fpga_region_class; region->dev.parent = dev; region->dev.of_node = dev->of_node; @@ -188,23 +206,47 @@ int fpga_region_register(struct device *dev, struct fpga_region *region) if (ret) goto err_remove; - ret = device_add(®ion->dev); - if (ret) - goto err_remove; - - return 0; + return region; err_remove: ida_simple_remove(&fpga_region_ida, id); - return ret; +err_free: + kfree(region); + + return NULL; +} +EXPORT_SYMBOL_GPL(fpga_region_create); + +/** + * fpga_region_free - free a struct fpga_region + * @region: FPGA region created by fpga_region_create + */ +void fpga_region_free(struct fpga_region *region) +{ + ida_simple_remove(&fpga_region_ida, region->dev.id); + kfree(region); +} +EXPORT_SYMBOL_GPL(fpga_region_free); + +/* + * fpga_region_register - register a FPGA region + * @region: FPGA region created by fpga_region_create + * Return: 0 or -errno + */ +int fpga_region_register(struct fpga_region *region) +{ + return device_add(®ion->dev); + } EXPORT_SYMBOL_GPL(fpga_region_register); -int fpga_region_unregister(struct fpga_region *region) +/* + * fpga_region_unregister - unregister a FPGA region + * @region: FPGA region + */ +void fpga_region_unregister(struct fpga_region *region) { device_unregister(®ion->dev); - - return 0; } EXPORT_SYMBOL_GPL(fpga_region_unregister); @@ -212,7 +254,7 @@ static void fpga_region_dev_release(struct device *dev) { struct fpga_region *region = to_fpga_region(dev); - ida_simple_remove(&fpga_region_ida, region->dev.id); + fpga_region_free(region); } /** diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c index 35e7e8c4a0cb..9d681a1c5738 100644 --- a/drivers/fpga/of-fpga-region.c +++ b/drivers/fpga/of-fpga-region.c @@ -422,20 +422,15 @@ static int of_fpga_region_probe(struct platform_device *pdev) if (IS_ERR(mgr)) return -EPROBE_DEFER; - region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL); + region = fpga_region_create(dev, mgr, of_fpga_region_get_bridges); if (!region) { ret = -ENOMEM; goto eprobe_mgr_put; } - region->mgr = mgr; - - /* Specify how to get bridges for this type of region. */ - region->get_bridges = of_fpga_region_get_bridges; - - ret = fpga_region_register(dev, region); + ret = fpga_region_register(region); if (ret) - goto eprobe_mgr_put; + goto eprobe_free; of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); dev_set_drvdata(dev, region); @@ -444,6 +439,8 @@ static int of_fpga_region_probe(struct platform_device *pdev) return 0; +eprobe_free: + fpga_region_free(region); eprobe_mgr_put: fpga_mgr_put(mgr); return ret; diff --git a/include/linux/fpga/fpga-region.h b/include/linux/fpga/fpga-region.h index b6520318ab9c..f2e215bd1330 100644 --- a/include/linux/fpga/fpga-region.h +++ b/include/linux/fpga/fpga-region.h @@ -14,7 +14,6 @@ * @info: FPGA image info * @priv: private data * @get_bridges: optional function to get bridges to a list - * @groups: optional attribute groups. */ struct fpga_region { struct device dev; @@ -24,7 +23,6 @@ struct fpga_region { struct fpga_image_info *info; void *priv; int (*get_bridges)(struct fpga_region *region); - const struct attribute_group **groups; }; #define to_fpga_region(d) container_of(d, struct fpga_region, dev) @@ -34,7 +32,12 @@ struct fpga_region *fpga_region_class_find( int (*match)(struct device *, const void *)); int fpga_region_program_fpga(struct fpga_region *region); -int fpga_region_register(struct device *dev, struct fpga_region *region); -int fpga_region_unregister(struct fpga_region *region); + +struct fpga_region +*fpga_region_create(struct device *dev, struct fpga_manager *mgr, + int (*get_bridges)(struct fpga_region *)); +void fpga_region_free(struct fpga_region *region); +int fpga_region_register(struct fpga_region *region); +void fpga_region_unregister(struct fpga_region *region); #endif /* _FPGA_REGION_H */ -- cgit v1.2.3 From 66c472cdb62d7b00de55722a772f7dfecf88abd1 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Wed, 16 May 2018 18:50:02 -0500 Subject: Documentation: fpga: move fpga overview to driver-api Start of moving Documentation/fpga/*.txt to driver-api, including: - Add new directory driver-api/fpga - Add new file driver-api/fpga/index.rst - Add driver-api/fpga to driver-api/index.rst - Move Documentation/fpga/overview.txt to driver-api/fpga/intro.rst - Formatting and rewrites so that intro.rst will build cleanly and form a good introduction to the rest of the docs to be added. Signed-off-by: Alan Tull Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/fpga/index.rst | 10 ++++++ Documentation/driver-api/fpga/intro.rst | 54 +++++++++++++++++++++++++++++++++ Documentation/driver-api/index.rst | 1 + Documentation/fpga/overview.txt | 23 -------------- 4 files changed, 65 insertions(+), 23 deletions(-) create mode 100644 Documentation/driver-api/fpga/index.rst create mode 100644 Documentation/driver-api/fpga/intro.rst delete mode 100644 Documentation/fpga/overview.txt (limited to 'Documentation/fpga') diff --git a/Documentation/driver-api/fpga/index.rst b/Documentation/driver-api/fpga/index.rst new file mode 100644 index 000000000000..71e568aea6cd --- /dev/null +++ b/Documentation/driver-api/fpga/index.rst @@ -0,0 +1,10 @@ +============== +FPGA Subsystem +============== + +:Author: Alan Tull + +.. toctree:: + :maxdepth: 2 + + intro diff --git a/Documentation/driver-api/fpga/intro.rst b/Documentation/driver-api/fpga/intro.rst new file mode 100644 index 000000000000..51cd81dbb4dc --- /dev/null +++ b/Documentation/driver-api/fpga/intro.rst @@ -0,0 +1,54 @@ +Introduction +============ + +The FPGA subsystem supports reprogramming FPGAs dynamically under +Linux. Some of the core intentions of the FPGA subsystems are: + +* The FPGA subsystem is vendor agnostic. + +* The FPGA subsystem separates upper layers (userspace interfaces and + enumeration) from lower layers that know how to program a specific + FPGA. + +* Code should not be shared between upper and lower layers. This + should go without saying. If that seems necessary, there's probably + framework functionality that that can be added that will benefit + other users. Write the linux-fpga mailing list and maintainers and + seek out a solution that expands the framework for broad reuse. + +* Generally, when adding code, think of the future. Plan for re-use. + +The framework in the kernel is divided into: + +FPGA Manager +------------ + +If you are adding a new FPGA or a new method of programming a FPGA, +this is the subsystem for you. Low level FPGA manager drivers contain +the knowledge of how to program a specific device. This subsystem +includes the framework in fpga-mgr.c and the low level drivers that +are registered with it. + +FPGA Bridge +----------- + +FPGA Bridges prevent spurious signals from going out of a FPGA or a +region of a FPGA during programming. They are disabled before +programming begins and re-enabled afterwards. An FPGA bridge may be +actual hard hardware that gates a bus to a cpu or a soft ("freeze") +bridge in FPGA fabric that surrounds a partial reconfiguration region +of an FPGA. This subsystem includes fpga-bridge.c and the low level +drivers that are registered with it. + +FPGA Region +----------- + +If you are adding a new interface to the FPGA framework, add it on top +of a FPGA region to allow the most reuse of your interface. + +The FPGA Region framework (fpga-region.c) associates managers and +bridges as reconfigurable regions. A region may refer to the whole +FPGA in full reconfiguration or to a partial reconfiguration region. + +The Device Tree FPGA Region support (of-fpga-region.c) handles +reprogramming FPGAs when device tree overlays are applied. diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index 6d8352c0f354..ed40ec090299 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -49,6 +49,7 @@ available subsections can be seen below. dmaengine/index slimbus soundwire/index + fpga/index .. only:: subproject and html diff --git a/Documentation/fpga/overview.txt b/Documentation/fpga/overview.txt deleted file mode 100644 index 0f1236e7e675..000000000000 --- a/Documentation/fpga/overview.txt +++ /dev/null @@ -1,23 +0,0 @@ -Linux kernel FPGA support - -Alan Tull 2017 - -The main point of this project has been to separate the out the upper layers -that know when to reprogram a FPGA from the lower layers that know how to -reprogram a specific FPGA device. The intention is to make this manufacturer -agnostic, understanding that of course the FPGA images are very device specific -themselves. - -The framework in the kernel includes: -* low level FPGA manager drivers that know how to program a specific device -* the fpga-mgr framework they are registered with -* low level FPGA bridge drivers for hard/soft bridges which are intended to - be disable during FPGA programming -* the fpga-bridge framework they are registered with -* the fpga-region framework which associates and controls managers and bridges - as reconfigurable regions -* the of-fpga-region support for reprogramming FPGAs when device tree overlays - are applied. - -I would encourage you the user to add code that creates FPGA regions rather -that trying to control managers and bridges separately. -- cgit v1.2.3 From 547b822c22b18e346ee1d562d1787486e5c88c3c Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Wed, 16 May 2018 18:50:03 -0500 Subject: documentation: fpga: move fpga-mgr.txt to driver-api Move Documentation/fpga/fpga-mgr.txt to driver-api/fpga/fpga-mgr.rst and: - Add to driver-api/fpga/index.rst - Format changes so documentation builds cleanly. - Minor rewrites that make the doc flow better as ReST documentation. - Such as moving API reference to end of doc - Change API reference section to refer to kernel-doc documentation in fpga-mgr.c driver code rather than statically defining each function. Signed-off-by: Alan Tull Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/fpga/fpga-mgr.rst | 220 +++++++++++++++++++++++++++++ Documentation/driver-api/fpga/index.rst | 1 + Documentation/fpga/fpga-mgr.txt | 218 ---------------------------- 3 files changed, 221 insertions(+), 218 deletions(-) create mode 100644 Documentation/driver-api/fpga/fpga-mgr.rst delete mode 100644 Documentation/fpga/fpga-mgr.txt (limited to 'Documentation/fpga') diff --git a/Documentation/driver-api/fpga/fpga-mgr.rst b/Documentation/driver-api/fpga/fpga-mgr.rst new file mode 100644 index 000000000000..bcf2dd24e179 --- /dev/null +++ b/Documentation/driver-api/fpga/fpga-mgr.rst @@ -0,0 +1,220 @@ +FPGA Manager +============ + +Overview +-------- + +The FPGA manager core exports a set of functions for programming an FPGA with +an image. The API is manufacturer agnostic. All manufacturer specifics are +hidden away in a low level driver which registers a set of ops with the core. +The FPGA image data itself is very manufacturer specific, but for our purposes +it's just binary data. The FPGA manager core won't parse it. + +The FPGA image to be programmed can be in a scatter gather list, a single +contiguous buffer, or a firmware file. Because allocating contiguous kernel +memory for the buffer should be avoided, users are encouraged to use a scatter +gather list instead if possible. + +The particulars for programming the image are presented in a structure (struct +fpga_image_info). This struct contains parameters such as pointers to the +FPGA image as well as image-specific particulars such as whether the image was +built for full or partial reconfiguration. + +How to support a new FPGA device +-------------------------------- + +To add another FPGA manager, write a driver that implements a set of ops. The +probe function calls fpga_mgr_register(), such as:: + + static const struct fpga_manager_ops socfpga_fpga_ops = { + .write_init = socfpga_fpga_ops_configure_init, + .write = socfpga_fpga_ops_configure_write, + .write_complete = socfpga_fpga_ops_configure_complete, + .state = socfpga_fpga_ops_state, + }; + + static int socfpga_fpga_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct socfpga_fpga_priv *priv; + struct fpga_manager *mgr; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* + * do ioremaps, get interrupts, etc. and save + * them in priv + */ + + mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager", + &socfpga_fpga_ops, priv); + if (!mgr) + return -ENOMEM; + + platform_set_drvdata(pdev, mgr); + + ret = fpga_mgr_register(mgr); + if (ret) + fpga_mgr_free(mgr); + + return ret; + } + + static int socfpga_fpga_remove(struct platform_device *pdev) + { + struct fpga_manager *mgr = platform_get_drvdata(pdev); + + fpga_mgr_unregister(mgr); + + return 0; + } + + +The ops will implement whatever device specific register writes are needed to +do the programming sequence for this particular FPGA. These ops return 0 for +success or negative error codes otherwise. + +The programming sequence is:: + 1. .write_init + 2. .write or .write_sg (may be called once or multiple times) + 3. .write_complete + +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 +case, this function is called multiple times for successive chunks. This interface +is suitable for drivers which use PIO. + +The .write_sg version behaves the same as .write except the input is a sg_table +scatter list. This interface is suitable for drivers which use DMA. + +The .write_complete function is called after all the image has been written +to put the FPGA into operating mode. + +The ops include a .state function which will read the hardware FPGA manager and +return a code of type enum fpga_mgr_states. It doesn't result in a change in +hardware state. + +How to write an image buffer to a supported FPGA +------------------------------------------------ + +Some sample code:: + + #include + + struct fpga_manager *mgr; + struct fpga_image_info *info; + int ret; + + /* + * Get a reference to FPGA manager. The manager is not locked, so you can + * hold onto this reference without it preventing programming. + * + * This example uses the device node of the manager. Alternatively, use + * fpga_mgr_get(dev) instead if you have the device. + */ + mgr = of_fpga_mgr_get(mgr_node); + + /* struct with information about the FPGA image to program. */ + info = fpga_image_info_alloc(dev); + + /* flags indicates whether to do full or partial reconfiguration */ + info->flags = FPGA_MGR_PARTIAL_RECONFIG; + + /* + * At this point, indicate where the image is. This is pseudo-code; you're + * going to use one of these three. + */ + if (image is in a scatter gather table) { + + info->sgt = [your scatter gather table] + + } else if (image is in a buffer) { + + info->buf = [your image buffer] + info->count = [image buffer size] + + } else if (image is in a firmware file) { + + info->firmware_name = devm_kstrdup(dev, firmware_name, GFP_KERNEL); + + } + + /* Get exclusive control of FPGA manager */ + ret = fpga_mgr_lock(mgr); + + /* Load the buffer to the FPGA */ + ret = fpga_mgr_buf_load(mgr, &info, buf, count); + + /* Release the FPGA manager */ + fpga_mgr_unlock(mgr); + fpga_mgr_put(mgr); + + /* Deallocate the image info if you're done with it */ + fpga_image_info_free(info); + +API for implementing a new FPGA Manager driver +---------------------------------------------- + +.. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_manager + +.. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_manager_ops + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_create + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_free + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_register + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_unregister + +API for programming a FPGA +-------------------------- + +.. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_image_info + +.. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_mgr_states + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_image_info_alloc + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_image_info_free + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: of_fpga_mgr_get + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_get + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_put + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_lock + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_unlock + +.. kernel-doc:: include/linux/fpga/fpga-mgr.h + :functions: fpga_mgr_states + +Note - use :c:func:`fpga_region_program_fpga()` instead of :c:func:`fpga_mgr_load()` + +.. kernel-doc:: drivers/fpga/fpga-mgr.c + :functions: fpga_mgr_load diff --git a/Documentation/driver-api/fpga/index.rst b/Documentation/driver-api/fpga/index.rst index 71e568aea6cd..34b20754517f 100644 --- a/Documentation/driver-api/fpga/index.rst +++ b/Documentation/driver-api/fpga/index.rst @@ -8,3 +8,4 @@ FPGA Subsystem :maxdepth: 2 intro + fpga-mgr diff --git a/Documentation/fpga/fpga-mgr.txt b/Documentation/fpga/fpga-mgr.txt deleted file mode 100644 index 86b6df66a905..000000000000 --- a/Documentation/fpga/fpga-mgr.txt +++ /dev/null @@ -1,218 +0,0 @@ -FPGA Manager Core - -Alan Tull 2015 - -Overview -======== - -The FPGA manager core exports a set of functions for programming an FPGA with -an image. The API is manufacturer agnostic. All manufacturer specifics are -hidden away in a low level driver which registers a set of ops with the core. -The FPGA image data itself is very manufacturer specific, but for our purposes -it's just binary data. The FPGA manager core won't parse it. - -The FPGA image to be programmed can be in a scatter gather list, a single -contiguous buffer, or a firmware file. Because allocating contiguous kernel -memory for the buffer should be avoided, users are encouraged to use a scatter -gather list instead if possible. - -The particulars for programming the image are presented in a structure (struct -fpga_image_info). This struct contains parameters such as pointers to the -FPGA image as well as image-specific particulars such as whether the image was -built for full or partial reconfiguration. - -API Functions: -============== - -To program the FPGA: --------------------- - - int fpga_mgr_load(struct fpga_manager *mgr, - struct fpga_image_info *info); - -Load the FPGA from an image which is indicated in the info. If successful, -the FPGA ends up in operating mode. Return 0 on success or a negative error -code. - -To allocate or free a struct fpga_image_info: ---------------------------------------------- - - struct fpga_image_info *fpga_image_info_alloc(struct device *dev); - - void fpga_image_info_free(struct fpga_image_info *info); - -To get/put a reference to a FPGA manager: ------------------------------------------ - - struct fpga_manager *of_fpga_mgr_get(struct device_node *node); - struct fpga_manager *fpga_mgr_get(struct device *dev); - void fpga_mgr_put(struct fpga_manager *mgr); - -Given a DT node or device, get a reference to a FPGA manager. This pointer -can be saved until you are ready to program the FPGA. fpga_mgr_put releases -the reference. - - -To get exclusive control of a FPGA manager: -------------------------------------------- - - int fpga_mgr_lock(struct fpga_manager *mgr); - void fpga_mgr_unlock(struct fpga_manager *mgr); - -The user should call fpga_mgr_lock and verify that it returns 0 before -attempting to program the FPGA. Likewise, the user should call -fpga_mgr_unlock when done programming the FPGA. - -To alloc/free a FPGA manager struct: ------------------------------------- - - struct fpga_manager *fpga_mgr_create(struct device *dev, - const char *name, - const struct fpga_manager_ops *mops, - void *priv); - void fpga_mgr_free(struct fpga_manager *mgr); - -To register or unregister the low level FPGA-specific driver: -------------------------------------------------------------- - - int fpga_mgr_register(struct fpga_manager *mgr); - - void fpga_mgr_unregister(struct fpga_manager *mgr); - -Use of these functions is described below in "How To Support a new FPGA -device." - - -How to write an image buffer to a supported FPGA -================================================ -#include - -struct fpga_manager *mgr; -struct fpga_image_info *info; -int ret; - -/* - * Get a reference to FPGA manager. The manager is not locked, so you can - * hold onto this reference without it preventing programming. - * - * This example uses the device node of the manager. Alternatively, use - * fpga_mgr_get(dev) instead if you have the device. - */ -mgr = of_fpga_mgr_get(mgr_node); - -/* struct with information about the FPGA image to program. */ -info = fpga_image_info_alloc(dev); - -/* flags indicates whether to do full or partial reconfiguration */ -info->flags = FPGA_MGR_PARTIAL_RECONFIG; - -/* - * At this point, indicate where the image is. This is pseudo-code; you're - * going to use one of these three. - */ -if (image is in a scatter gather table) { - - info->sgt = [your scatter gather table] - -} else if (image is in a buffer) { - - info->buf = [your image buffer] - info->count = [image buffer size] - -} else if (image is in a firmware file) { - - info->firmware_name = devm_kstrdup(dev, firmware_name, GFP_KERNEL); - -} - -/* Get exclusive control of FPGA manager */ -ret = fpga_mgr_lock(mgr); - -/* Load the buffer to the FPGA */ -ret = fpga_mgr_buf_load(mgr, &info, buf, count); - -/* Release the FPGA manager */ -fpga_mgr_unlock(mgr); -fpga_mgr_put(mgr); - -/* Deallocate the image info if you're done with it */ -fpga_image_info_free(info); - -How to support a new FPGA device -================================ -To add another FPGA manager, write a driver that implements a set of ops. The -probe function calls fpga_mgr_register(), such as: - -static const struct fpga_manager_ops socfpga_fpga_ops = { - .write_init = socfpga_fpga_ops_configure_init, - .write = socfpga_fpga_ops_configure_write, - .write_complete = socfpga_fpga_ops_configure_complete, - .state = socfpga_fpga_ops_state, -}; - -static int socfpga_fpga_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct socfpga_fpga_priv *priv; - struct fpga_manager *mgr; - int ret; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - /* ... do ioremaps, get interrupts, etc. and save - them in priv... */ - - mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager", - &socfpga_fpga_ops, priv); - if (!mgr) - return -ENOMEM; - - platform_set_drvdata(pdev, mgr); - - ret = fpga_mgr_register(mgr); - if (ret) - fpga_mgr_free(mgr); - - return ret; -} - -static int socfpga_fpga_remove(struct platform_device *pdev) -{ - struct fpga_manager *mgr = platform_get_drvdata(pdev); - - fpga_mgr_unregister(mgr); - - return 0; -} - - -The ops will implement whatever device specific register writes are needed to -do the programming sequence for this particular FPGA. These ops return 0 for -success or negative error codes otherwise. - -The programming sequence is: - 1. .write_init - 2. .write or .write_sg (may be called once or multiple times) - 3. .write_complete - -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 -case, this function is called multiple times for successive chunks. This interface -is suitable for drivers which use PIO. - -The .write_sg version behaves the same as .write except the input is a sg_table -scatter list. This interface is suitable for drivers which use DMA. - -The .write_complete function is called after all the image has been written -to put the FPGA into operating mode. - -The ops include a .state function which will read the hardware FPGA manager and -return a code of type enum fpga_mgr_states. It doesn't result in a change in -hardware state. -- cgit v1.2.3 From fcc803956a4725dac790ddfce27f519ca6d84c60 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Wed, 16 May 2018 18:50:05 -0500 Subject: documentation: fpga: move fpga-region.txt to driver-api Move Documentation/fpga/fpga-region.txt to driver-api/fpga/fpga-region.rst. Including: - Add it to driver-api/fpga/index.rst - Formatting changes to build cleanly as ReST documentation - Some rewrites for better flow as a ReST doc such as moving API reference to the end of the doc - Rewrite API reference section to refer to kernel-doc documentation in fpga-region.c driver code Signed-off-by: Alan Tull Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/fpga/fpga-region.rst | 102 ++++++++++++++++++++++++++ Documentation/driver-api/fpga/index.rst | 1 + Documentation/fpga/fpga-region.txt | 94 ------------------------ 3 files changed, 103 insertions(+), 94 deletions(-) create mode 100644 Documentation/driver-api/fpga/fpga-region.rst delete mode 100644 Documentation/fpga/fpga-region.txt (limited to 'Documentation/fpga') diff --git a/Documentation/driver-api/fpga/fpga-region.rst b/Documentation/driver-api/fpga/fpga-region.rst new file mode 100644 index 000000000000..f89e4a311722 --- /dev/null +++ b/Documentation/driver-api/fpga/fpga-region.rst @@ -0,0 +1,102 @@ +FPGA Region +=========== + +Overview +-------- + +This document is meant to be an brief overview of the FPGA region API usage. A +more conceptual look at regions can be found in the Device Tree binding +document [#f1]_. + +For the purposes of this API document, let's just say that a region associates +an FPGA Manager and a bridge (or bridges) with a reprogrammable region of an +FPGA or the whole FPGA. The API provides a way to register a region and to +program a region. + +Currently the only layer above fpga-region.c in the kernel is the Device Tree +support (of-fpga-region.c) described in [#f1]_. The DT support layer uses regions +to program the FPGA and then DT to handle enumeration. The common region code +is intended to be used by other schemes that have other ways of accomplishing +enumeration after programming. + +An fpga-region can be set up to know the following things: + + * which FPGA manager to use to do the programming + + * which bridges to disable before programming and enable afterwards. + +Additional info needed to program the FPGA image is passed in the struct +fpga_image_info including: + + * pointers to the image as either a scatter-gather buffer, a contiguous + buffer, or the name of firmware file + + * flags indicating specifics such as whether the image if for partial + reconfiguration. + +How to program a FPGA using a region +------------------------------------ + +First, allocate the info struct:: + + info = fpga_image_info_alloc(dev); + if (!info) + return -ENOMEM; + +Set flags as needed, i.e.:: + + info->flags |= FPGA_MGR_PARTIAL_RECONFIG; + +Point to your FPGA image, such as:: + + info->sgt = &sgt; + +Add info to region and do the programming:: + + region->info = info; + ret = fpga_region_program_fpga(region); + +:c:func:`fpga_region_program_fpga()` operates on info passed in the +fpga_image_info (region->info). This function will attempt to: + + * lock the region's mutex + * lock the region's FPGA manager + * build a list of FPGA bridges if a method has been specified to do so + * disable the bridges + * program the FPGA + * re-enable the bridges + * release the locks + +Then you will want to enumerate whatever hardware has appeared in the FPGA. + +How to add a new FPGA region +---------------------------- + +An example of usage can be seen in the probe function of [#f2]_. + +.. [#f1] ../devicetree/bindings/fpga/fpga-region.txt +.. [#f2] ../../drivers/fpga/of-fpga-region.c + +API to program a FGPA +--------------------- + +.. kernel-doc:: drivers/fpga/fpga-region.c + :functions: fpga_region_program_fpga + +API to add a new FPGA region +---------------------------- + +.. kernel-doc:: include/linux/fpga/fpga-region.h + :functions: fpga_region + +.. kernel-doc:: drivers/fpga/fpga-region.c + :functions: fpga_region_create + +.. kernel-doc:: drivers/fpga/fpga-region.c + :functions: fpga_region_free + +.. kernel-doc:: drivers/fpga/fpga-region.c + :functions: fpga_region_register + +.. kernel-doc:: drivers/fpga/fpga-region.c + :functions: fpga_region_unregister diff --git a/Documentation/driver-api/fpga/index.rst b/Documentation/driver-api/fpga/index.rst index 968bbbfce0e8..c51e5ebd544a 100644 --- a/Documentation/driver-api/fpga/index.rst +++ b/Documentation/driver-api/fpga/index.rst @@ -10,3 +10,4 @@ FPGA Subsystem intro fpga-mgr fpga-bridge + fpga-region diff --git a/Documentation/fpga/fpga-region.txt b/Documentation/fpga/fpga-region.txt deleted file mode 100644 index d38fa3b4154a..000000000000 --- a/Documentation/fpga/fpga-region.txt +++ /dev/null @@ -1,94 +0,0 @@ -FPGA Regions - -Alan Tull 2017 - -CONTENTS - - Introduction - - The FPGA region API - - Usage example - -Introduction -============ - -This document is meant to be an brief overview of the FPGA region API usage. A -more conceptual look at regions can be found in [1]. - -For the purposes of this API document, let's just say that a region associates -an FPGA Manager and a bridge (or bridges) with a reprogrammable region of an -FPGA or the whole FPGA. The API provides a way to register a region and to -program a region. - -Currently the only layer above fpga-region.c in the kernel is the Device Tree -support (of-fpga-region.c) described in [1]. The DT support layer uses regions -to program the FPGA and then DT to handle enumeration. The common region code -is intended to be used by other schemes that have other ways of accomplishing -enumeration after programming. - -An fpga-region can be set up to know the following things: -* which FPGA manager to use to do the programming -* which bridges to disable before programming and enable afterwards. - -Additional info needed to program the FPGA image is passed in the struct -fpga_image_info [2] including: -* pointers to the image as either a scatter-gather buffer, a contiguous - buffer, or the name of firmware file -* flags indicating specifics such as whether the image if for partial - reconfiguration. - -=================== -The FPGA region API -=================== - -To register or unregister a region: ------------------------------------ - - int fpga_region_register(struct fpga_region *region); - int fpga_region_unregister(struct fpga_region *region); - -An example of usage can be seen in the probe function of [3] - -To program an FPGA: -------------------- - int fpga_region_program_fpga(struct fpga_region *region); - -This function operates on info passed in the fpga_image_info -(region->info). - -This function will attempt to: - * lock the region's mutex - * lock the region's FPGA manager - * build a list of FPGA bridges if a method has been specified to do so - * disable the bridges - * program the FPGA - * re-enable the bridges - * release the locks - -============= -Usage example -============= - -First, allocate the info struct: - - info = fpga_image_info_alloc(dev); - if (!info) - return -ENOMEM; - -Set flags as needed, i.e. - - info->flags |= FPGA_MGR_PARTIAL_RECONFIG; - -Point to your FPGA image, such as: - - info->sgt = &sgt; - -Add info to region and do the programming: - - region->info = info; - ret = fpga_region_program_fpga(region); - -Then enumerate whatever hardware has appeared in the FPGA. - --- -[1] ../devicetree/bindings/fpga/fpga-region.txt -[2] ./fpga-mgr.txt -[3] ../../drivers/fpga/of-fpga-region.c -- cgit v1.2.3