Received: by 10.213.65.68 with SMTP id h4csp1419576imn; Mon, 26 Mar 2018 07:12:41 -0700 (PDT) X-Google-Smtp-Source: AG47ELtxbAcVr80qWh8NjsYhVXJNtSmfxQq2Dc8eeNXaObCWueLEKJ+Zni65McavNdhTLKfIZcg5 X-Received: by 2002:a17:902:57d2:: with SMTP id g18-v6mr28629291plj.381.1522073561676; Mon, 26 Mar 2018 07:12:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522073561; cv=none; d=google.com; s=arc-20160816; b=mSK3f2nKYliVBuf3wISx60ffXFpcAfNy8qg65nVh8IIGKpoW9PuuW7JVvSMhs5R7+M iLnMwF62eWI8G7q8tsp1YbyooPtbHEA0VDa9ATrIq8N8oDb+iC9QtaoLUiGrbdw2r0Dv 8aUfZo4yiH3R4BZo/NH6tvcviXUWWDFctfWWDABxB4Aj5VN1UqvBOm2PrxNY8+z5CgSc 7dFbYX/BOaXegKwl72lQ8gU3P9alnzWd3ZiOcxx6iWOF4H8pXxE9/xt2okcmPnPs4aY/ KMcLNqJpHQ38BKt2B8ORhCMC2Bu6QhkdEe+D1Jnh7J+qoEjdCJkNIHqGhyqMEGZVKCxX 3/6g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=sOhd1urCXlAmHtpm+/xfVH3jVPUGwXIYYeIyfFbi40g=; b=StFsP4LKQwp5W/VAs8eVUlCZ4EJNbkAVqeoQAvV0qhGrpDyq4/CtmqjQuNdXDaX0lp DdBUxzhre3rHMu/ombunM07uYZHuxjBQ5+CbHp4N5fI58isfFv56RvrGytrdfeEbV8d5 MWKKiKzyaIa4r8C35nHZNSY+eX+piMu0lryp388NlR81G5crtZjmfLfWlxGtz9LjYECc Z1zHgF6JGCijI7reRoNqx+C+UoPVs35P5w8lPe5NTQIF66LG+Qu99AOGceZmyX68hz8H ErA3sFEjNy2z4sH7HDMjJvJuM27azdynQvDXmVw+uiXNRuEpaGqfs6jElQY3UTE1EAvT a0IQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z69si11675281pfk.321.2018.03.26.07.12.26; Mon, 26 Mar 2018 07:12:41 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752048AbeCZOJh (ORCPT + 99 others); Mon, 26 Mar 2018 10:09:37 -0400 Received: from mga17.intel.com ([192.55.52.151]:54092 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751024AbeCZOJf (ORCPT ); Mon, 26 Mar 2018 10:09:35 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Mar 2018 07:09:34 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.48,364,1517904000"; d="scan'208";a="36905996" Received: from tthayer-hp-z620-workstation.an.intel.com ([10.122.105.144]) by FMSMGA003.fm.intel.com with ESMTP; 26 Mar 2018 07:09:33 -0700 From: thor.thayer@linux.intel.com To: cyrille.pitchen@wedev4u.fr, marek.vasut@gmail.com, dwmw2@infradead.org, computersforpeace@gmail.com, boris.brezillon@bootlin.com, richard@nod.at Cc: linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org, thor.thayer@linux.intel.com Subject: [PATCHv2] mtd: spi-nor: Fix Cadence QSPI page fault kernel panic Date: Mon, 26 Mar 2018 09:12:17 -0500 Message-Id: <1522073537-27386-1-git-send-email-thor.thayer@linux.intel.com> X-Mailer: git-send-email 2.7.4 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Thor Thayer The current Cadence QSPI driver caused a kernel panic when loading a Root Filesystem from QSPI. The problem was caused by reading more bytes than needed because the QSPI operated on 4 bytes at a time. [ 7.947754] spi_nor_read[1048]:from 0x037cad74, len 1 [bfe07fff] [ 7.956247] cqspi_read[910]:offset 0x58502516, buffer=bfe07fff [ 7.956247] [ 7.966046] Unable to handle kernel paging request at virtual address bfe08002 [ 7.973239] pgd = eebfc000 [ 7.975931] [bfe08002] *pgd=2fffb811, *pte=00000000, *ppte=00000000 Notice above how only 1 byte needed to be read but by reading 4 bytes into the end of a mapped page, an unrecoverable page fault occurred. This patch uses a temporary buffer to hold the 4 bytes read and then copies only the bytes required into the buffer. A min() function is used to limit the length to prevent buffer overflows. Request testing of this patch on other platforms. This was tested on the Intel Arria10 SoCFPGA DevKit. Signed-off-by: Thor Thayer --- v2 Changes to only write dangling bytes at end of transfer since previous patch may have multiple dangling byte transfers. Remove write patch since no errors reported and write timeout needs more investigation. --- drivers/mtd/spi-nor/cadence-quadspi.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index 4b8e9183489a..5872f31eaa60 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -501,7 +501,9 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, u8 *rxbuf, void __iomem *reg_base = cqspi->iobase; void __iomem *ahb_base = cqspi->ahb_base; unsigned int remaining = n_rx; + unsigned int mod_bytes = n_rx % 4; unsigned int bytes_to_read = 0; + u8 *rxbuf_end = rxbuf + n_rx; int ret = 0; writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR); @@ -530,11 +532,24 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, u8 *rxbuf, } while (bytes_to_read != 0) { + unsigned int word_remain = round_down(remaining, 4); + bytes_to_read *= cqspi->fifo_width; bytes_to_read = bytes_to_read > remaining ? remaining : bytes_to_read; - ioread32_rep(ahb_base, rxbuf, - DIV_ROUND_UP(bytes_to_read, 4)); + bytes_to_read = round_down(bytes_to_read, 4); + /* Read 4 byte word chunks then single bytes */ + if (bytes_to_read) { + ioread32_rep(ahb_base, rxbuf, + (bytes_to_read / 4)); + } else if (!word_remain && mod_bytes) { + unsigned int temp = ioread32(ahb_base); + + bytes_to_read = mod_bytes; + memcpy(rxbuf, &temp, min((unsigned int) + (rxbuf_end - rxbuf), + bytes_to_read)); + } rxbuf += bytes_to_read; remaining -= bytes_to_read; bytes_to_read = cqspi_get_rd_sram_level(cqspi); -- 2.7.4