[PATCH V3] mtd: basic (read only) driver for BCMA serial flash

Rafał Miłecki zajec5 at gmail.com
Wed Sep 19 06:46:09 EDT 2012


2012/9/18 Jonas Gorski <jonas.gorski at gmail.com>:
> I know I'm a bit late, but ...
>
> On 17 September 2012 11:50, Rafał Miłecki <zajec5 at gmail.com> wrote:
>> (...)
>> diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
>> index a4dd1d8..395733a 100644
>> --- a/drivers/mtd/devices/Makefile
>> +++ b/drivers/mtd/devices/Makefile
>> @@ -19,5 +19,6 @@ obj-$(CONFIG_MTD_DATAFLASH)   += mtd_dataflash.o
>>  obj-$(CONFIG_MTD_M25P80)       += m25p80.o
>>  obj-$(CONFIG_MTD_SPEAR_SMI)    += spear_smi.o
>>  obj-$(CONFIG_MTD_SST25L)       += sst25l.o
>> +obj-$(CONFIG_MTD_BCM47XXSFLASH)        += bcm47xxsflash.o
>>
>>  CFLAGS_docg3.o                 += -I$(src)
>> \ No newline at end of file
>> diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c
>> new file mode 100644
>> index 0000000..f711a51
>> --- /dev/null
>> +++ b/drivers/mtd/devices/bcm47xxsflash.c
>> @@ -0,0 +1,131 @@
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/slab.h>
>> +#include <linux/mtd/mtd.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/bcma/bcma.h>
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
>> +
>> +static const char *probes[] = { "bcm47xxpart", NULL };
>> +
>> +static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
>> +                             size_t *retlen, u_char *buf)
>> +{
>> +       struct bcma_sflash *sflash = mtd->priv;
>> +       size_t bytes_read = 0;
>> +       u8 *src = (u8 *)KSEG0ADDR(sflash->window + from);
>> +       int i;
>> +       size_t unaligned_before, unaligned_after;
>> +
>> +       /* Check address range */
>> +       if ((from + len) > mtd->size)
>> +               return -EINVAL;
>> +
>> +       unaligned_before = from & 0x3;
>
> I think this should be 4 - (from & 0x3), else you will read too much
> in the unaligned_before loop, also being at an unaligned address then.

Right, that's wrong.


>> +       unaligned_after = (from + len) & 0x3;
>> +
>> +       for (i = 0; i < unaligned_before; i++) {
>> +               *buf = readb(src);
>> +               buf++;
>> +               src++;
>> +               bytes_read++;
>> +       }
>> +       for (i = from - unaligned_before; i < from + len - unaligned_after;
>
> This one looks suspicious, aren't you assuming you have read
> unaligned_before bytes, so shouldn't i be from /+/ unaligned_before?

Right again. I could probably drom "from" too.


>> +            i += 4) {
>> +               *(u32 *)buf = readl((u32 *)src);
>> +               buf += 4;
>> +               src += 4;
>> +               bytes_read += 4;
>> +       }
>> +       for (i = 0; i < unaligned_after; i++) {
>> +               *buf = readb(src);
>> +               buf++;
>> +               src++;
>> +               bytes_read++;
>> +       }
>
> It will also fail for unaligned reads within the same 4 byte block -
> they will be read twice, once in _before, once in _after.

Hm, I don't understand that yet. It looks fine for me :| But I'll do
some test and it should become obvious to me then :)


> Also in the before and after loops, you are reading with native
> endianess (since you don't swab the addresses), but in the aligned
> case you are assuming little endianess. If you intend to do native
> endianess reads (we only support little endian bcm47xx), you should be
> fine by just replacing this whole logic with a memcpy(_fromio?), if
> not you should probably swab the addresses when reading the unaligned
> parts when big endian. Unfortunately I don't have any big endian
> bcm47xx devices at hand to test ;-) (but I do know they exist - AFAICT
> from netgear's gpl sources the bcm53xxx switch chips are big endian
> bcm47xx).

Whoops, I didn't know readl is LE access :| I though readb/readw/readl
are native endianess. Sorry for that.


I'm not sure about that endianess, what exactly we should implement. I
wanted to get some tip from simple map (see map_funcs.c and map.h) and
it seems it is using "inline_map_copy_from" indeed.

-- 
Rafał



More information about the linux-mtd mailing list