Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp703795imm; Wed, 23 May 2018 04:19:11 -0700 (PDT) X-Google-Smtp-Source: AB8JxZp38hIWn68Bft3jThDKGWa3YuHQ/yKEqhtRhLrGKsGNjhrQM7wYb4P9l3eDAkABXAgL1/tb X-Received: by 2002:a17:902:9689:: with SMTP id n9-v6mr2461344plp.363.1527074351802; Wed, 23 May 2018 04:19:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527074351; cv=none; d=google.com; s=arc-20160816; b=uE1R9qvhJw4+eLLg78OiDf5iSumXgYrr3DDQc8f5113Ie97HFv3imTrpgrT/+byXIy S0pEmcELkGPaE2cwMSw/YT9hIUeaFyVCwyFDMI92qKdH1gL3LVcpUFLRcqzAzb3E1HyP 6c421MzrPrfsweQgDw828ufrW+2G1hXbRM49m4pN4mQaGuemjHIRms8fiMEs64xSNBd4 RSMcYG1gMzSWTdKazofUT9ZVL85dJOwAdSFAeBzo0Xq9PdKta/8sGPaz56PyyZFgO0sD 2mj/IjFqvjcqq5WPn9Wpvy99dRMI9CoNdSGrNb/calTko9CBZy1lBIf2FzPjx8wLYL8i 3YBQ== 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=VMDTjFn++Jk8Z1oXbDRce1d3inPfK+02B/IwhAIsSjY=; b=on0+uvfroSVKfG0iLH+nCY7w8px4BTsV2NSNBkz+UQgnPnzVvXtb7zD7RjPLSEJLGX f8OdjIMbYA5uf9mPakGlEdkRh/MnZKf/uTAPWyDD66731NcrGdOwd70LkcMneDxqXZ2D fuq+giyBqmmCHpGbBKZHhlMqwFpuxhV8HmY+K5P2dCnB5N96D8RweBXRCQ2Se4gYr0Ee yDxs3uQ1XLaOC5kYobhbkYl3XkLKW2//uN6I1wiYNwyvIhW6PkPwiBxZ4AHug6X4C9WM Dx6sbeJ2ngJacCgiTQAlWsLLqH/KgtuysGT2vPYVxLA9T36MmD7K6iGJxfpxSSPb5dbj s7tQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=GGRGiGtY; 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 i15-v6si19160234pfk.146.2018.05.23.04.18.56; Wed, 23 May 2018 04:19:11 -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=GGRGiGtY; 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 S932551AbeEWLOS (ORCPT + 99 others); Wed, 23 May 2018 07:14:18 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:39147 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932071AbeEWLOO (ORCPT ); Wed, 23 May 2018 07:14:14 -0400 Received: by mail-wr0-f195.google.com with SMTP id w18-v6so21985753wrn.6 for ; Wed, 23 May 2018 04:14:14 -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=VMDTjFn++Jk8Z1oXbDRce1d3inPfK+02B/IwhAIsSjY=; b=GGRGiGtYM+b2xWBKzZYmep7zMaW8PnDbXddCeoeW3S0Fm//SEYfqesJmdyZ+7AbZYm 4jjXWUntjh+2LtTjJYNl6JG1dkC1jqtddErDCWRX9RXzc4XiAPsKeS7zn7dxvC8vi9Wv 4ZEmZ/HOx4YxQpv8SRR31HgkXYhWk2NZhM0dfJmGRjmpF7rZmynKhEmnKcDgw5bZWoAV wp76vY1izpmk6L2CfU9Pd931oUjxJ7HEjNMXiUd0gRMcHdxU2JF65hPdP/bZu0xna6l8 eO9P0LMnciJ36xNN8pnxqDtYmIxYGsy8tKNviqfol2J5ynOlQi0ByiKfsD/LMomHJzGl 9uuw== 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=VMDTjFn++Jk8Z1oXbDRce1d3inPfK+02B/IwhAIsSjY=; b=Y+SP62IUjQyM3vjwes1cGf4kexlo2T7Hz55SxlQvCM7KcvK8wfw5xZSND+LmzlPYKM 8WzVamHncVELpTS4GPDzidcoXtU70PpJJJKQWaTyxjbh02WAAwVW4j45PUIqFusfmc4d V2DzVdN0TVdF0hsGzptDuW3QXGCVot3WkwRUfY7U93Tp62Yop0kf9yHoEu8KMiit4rvZ +VMh5f46U3g9nIYRsPdRQEpcXYZ/tkqVo/hkjLyLTYylVfhvX8uz0Z86KNrvnQZdnkNR 4TDVam5OPyz0IlN0GfeP8q3MxeitKuXIEeTM/Kak6J6XVIOCokJQKGtfVDjgBbuN/4Ad vzCA== X-Gm-Message-State: ALKqPweif1Fjwyi19p2kQMedDVW/AWNRICh50F3mlhJQR5MLhZ5EVRU5 5vgZ59mj2ZUYfkSGRZWw0Lk= X-Received: by 2002:adf:a58a:: with SMTP id g10-v6mr2205398wrc.233.1527074053256; Wed, 23 May 2018 04:14:13 -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 z8-v6sm20025030wrl.62.2018.05.23.04.14.11 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 23 May 2018 04:14:12 -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> <123e50da-e49e-f876-bdb4-2719f7f7640a@microchip.com> From: Marek Vasut Message-ID: Date: Wed, 23 May 2018 11:56:57 +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: <123e50da-e49e-f876-bdb4-2719f7f7640a@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/22/2018 07:01 AM, Tudor Ambarus wrote: > Hi, Marek, Hi! > On 05/21/2018 07:59 PM, Marek Vasut wrote: >> 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. >> > > I'm looking for the 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 your example, 4k erase type will be used until > reaching the 64k offset, then a 64k erase type, then a 4k type. That's good! >> [...] >> >>>>> +    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 ? > > It will be great if we can do this without having performance penalties. > Can we loose the conditions for the last erase command? If one wants to > erase 80k chunk starting from offset 0 and only 32k and 64k erase type > are supported, can we erase 96k? No. But can you maybe build a list of erase commands to be executed once you validate that the erase can be performed for example ? -- Best regards, Marek Vasut