[PATCH] map-ram chip driver: 16-bit block transfer

Sanjay Tandel sanjay.tandel at rockwellcollins.com
Fri Aug 11 09:50:37 PDT 2017


Hi Boris,

On Wed, Aug 9, 2017 at 1:10 PM, Boris Brezillon
<boris.brezillon at free-electrons.com> wrote:
> +Arnd for the memcpy_to/fromio aspects.
>
> Hi Matt,
>
> Subject should be something like "mtd: map: support 16-bit block
> transfers"
>
> Le Fri,  4 Aug 2017 08:02:20 -0500,
> Matt Weber <matthew.weber at rockwellcollins.com> a écrit :
>
>> From: sgtandel <sanjay.tandel at rockwellcollins.com>
>>
>> This patch adds 16-bit I/O memory write function (map_copy_to16) in map-ram
>> driver. map-ram driver's block write function(i.e map_copy_to) uses
>> memcpy_toio() function for block transfer. memcpy_toio() is limited to do
>> single byte write, irrespective of bankwidth.
>
> That's not true. Depending on the platform (+ config options)
> memcpy_to/fromio() can be a simple redirection to memcpy, and
> memcpy is likely to be optimized to do 32bit or 64bit accesses when
> possible (IOW, when alignment allows it).
>
Agree with you on memcpy_toio/_fromio.
but map-ram driver's map_copy_to/map_copy_from aren't based on bank-width
provided for specific chip.It relies on memcpy_toio, which is dependent on arch,
alignment and size.For example - like in our case of accessing 16-bit
flash, despite
of chip's bank-width being 16-bit, map_copy_to ends up accessing 8-bit using
memcpy_toio, because memcpy_toio for ARM arch always does 8-bit accesses.

Single entity read/write function (like map_read/map_write), on the other hand,
seems to be doing that correctly by checking the bank-width.

>> Therefore,
>> added map_copy_to16() function to be used by map-ram driver for block
>> transfers for chips that only supports word(16-bit) transfers. map-ram
>> driver's single entity read/write functions (such as map_read and
>> map_write) use bankwidth property(provided by DTS entry) and calls
>> appropriate readb/readw/readq function. For block write, there was no such
>> implementation found in map-ram driver. So map_copy_to() calls memcpy_toio
>> (which in turn calls writeb) for all block write, irrespective of
>> bankwidth.
>
> You're kind of repeating what was said above.
>

agree. lot of repeating!

>> So wrong or corrupted data might be written into flash memory in
>> case chips that does not support 8-bit write.
>
> It's likely to be arch and buffer alignment dependent (see my
> explanation about memcpy_to/fromio() being a simple redirection to
> memcpy on some architectures).
>

That's correct and calling memcpy_toio (and not checking chip's bank-width)
could lead to corrupt data.

>> This patch adds a condition
>> in block write function (map_copy_to) to call map_copy_to16(), if bankwidth
>> is 2. This patch also adds map_copy_from16() function to be used for 16-bit
>> block read operation. map-ram driver's block read function
>> (i.e map_copy_from) uses memcpy_fromio() function for all block read,
>> irrespective of bankwidth. memcpy_fromio is limited to do single byte read.
>> Therefore, Added map_copy_from16() function to be used by map-ram driver
>> for block read for chips that only supports word(16-bit) transfers.
>> map-ram driver's single entity read/write functions (such as map_read and
>> map_write) already use bankwidth property(provided by DTS entry) and calls
>> appropriate readb/readw/readq function. For block read, there was no such
>> implementation found in map-ram driver. So map_copy_from() calls
>> memcpy_fromio() (which in turn calls writeb) for all block write,
>> irrespective of bankwidth. This patch adds a condition in block read
>> function (i.e map_copy_from) to call map_copy_from16(), if bankwidth is 2.
>
> Come on! You repeat the same thing again but for the other direction.
> I'm sure you can shrink the commit message and make it clearer.
>
> Also, while you're at it, can you please re-format the commit message
> to make it readable. Right now it's a huge block of text without any
> blank line or line break.
>

How about below description? :)

