From patchwork Wed Nov 9 22:58:16 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gunthorpe X-Patchwork-Id: 9420291 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8B6DE601C2 for ; Wed, 9 Nov 2016 23:00:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7D49D29309 for ; Wed, 9 Nov 2016 23:00:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 72056293A6; Wed, 9 Nov 2016 23:00:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D9DC52935C for ; Wed, 9 Nov 2016 23:00:43 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1c4bpo-00015Y-JX; Wed, 09 Nov 2016 22:59:12 +0000 Received: from quartz.orcorp.ca ([184.70.90.242]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1c4bpl-00012O-8h for linux-arm-kernel@lists.infradead.org; Wed, 09 Nov 2016 22:59:10 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=obsidianresearch.com; s=rsa1; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=Lglgqz3C2sAHprJoeHjnj3RstiWkOBGvZdh3cB/RB6o=; b=FzxhMPsY1KaWNnNgXZ9FcboCF1W3iyTgNxbqwrSUS4Pvx2INVVMK7ox2I/820igPVC5OO0X5QgIVGx4YtrMovUZ8Z+QLi4KEVFaMOhmGDf17y9wYsO/K//DL3VKT5BMC2kNlQPc0kBX1jce/66xxEaCvXFzrSVq1T1agynamC3Y=; Received: from [10.0.0.151] (helo=jggl.edm.orcorp.ca) by quartz.orcorp.ca with esmtps (TLS1.2:ECDHE_RSA_AES_128_CBC_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1c4bpG-00011i-Bi; Wed, 09 Nov 2016 15:58:38 -0700 From: Jason Gunthorpe To: Alan Tull , Moritz Fischer Subject: [PATCH fpga 2/9] fpga zynq: Check the bitstream for validity Date: Wed, 9 Nov 2016 15:58:16 -0700 Message-Id: <1478732303-13718-3-git-send-email-jgunthorpe@obsidianresearch.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1478732303-13718-1-git-send-email-jgunthorpe@obsidianresearch.com> References: <1478732303-13718-1-git-send-email-jgunthorpe@obsidianresearch.com> X-Broken-Reverse-DNS: no host name found for IP address 10.0.0.151 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161109_145909_461072_69BCCA46 X-CRM114-Status: GOOD ( 15.21 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mike Looijmans , =?UTF-8?q?S=C3=B6ren=20Brinkmann?= , Matthias Brugger , Michal Simek , linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- drivers/fpga/zynq-fpga.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index e72340ea7323..86f4377e2b52 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 -= 4) + 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,28 @@ 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) { + dev_err(priv->dev, + "Invalid bitstream size, must be multiples of 4 bytes\n"); + 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)) { + dev_err(priv->dev, + "Invalid bitstream, could not find a sync word. Bitstream must be a byte swaped .bin file\n"); + err = -EINVAL; + goto out_err; + } + /* assert AXI interface resets */ regmap_write(priv->slcr, SLCR_FPGA_RST_CTRL_OFFSET, FPGA_RST_ALL_MASK); @@ -287,12 +316,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 +344,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 +360,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; }