Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp769406imm; Mon, 21 May 2018 14:05:42 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpJ9MWsCZUd4gLZX74MDjEZdLp0Q1cDERqqu+K7r2K96lHi1w/2LQnZIvuyPHoKksRHxbeb X-Received: by 2002:a65:5946:: with SMTP id g6-v6mr16713168pgu.391.1526936742449; Mon, 21 May 2018 14:05:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526936742; cv=none; d=google.com; s=arc-20160816; b=gWSrXJlZ0St0hIc0pLHgXnjKbqzdaCXw38b4Ug597dj8TIESv9wCMiUUKmhCXBekkW 6ap7WQuWM+otE2cbUYF+YQtc4UCxOa/tjWOZ7hNVwD/IO2vI4xbtxCK4rDwqo+62B9HD azTwT9f8F3uRQB/hUN/jQUQD5l1LfivCiu4ox/LVczXa5qIaOZVKmhs1qOfGbxQkXYVs 8JKxGEiQQAZ0lGJpaVu80tGg5/1uMIu5lhF45UQYVkXLNLgHr9pGh3nOJKkcfYU56bA1 G/Y1S343kDoM8n0CW4Bd0HMYX7jUfkae/R5tppPxli0cNdjmIsM0mMhVHB1WdL6lBYDG 5Tlg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject:dkim-signature :arc-authentication-results; bh=lNnDfNrMz2gCtdJNKeqfQOCyL1tsP/jh6nVqJifvzsQ=; b=B0PKaJ7J2n+Skj3r54L224gPmUuPI3Z7uXElp3Cl3fLMG6LqDEapMA8qwULurN3Mhc HeX07wycx1l+TL3H//wLbTzCBMjZEXVzSj3bMW3fwUyX7M3AlSjLQCbei0YiPmRWW9IG HjKFFymz32dOly32yCBDclL62CUqvG2jgg6tv9yL3Ibyw+sCTnXiXUZX3Wd0GjI801qw IOUwZmJSjMNtouHa9GwlgHoX3kzYIJdGLVaojMG6N9oPbycvTZUHYVOvK36YcJmakGn/ 715B1PNtobw4WTW6wujQXRvgtkt58LC1ZARwITMPpHuyWwLpN9pkaNJSToRSeusUpur2 PyKQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=rhj0qCxa; 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; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id x17-v6si15125964pfh.354.2018.05.21.14.05.27; Mon, 21 May 2018 14:05:42 -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; dkim=pass header.i=@gmail.com header.s=20161025 header.b=rhj0qCxa; 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; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752096AbeEUVEx (ORCPT + 99 others); Mon, 21 May 2018 17:04:53 -0400 Received: from mail-wr0-f194.google.com ([209.85.128.194]:32990 "EHLO mail-wr0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751276AbeEUVEt (ORCPT ); Mon, 21 May 2018 17:04:49 -0400 Received: by mail-wr0-f194.google.com with SMTP id a15-v6so10024278wrm.0 for ; Mon, 21 May 2018 14:04:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=lNnDfNrMz2gCtdJNKeqfQOCyL1tsP/jh6nVqJifvzsQ=; b=rhj0qCxazEDMJ65PHC6l0hhs3gNzixMGeJoBiitQaBfCrC57gPAmUGW7Jil0FzzXnN 0/tZNhJKs7I4mB70HFHBPnz4eOtzXojYwWSqThUtwnsb8fppPZ9Xdvtz/DBqZQI9qXwY asi9+vLlygJsqj4fsndX9HcdEn3NGjmxQPybIg+qc395VLg1UW2fIRaZlbBvRbVpHMCh UqhpcxdnsqKHUWNqCCodpBdy4mGmPlTR5OuBjvqUq/UIoHlKtsB19WJh3HTt/8+ne4Lz HMrysuIOPWrBg2A0loGIWNcjW6TUvuVMk+8C4XG/8BNETKt4LTU9IORki68cWybvxhp/ T+Ug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=lNnDfNrMz2gCtdJNKeqfQOCyL1tsP/jh6nVqJifvzsQ=; b=FGXZl9BVL2EwN3cAbxqc+XMHBECEZr/IBGCnKa2KV1fgZU6nIDibbhtBGP8GEN4tv8 rFa17gEta+Sv9vE11At7lNPrbZE7UpDtWEZxvYTvK4BO5Tz0G3egp7K9qnMp/AA0rzaC aMnLMD0lNkGlnHNV60etdahK8UfM3FJReD+FT6e1oJAxgEcM63vN9AQc889+WMVORF/+ sPvOStrOdyyOc7kgMAJHowc+3MMroerZ65gvzzD3m5tLNYtVECH+Xl7g7zPyxH0dJVwD oNYa+Dq/sk/6V/mpQibGfxyj2xq7OU9+anlKNn0KzYfRiHqTHxURgCaRyZnOQG8U5UHt 8XJw== X-Gm-Message-State: ALKqPwdpYOeIwLKutSm4TgBoECI9fW/ChZSwj1v3iluL2ZkDLCOv+I6y 8J0eUukGMEtI3FKv4rG5BRo= X-Received: by 2002:adf:a805:: with SMTP id l5-v6mr15283420wrc.97.1526936688160; Mon, 21 May 2018 14:04:48 -0700 (PDT) Received: from [192.168.1.4] (ip-86-49-107-50.net.upcbroadband.cz. [86.49.107.50]) by smtp.gmail.com with ESMTPSA id k130-v6sm21895815wmg.15.2018.05.21.14.04.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 21 May 2018 14:04:47 -0700 (PDT) Subject: Re: [RFC PATCH] mtd: spi-nor: add support to non-uniform SPI NOR flash memories To: Tudor Ambarus , cyrille.pitchen@microchip.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, nicolas.ferre@microchip.com, Cristian.Birsan@microchip.com References: <20180518093233.24241-1-tudor.ambarus@microchip.com> <89d45190-95b0-b780-b219-e6c6adcb6147@gmail.com> <4cd7d47a-fd56-6b54-3b38-262adf46a97f@microchip.com> From: Marek Vasut Message-ID: Date: Mon, 21 May 2018 18:59:04 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <4cd7d47a-fd56-6b54-3b38-262adf46a97f@microchip.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 05/21/2018 06:42 PM, Tudor Ambarus wrote: > Hi, Marek, [...] >>> This is a transitional patch: non-uniform erase maps will be used later >>> when initialized based on the SFDP data. >> >> What about non-SFDP non-linear flashes ? > > Non-SFDP non-uniform flashes support is not addressed with this > proposal, I should have told this in the commit message, thanks. But we > are backward compatible, if non-SFDP, the flashes are considered > uniform. OK. btw wall-of-text description of patch isn't my fav thing. >>> Signed-off-by: Cyrille Pitchen >>> >>> [tudor.ambarus@microchip.com: >>> - add improvements on how the erase map is handled. The map is an array >>> describing the boundaries of the erase regions. LSB bits of the region's >>> offset are used to describe the supported erase types, to indicate if >>> that specific region is the last region in the map and to mark if the >>> region is overlaid or not. When one sends an addr and len to erase a >>> chunk of memory, we identify in which region the address fits, we start >>> erasing with the best fitted erase commands and when the region ends, >>> continue to erase from the next region. The erase is optimal: identify >>> the start offset (once), then erase with the best erase command, >>> move forward and repeat. >> >> Is that like an R-tree ? > > Not really. I find this RFC proposal faster and neat, but I'm open for > suggestions and guidance. > > One wants to erase a contiguous chunk of memory and sends us the > starting address and the total length. The algorithm of finding the best > sequence of erase commands can be summarized in four steps: > > 1. Find in which region the address fits. > This step is done only once, at the beginning. For the non-uniform > SFDP-defined flashes, usually there are two or three regions defined. > Nevertheless, in the worst case, the maximum number of regions that can > be defined is on eight bits, so 255. Linear search for just 255 elements > in the worst case looks good for me, especially that we do this search > once. > > 2. Find the *best* erase command that is defined in that region. > Each region can define maximum 4 erase commands. *Best* is defined as > the largest/biggest supported erase command with which the provided > address is aligned and which does not erase more that what the user has > asked for. In case of overlaid regions, alignment does not matter. The > largest command will erase the remaining of the overlaid region without > touching the region with which it overlaps (see S25FS512S). The > supported erase commands are ordered by size with the biggest queried > first. It is desirable to erase with large erase commands so that we > erase as much as we can in one shoot, minimizing the erase() calls. > > 3. Erase sector with the *best* erase command and move forward in a > linear fashion. > addr += cmd->size; > len -= cmd->size; > If the new address exceeds the end of this region, move to the next. > > 4. While (len) goto step2. > > That's all. Linearity is an advantage. We find the starting region and > then we traverse each region in order without other queries. > >> >>> - order erase types by size, with the biggest erase type at BIT(0). With >>> this, we can iterate from the biggest supported erase type to the >>> smallest, >>> and when find one that meets all the required conditions, break the >>> loop. >>> This saves time in determining the best erase cmd. >>> >>> - minimize the amount of erase() calls by using the best sequence of >>> erase >>> type commands depending on alignment. >> >> Nice, this was long overdue >> >>> - replace spi_nor_find_uniform_erase() with >>> spi_nor_select_uniform_erase(). >>> Even for the SPI NOR memories with non-uniform erase types, we can >>> determine >>> at init if there are erase types that can erase the entire memory. >>> Fill at >>> init the uniform_erase_type bitmask, to encode the erase type >>> commands that >>> can erase the entire memory. >>> >>> - clarify support for overlaid regions. Considering one of the erase >>> maps >>> of the S25FS512S memory: >>> Bottom: 8x 4KB sectors at bottom (only 4KB erase supported), >>>          1x overlaid 224KB sector at bottom (only 256KB erase >>> supported), >>>          255x 256KB sectors (only 256KB erase supported) >>> S25FS512S states that 'if a sector erase command is applied to a >>> 256KB range >>> that is overlaid by 4KB secors, the overlaid 4kB sectors are not >>> affected by >>> the erase'. When at init, the overlaid region size should be set to >>> region->size = erase_size - count; in order to not miss chunks of data >>> when traversing the regions. >>> >>> - backward compatibility test done on MX25L25673G. >>> >>> The 'erase with the best command, move forward and repeat' approach was >>> suggested by Cristian Birsan in a brainstorm session, so: >>> ] >>> Suggested-by: Cristian Birsan >>> Signed-off-by: Tudor Ambarus >>> --- >>>   drivers/mtd/spi-nor/spi-nor.c | 281 >>> +++++++++++++++++++++++++++++++++++++++--- >>>   include/linux/mtd/spi-nor.h   |  89 +++++++++++++ >>>   2 files changed, 356 insertions(+), 14 deletions(-) >>> >>> diff --git a/drivers/mtd/spi-nor/spi-nor.c >>> b/drivers/mtd/spi-nor/spi-nor.c >>> index 494b7a2..bb70664 100644 >>> --- a/drivers/mtd/spi-nor/spi-nor.c >>> +++ b/drivers/mtd/spi-nor/spi-nor.c >>> @@ -260,6 +260,17 @@ static void spi_nor_set_4byte_opcodes(struct >>> spi_nor *nor, >>>       nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode); >>>       nor->program_opcode = >>> spi_nor_convert_3to4_program(nor->program_opcode); >>>       nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode); >>> + >>> +    if (!spi_nor_has_uniform_erase(nor)) { >>> +        struct spi_nor_erase_map *map = &nor->erase_map; >>> +        struct spi_nor_erase_command *cmd; >>> +        int i; >>> + >>> +        for (i = 0; i < SNOR_CMD_ERASE_MAX; i++) { >>> +            cmd = &map->commands[i]; >>> +            cmd->opcode = spi_nor_convert_3to4_erase(cmd->opcode); >>> +        } >>> +    } >>>   } >>>     /* Enable/disable 4-byte addressing mode. */ >>> @@ -497,6 +508,131 @@ static int spi_nor_erase_sector(struct spi_nor >>> *nor, u32 addr) >>>       return nor->write_reg(nor, nor->erase_opcode, buf, >>> nor->addr_width); >>>   } >>>   +/* JEDEC JESD216B Standard imposes erase sizes to be power of 2. */ >>> +static inline u64 >>> +spi_nor_div_by_erase_size(const struct spi_nor_erase_command *cmd, >>> +              u64 dividend, u32 *remainder) >>> +{ >>> +    *remainder = (u32)dividend & cmd->size_mask; >>> +    return dividend >> cmd->size_shift; >>> +} >>> + >>> +static const struct spi_nor_erase_command * >>> +spi_nor_find_best_erase_cmd(const struct spi_nor_erase_map *map, >>> +                const struct spi_nor_erase_region *region, u64 addr, >>> +                u32 len) >>> +{ >>> +    const struct spi_nor_erase_command *cmd; >>> +    u32 rem; >>> +    int i; >>> +    u8 cmd_mask = region->offset & SNOR_CMD_ERASE_MASK; >>> + >>> +    /* >>> +     * Commands are ordered by size, with the biggest erase type at >>> +     * index 0. >>> +     */ >>> +    for (i = 0; i < SNOR_CMD_ERASE_MAX; i++) { >>> +        /* Does the erase region support the tested erase command? */ >>> +        if (!(cmd_mask & BIT(i))) >>> +            continue; >>> + >>> +        cmd = &map->commands[i]; >>> + >>> +        /* Don't erase more than what the user has asked for. */ >>> +        if (cmd->size > len) >>> +            continue; >> >> Are you sure checking for the full erase block length first and then >> checking if you can sub-erase the block is OK ? > > will respond in the next comment. > >> >>> +        if (!(region->offset & SNOR_OVERLAID_REGION)) { >>> +            /* 'addr' must be aligned to the erase size. */ >>> +            spi_nor_div_by_erase_size(cmd, addr, &rem); > > oh, I missed the if here, this should have been confusing. > if (rem) >     continue; > else >     return cmd; > The else case can be merged with the one from below. > > Returning to your previous question. I iterate from the biggest erase > command to the smallest, because bigger is preferred, it will minimize > the amount of erase() calls. The biggest erase command that doesn't > erase more that what the user has asked for, will do. If the region is > not-overlaid the address must also be aligned with the erase size. You can have a flash with 4k sectors which also supports 64k erase and try to erase ie. 128k at offset +4k. That means you need to first erase small chunks, then big chunk, then small chunks again. So I don't think you can start with large chunk to see if you can erase it, since on such a setup the erase will degrade to massive amount of 4k erase ops. [...] >>> +    while (len) { >>> +        cmd = spi_nor_find_best_erase_cmd(map, region, addr, len); >>> +        if (!cmd) >>> +            return -EINVAL; >> >> What would happen if you realize mid-way that you cannot erase some >> sector , do you end up with partial erase ? > > Is this possible? In non-overlaid regions, the address is aligned with > at least one of the erase commands, else -EINVAL. For overlaid regions > alignment doesn't matter. But yes, if this is possible, in this case, > this proposal will do a partial erase. Shouldn't we fail up front instead ? -- Best regards, Marek Vasut