"Unlike single entity access functions(map_read/map_write) in map-ram,
block access functions (map_copy_to/map_copy_from) aren't based on
bank-width provided for specific chip. It relies on memcpy_toio, which is
dependent on arch, buffer size and alignment.

So add support for block access based on bank-width."


>>
>> Signed-off-by: Sanjay Tandel <sanjay.tandel at rockwellcollins.com>
>> Signed-off-by: Matt Weber <matthew.weber at rockwellcollins.com>
>> ---
>>  include/linux/mtd/map.h | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 61 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
>> index 3aa56e3..3d7a296 100644
>> --- a/include/linux/mtd/map.h
>> +++ b/include/linux/mtd/map.h
>> @@ -449,17 +449,77 @@ static inline void inline_map_write(struct map_info *map, const map_word datum,
>>       mb();
>>  }
>>
>> +static void map_copy_from16(void *to, void __iomem *from, size_t count)
>
> You're in a source header and you define a function. If 2 source files
> include the same header you'll face a duplicate symbol at link time.
> This function should be inlined.
>

Okay. I will fix this.

>> +{
>> +     const unsigned char *t = to;
>> +
>> +     if (!(IS_ALIGNED((u32)from, sizeof(u16)))) {
>> +             from = (void __iomem *)ALIGN((u32)from, sizeof(u16))
>> +                                                     - sizeof(u16);
>> +             *(u8 *)t = (u8)((readw(from) & 0xff00) >> 8);
>> +             count--;
>> +             t++;
>> +             from += 2;
>> +     }
>> +     while (count >= 2) {
>> +             *(u16 *)t = readw(from);
>> +             count -= 2;
>> +             t += 2;
>> +             from += 2;
>> +     };
>> +     while (count > 0) {
>> +             *(u8 *)t = (u8)(readw(from) & 0x00ff);
>> +             count--;
>> +             t++;
>> +             from++;
>> +     }
>> +}
>> +
>>  static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
>>  {
>>       if (map->cached)
>>               memcpy(to, (char *)map->cached + from, len);
>> +     else if (map_bankwidth_is_2(map))
>> +             map_copy_from16(to, map->virt + from, len);
>>       else
>>               memcpy_fromio(to, map->virt + from, len);
>
> We're likely to face the same problem with map_bankwidth_is_4()
> (AKA 32bit busses), right? Why not patching the code to handler this
> case?
>
> BTW, I'm not sure what kind of guarantees are provided by
> memcpy_to/fromio(), but I'd expect them to optimize things when they
> can, so they might use 32bit or 64bit accesses when alignment
> authorizes it. Will that work correctly even on 8bit chips?
>

32-bit access for 8-bit chip may not work. I am working for 32-bit and
8-bit accesses based on bank-width.

>>  }
>>
>> +static void map_copy_to16(void __iomem *to, const void *from, size_t count)
>
> Ditto -> static inline void
>

agree.

>
>> +{
>> +     const unsigned char *f = from;
>> +     u16 d;
>> +
>> +     if (!(IS_ALIGNED((u32)to, sizeof(u16)))) {
>> +             to = (void __iomem *)ALIGN((u32)to, sizeof(u16))
>> +                                                     - sizeof(u16);
>> +             d = (readw(to) & 0x00ff) | ((u16)(*(const u8 *)f) << 8);
>> +             writew(d, to);
>> +             count--;
>> +             to += 2;
>> +             f++;
>> +     }
>> +     while (count >= 2) {
>> +             writew(*(const u16 *)f, to);
>> +             count -= 2;
>> +             to += 2;
>> +             f += 2;
>> +     };
>> +     while (count > 0) {
>> +             d = (readw(to) & 0xff00) | (u16)(*(const u8 *)f);
>> +             writew(d, to);
>> +             count--;
>> +             to++;
>> +             f++;
>> +     }
>> +}
>> +
>>  static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
>>  {
>> -     memcpy_toio(map->virt + to, from, len);
>> +     if (map_bankwidth_is_2(map))
>> +             map_copy_to16(map->virt + to, from, len);
>> +     else
>> +             memcpy_toio(map->virt + to, from, len);
>>  }
>>
>>  #ifdef CONFIG_MTD_COMPLEX_MAPPINGS
>


Thanks,
Sanjay



More information about the linux-mtd mailing list