Received: by 2002:a05:6a10:a852:0:0:0:0 with SMTP id d18csp1674471pxy; Thu, 6 May 2021 12:59:25 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw4jBt4LveTPX6rh4T5C9DFX0z6SebAkPVzaIcb2Z9KpZcIV0isE0oRpT9OUdjdrGg3fFgm X-Received: by 2002:a62:3787:0:b029:25a:d5da:27a9 with SMTP id e129-20020a6237870000b029025ad5da27a9mr6636038pfa.81.1620331165721; Thu, 06 May 2021 12:59:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1620331165; cv=none; d=google.com; s=arc-20160816; b=E/7Dp9Va48mwu2GpW3y6qDiZ6rYcdwR/+SG8Mk/fHN6yk2t+um67kh4Y7hQyNUayRV lqoNnWgxNyIA07gorqlK+HSijW0wq6S0gc8EewbP5oABVtlr3Zc4fHVrnveTuu6qNEFV yyLyf/cQzisCD6nwejor3b+J0s+mWVlTxiRMJr7rR4kL/gn+9z6eVJKr66GFw8ROeEVc GfEZkIwqOYw5ccr7Im2o4OzZlZiXroJK1KOBPbSfDfWHGglH0b8HCLg210DvQAdbhSLo xyyuZ20RUvotT2m53JXZ2s0qJF/Q4gs7adKWSOJPclFJNAKT8SeATtbpuNZVTy2/TKV7 7Erw== 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:cc:to:from :dkim-signature; bh=Qre2cxW/qPaINYaX2pXLttHC55Q98kYeS5PJg5R0I7E=; b=IWPEn7hypTRnAI+4NQzfyRlYFXngbiI4ZNahyPz6vKjkzYiumpUJuTg7g5UVF00sfX Q9VDllVUEvVC1MlSMcDroFgrNaNQuw75up42UzfEV2331JGBD+2WNiK2W0MNe32jk4ph MEu9UMrS+ltkwIBXVXJ+xMkgar2PZBiiKPIVK4QM7MojoqHNA9TTCRIAUX/HHKijY/Cy PedWXtkNM715K1fuVm57DiW5d1RMgJKT715+4ursshln8FiXhxsyw51iUAyIOYFSBohs t+z9V/uKvGGjieDPgn2ynGbYhcKoFgu3f2vzv3RGZbWBciNFtwFwbZZ5JDt/5ndP3n/r hg5A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=H3IEfePs; 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 cm16si4267364pjb.128.2021.05.06.12.59.13; Thu, 06 May 2021 12:59:25 -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=H3IEfePs; 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 S235029AbhEFTUF (ORCPT + 99 others); Thu, 6 May 2021 15:20:05 -0400 Received: from fllv0015.ext.ti.com ([198.47.19.141]:54868 "EHLO fllv0015.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235448AbhEFTT4 (ORCPT ); Thu, 6 May 2021 15:19:56 -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 146JIoJc080712; Thu, 6 May 2021 14:18:50 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1620328730; bh=Qre2cxW/qPaINYaX2pXLttHC55Q98kYeS5PJg5R0I7E=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=H3IEfePsq9U2n/1+gEs0wa6wQm0l8EnmgBr62hCtKxHK6Pnm9uiKZMRwEsG2VkqWB 2GvtvHuYkb47SgcXlr7ftlL3djux7EEBrAgvFN/O4zhHFySIRVxO+yPcbbKh/bIzuB WRhQ9sG3yCvy5Cwl2Z5saFGlNGXXaYbcttFUW1II= Received: from DFLE100.ent.ti.com (dfle100.ent.ti.com [10.64.6.21]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 146JIopp122924 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 6 May 2021 14:18:50 -0500 Received: from DFLE110.ent.ti.com (10.64.6.31) by DFLE100.ent.ti.com (10.64.6.21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2176.2; Thu, 6 May 2021 14:18:50 -0500 Received: from lelv0326.itg.ti.com (10.180.67.84) by DFLE110.ent.ti.com (10.64.6.31) 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; Thu, 6 May 2021 14:18:50 -0500 Received: from pratyush-OptiPlex-790.dhcp.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by lelv0326.itg.ti.com (8.15.2/8.15.2) with ESMTP id 146JIUNH026052; Thu, 6 May 2021 14:18:47 -0500 From: Pratyush Yadav To: Tudor Ambarus , Michael Walle , Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Mark Brown , , , CC: Pratyush Yadav Subject: [PATCH 5/6] mtd: spi-nor: core; avoid odd length/address reads on 8D-8D-8D mode Date: Fri, 7 May 2021 00:48:28 +0530 Message-ID: <20210506191829.8271-6-p.yadav@ti.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210506191829.8271-1-p.yadav@ti.com> References: <20210506191829.8271-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 --- drivers/mtd/spi-nor/core.c | 81 +++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 5cc206b8bbf3..3d66cc34af4d 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1904,6 +1904,82 @@ 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); + + if (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 +1997,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