Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp2811324pxj; Mon, 31 May 2021 11:22:24 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxcderqEik9rouVwZwqLMjx43ikIqYxDfOHcHCd4s0U62LEIbGs8bBZ+E2Zx8kfrt5+gsR6 X-Received: by 2002:a05:6402:1216:: with SMTP id c22mr6348730edw.36.1622485344402; Mon, 31 May 2021 11:22:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622485344; cv=none; d=google.com; s=arc-20160816; b=MC9cp5XDuzE/h/e6hU3eLiZCzTxvc+2rRNKRgt1VSIXgQpKykbkzo/M/6TOuSidweb cTZkX2cCHx3pOk58C5L/IC+SfjulK+jIhUro8klA/hea59UvsKa4LekcANOlXHKt3LDR DaGQloRaC7W5JYDStMORXdBi2J/RII3x/mb6R4WDSshinVfEWvrktk46iuvReSuBcF9z pO4o16ySP8ILRcSSkc5zJwMx5e/qid8UUKApevacwwekEuDPSQDYknjnIjI2qpvo+Hq1 vLRb42vEJlRmP2Gzjh1ld4CSLlUTHiXb+4EsRnYIyxKX6tI7hpi5RCZ2gXBD6Rs8rCap 9lgg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:to:from :dkim-signature; bh=Lbvml4LO8u8mq4+Jsg0QJUcjZqcDZe28EeBi6UXRwK4=; b=CQpnX+prX27eILLGZdJnE2XVd/KHnPaDKg2Fe5kiiWrVaKRVrukVO4KdKCngDEw5ok AEYhoyZPIFm/aJ9sP125IGNM338++gL9v4wgUJDowi8f4SF01pbQwBw68vglsXYlhpAZ h6JuuRVlNxXEJHb3oum9LlODqJCjFocr83QznMreBNq6CdTmR5JbISr7xD9YxgxYrcr+ yjo3XLySRbnQpGsvR3TdchC3S6QopT+YcoA+39eHdJpykE4BipTC7q8DTiTj1fm+wumh LcvRFmlJ6OJ5c7j90CI5GtRjdm5k2SfpOCG31NbjcBiX8HctJOP5Lm2+YJ9I9zNAYr0D 16yw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=T0eSUP4X; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id z3si5512839ejr.183.2021.05.31.11.22.02; Mon, 31 May 2021 11:22:24 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=T0eSUP4X; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232540AbhEaSUe (ORCPT + 99 others); Mon, 31 May 2021 14:20:34 -0400 Received: from fllv0015.ext.ti.com ([198.47.19.141]:59218 "EHLO fllv0015.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231594AbhEaSUE (ORCPT ); Mon, 31 May 2021 14:20:04 -0400 Received: from fllv0035.itg.ti.com ([10.64.41.0]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id 14VIII42078853; Mon, 31 May 2021 13:18:18 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1622485098; bh=Lbvml4LO8u8mq4+Jsg0QJUcjZqcDZe28EeBi6UXRwK4=; h=From:To:Subject:Date:In-Reply-To:References; b=T0eSUP4XQdt2We3MYdi4iGZvCClwsiw2TA0njJIv6Y3Qr59rxz4tcuHAAV0BARN1l 57lb8w7sZgpuW+/lTC1VzH0kHH/6zHXNPMMJtt0tCs4O+N4YI6smkhcpuzF/a78aAC 94k5kJGfgkakrzF9kYXnF0XYER7WzPyf4aeFxi/U= Received: from DLEE113.ent.ti.com (dlee113.ent.ti.com [157.170.170.24]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 14VIIIc9028535 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 31 May 2021 13:18:18 -0500 Received: from DLEE109.ent.ti.com (157.170.170.41) by DLEE113.ent.ti.com (157.170.170.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2176.2; Mon, 31 May 2021 13:18:17 -0500 Received: from fllv0039.itg.ti.com (10.64.41.19) by DLEE109.ent.ti.com (157.170.170.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2176.2 via Frontend Transport; Mon, 31 May 2021 13:18:17 -0500 Received: from pratyush-OptiPlex-790.dhcp.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by fllv0039.itg.ti.com (8.15.2/8.15.2) with ESMTP id 14VIHwdK118543; Mon, 31 May 2021 13:18:15 -0500 From: Pratyush Yadav To: Tudor Ambarus , Michael Walle , Pratyush Yadav , Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Mark Brown , , , Subject: [PATCH v2 5/6] mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode Date: Mon, 31 May 2021 23:47:56 +0530 Message-ID: <20210531181757.19458-6-p.yadav@ti.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210531181757.19458-1-p.yadav@ti.com> References: <20210531181757.19458-1-p.yadav@ti.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Octal DTR capable flashes like Micron Xcella reads cannot start or end at an odd address in Octal DTR mode. Extra bytes need to be read at the start or end to make sure both the start address and length remain even. To avoid allocating too much extra memory, thereby putting unnecessary memory pressure on the system, the temporary buffer containing the extra padding bytes is capped at PAGE_SIZE bytes. The rest of the 2-byte aligned part should be read directly in the main buffer. Signed-off-by: Pratyush Yadav Reviewed-by: Michael Walle --- Changes in v2: - Replace semicolon in subject with colon. - Add a comment that ret < 0 after adjusting for extra bytes is not possible, and add a WARN_ON() on the condition to make sure it gets spotted quickly when some change triggers this bug. - Add Michael's R-by. drivers/mtd/spi-nor/core.c | 82 +++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index d521ca577884..a696af6a1b71 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1904,6 +1904,83 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) return ERR_PTR(-ENODEV); } +/* + * On Octal DTR capable flashes like Micron Xcella reads cannot start or + * end at an odd address in Octal DTR mode. Extra bytes need to be read + * at the start or end to make sure both the start address and length + * remain even. + */ +static int spi_nor_octal_dtr_read(struct spi_nor *nor, loff_t from, size_t len, + u_char *buf) +{ + u_char *tmp_buf; + size_t tmp_len; + loff_t start, end; + int ret, bytes_read; + + if (IS_ALIGNED(from, 2) && IS_ALIGNED(len, 2)) + return spi_nor_read_data(nor, from, len, buf); + else if (IS_ALIGNED(from, 2) && len > PAGE_SIZE) + return spi_nor_read_data(nor, from, round_down(len, PAGE_SIZE), + buf); + + tmp_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!tmp_buf) + return -ENOMEM; + + start = round_down(from, 2); + end = round_up(from + len, 2); + + /* + * Avoid allocating too much memory. The requested read length might be + * quite large. Allocating a buffer just as large (slightly bigger, in + * fact) would put unnecessary memory pressure on the system. + * + * For example if the read is from 3 to 1M, then this will read from 2 + * to 4098. The reads from 4098 to 1M will then not need a temporary + * buffer so they can proceed as normal. + */ + tmp_len = min_t(size_t, end - start, PAGE_SIZE); + + ret = spi_nor_read_data(nor, start, tmp_len, tmp_buf); + if (ret == 0) { + ret = -EIO; + goto out; + } + if (ret < 0) + goto out; + + /* + * More bytes are read than actually requested, but that number can't be + * reported to the calling function or it will confuse its calculations. + * Calculate how many of the _requested_ bytes were read. + */ + bytes_read = ret; + + if (from != start) + ret -= from - start; + + /* + * Only account for extra bytes at the end if they were actually read. + * For example, if the total length was truncated because of temporary + * buffer size limit then the adjustment for the extra bytes at the end + * is not needed. + */ + if (start + bytes_read == end) + ret -= end - (from + len); + + /* Should not be possible. */ + if (WARN_ON(ret < 0)) { + ret = -EIO; + goto out; + } + + memcpy(buf, tmp_buf + (from - start), ret); +out: + kfree(tmp_buf); + return ret; +} + static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -1921,7 +1998,10 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, addr = spi_nor_convert_addr(nor, addr); - ret = spi_nor_read_data(nor, addr, len, buf); + if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) + ret = spi_nor_octal_dtr_read(nor, addr, len, buf); + else + ret = spi_nor_read_data(nor, addr, len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; -- 2.30.0