[PATCH] fpga zynq: Check the bitstream for validity
Matthias Brugger
mbrugger at suse.com
Tue Nov 8 01:59:43 PST 2016
On 11/08/2016 01:46 AM, Jason Gunthorpe wrote:
> On Fri, Oct 28, 2016 at 05:09:26PM -0700, Moritz Fischer wrote:
>
>> That being said, I don't like the idea of the driver having to search
>> either...
>
> I think we are stuck with that, considering what Xilinx tools
> produce..
>
> Here is a v2, what do you think?
>
> From 93ffde371ca50809ba9b4cdca17051a050b0f92d Mon Sep 17 00:00:00 2001
> From: Jason Gunthorpe <jgunthorpe at obsidianresearch.com>
> Date: Wed, 26 Oct 2016 16:51:26 -0600
> Subject: [PATCH v2] fpga zynq: Check the bitstream for validity
>
> There is no sense in sending a bitstream we know will not work, and
> with the variety of options for bitstream generation in Xilinx tools
> it is not terribly clear or very well documented what the correct
> input should be, especially since auto-detection was removed from this
> driver.
>
> All Zynq full configuration bitstreams must start with the sync word in
> the correct byte order.
>
> Zynq is also only able to DMA dword quantities, so bitstreams must be
> a multiple of 4 bytes. This also fixes a DMA-past the end bug.
>
> Signed-off-by: Jason Gunthorpe <jgunthorpe at obsidianresearch.com>
> ---
> drivers/fpga/zynq-fpga.c | 35 ++++++++++++++++++++++++++---------
> 1 file changed, 26 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
> index c2fb4120bd62..de475a6a1882 100644
> --- a/drivers/fpga/zynq-fpga.c
> +++ b/drivers/fpga/zynq-fpga.c
> @@ -175,6 +175,19 @@ static irqreturn_t zynq_fpga_isr(int irq, void *data)
> return IRQ_HANDLED;
> }
>
> +/* Sanity check the proposed bitstream. It must start with the sync word in
> + * the correct byte order. The input is a Xilinx .bin file with every 32 bit
> + * quantity swapped.
> + */
> +static bool zynq_fpga_has_sync(const char *buf, size_t count)
> +{
> + for (; count > 4; buf += 4, --count)
> + if (buf[0] == 0x66 && buf[1] == 0x55 && buf[2] == 0x99 &&
> + buf[3] == 0xaa)
> + return true;
> + return false;
> +}
> +
> static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
> const char *buf, size_t count)
> {
> @@ -184,12 +197,23 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
>
> priv = mgr->priv;
>
> + /* The hardware can only DMA multiples of 4 bytes, and we need at
> + * least the sync word and something else to do anything.
> + */
> + if (count <= 4 || (count % 4) != 0)
> + return -EINVAL;
> +
> err = clk_enable(priv->clk);
> if (err)
> return err;
>
> /* don't globally reset PL if we're doing partial reconfig */
> if (!(flags & FPGA_MGR_PARTIAL_RECONFIG)) {
> + if (!zynq_fpga_has_sync(buf, count)) {
Maybe we should add an error message here to let the user know what went
wrong, as I think this error path could easily be hit by an user.
Regards,
Matthias
> + err = -EINVAL;
> + goto out_err;
> + }
> +
> /* assert AXI interface resets */
> regmap_write(priv->slcr, SLCR_FPGA_RST_CTRL_OFFSET,
> FPGA_RST_ALL_MASK);
> @@ -287,12 +311,9 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr,
> struct zynq_fpga_priv *priv;
> int err;
> char *kbuf;
> - size_t in_count;
> dma_addr_t dma_addr;
> - u32 transfer_length;
> u32 intr_status;
>
> - in_count = count;
> priv = mgr->priv;
>
> kbuf = dma_alloc_coherent(priv->dev, count, &dma_addr, GFP_KERNEL);
> @@ -318,11 +339,7 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr,
> */
> zynq_fpga_write(priv, DMA_SRC_ADDR_OFFSET, (u32)(dma_addr) + 1);
> zynq_fpga_write(priv, DMA_DST_ADDR_OFFSET, (u32)DMA_INVALID_ADDRESS);
> -
> - /* convert #bytes to #words */
> - transfer_length = (count + 3) / 4;
> -
> - zynq_fpga_write(priv, DMA_SRC_LEN_OFFSET, transfer_length);
> + zynq_fpga_write(priv, DMA_SRC_LEN_OFFSET, count / 4);
> zynq_fpga_write(priv, DMA_DEST_LEN_OFFSET, 0);
>
> wait_for_completion(&priv->dma_done);
> @@ -338,7 +355,7 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr,
> clk_disable(priv->clk);
>
> out_free:
> - dma_free_coherent(priv->dev, in_count, kbuf, dma_addr);
> + dma_free_coherent(priv->dev, count, kbuf, dma_addr);
>
> return err;
> }
>
More information about the linux-arm-kernel
mailing list