[MTD][NOR] Add physical address to point() method

Adding the ability to get a physical address from point() in addition
to virtual address.  This physical address is required for XIP of
userspace code from flash.

Signed-off-by: Jared Hulbert <jaredeh@gmail.com>
Reviewed-by: Jörn Engel <joern@logfs.org>
Acked-by: Nicolas Pitre <nico@cam.org>
Acked-by: Greg Ungerer <gerg@uclinux.org>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
This commit is contained in:
Jared Hulbert 2008-04-29 23:26:49 -07:00 committed by David Woodhouse
parent 27c72b040c
commit a98889f3d8
12 changed files with 77 additions and 51 deletions

View File

@ -82,9 +82,8 @@ static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **); static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf); size_t *retlen, void **virt, resource_size_t *phys);
static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
size_t len);
static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode); static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode); static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
@ -1240,7 +1239,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
return ret; return ret;
} }
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, void **virt, resource_size_t *phys)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
@ -1257,8 +1257,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
chipnum = (from >> cfi->chipshift); chipnum = (from >> cfi->chipshift);
ofs = from - (chipnum << cfi->chipshift); ofs = from - (chipnum << cfi->chipshift);
*mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs; *virt = map->virt + cfi->chips[chipnum].start + ofs;
*retlen = 0; *retlen = 0;
if (phys)
*phys = map->phys + cfi->chips[chipnum].start + ofs;
while (len) { while (len) {
unsigned long thislen; unsigned long thislen;
@ -1291,7 +1293,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
return 0; return 0;
} }
static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;

View File

@ -48,18 +48,21 @@ static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
static int ram_point(struct mtd_info *mtd, loff_t from, size_t len, static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
if (from + len > mtd->size) if (from + len > mtd->size)
return -EINVAL; return -EINVAL;
*mtdbuf = mtd->priv + from; /* can we return a physical address with this driver? */
if (phys)
return -EINVAL;
*virt = mtd->priv + from;
*retlen = len; *retlen = len;
return 0; return 0;
} }
static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from, static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
size_t len)
{ {
} }

View File

@ -57,20 +57,21 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
u_char *start = mtd->priv;
if (from + len > mtd->size) if (from + len > mtd->size)
return -EINVAL; return -EINVAL;
*mtdbuf = start + from; /* can we return a physical address with this driver? */
if (phys)
return -EINVAL;
*virt = mtd->priv + from;
*retlen = len; *retlen = len;
return 0; return 0;
} }
static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
size_t len)
{ {
} }

View File

@ -134,7 +134,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
eoff_lo = end & (priv->asize - 1); eoff_lo = end & (priv->asize - 1);
soff_lo = instr->addr & (priv->asize - 1); soff_lo = instr->addr & (priv->asize - 1);
pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr); pmc551_point(mtd, instr->addr, instr->len, &retlen,
(void **)&ptr, NULL);
if (soff_hi == eoff_hi || mtd->size == priv->asize) { if (soff_hi == eoff_hi || mtd->size == priv->asize) {
/* The whole thing fits within one access, so just one shot /* The whole thing fits within one access, so just one shot
@ -154,7 +155,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
soff_hi += priv->asize; soff_hi += priv->asize;
pmc551_point(mtd, (priv->base_map0 | soff_hi), pmc551_point(mtd, (priv->base_map0 | soff_hi),
priv->asize, &retlen, &ptr); priv->asize, &retlen,
(void **)&ptr, NULL);
} }
memset(ptr, 0xff, eoff_lo); memset(ptr, 0xff, eoff_lo);
} }
@ -170,7 +172,7 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char ** mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
struct mypriv *priv = mtd->priv; struct mypriv *priv = mtd->priv;
u32 soff_hi; u32 soff_hi;
@ -188,6 +190,10 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
return -EINVAL; return -EINVAL;
} }
/* can we return a physical address with this driver? */
if (phys)
return -EINVAL;
soff_hi = from & ~(priv->asize - 1); soff_hi = from & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1); soff_lo = from & (priv->asize - 1);
@ -198,13 +204,12 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
priv->curr_map0 = soff_hi; priv->curr_map0 = soff_hi;
} }
*mtdbuf = priv->start + soff_lo; *virt = priv->start + soff_lo;
*retlen = len; *retlen = len;
return 0; return 0;
} }
static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from, static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
size_t len)
{ {
#ifdef CONFIG_MTD_PMC551_DEBUG #ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_unpoint()\n"); printk(KERN_DEBUG "pmc551_unpoint()\n");
@ -242,7 +247,7 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
soff_lo = from & (priv->asize - 1); soff_lo = from & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1); eoff_lo = end & (priv->asize - 1);
pmc551_point(mtd, from, len, retlen, &ptr); pmc551_point(mtd, from, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) { if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot /* The whole thing fits within one access, so just one shot
@ -263,7 +268,8 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
goto out; goto out;
} }
soff_hi += priv->asize; soff_hi += priv->asize;
pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr); pmc551_point(mtd, soff_hi, priv->asize, retlen,
(void **)&ptr, NULL);
} }
memcpy(copyto, ptr, eoff_lo); memcpy(copyto, ptr, eoff_lo);
copyto += eoff_lo; copyto += eoff_lo;
@ -308,7 +314,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
soff_lo = to & (priv->asize - 1); soff_lo = to & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1); eoff_lo = end & (priv->asize - 1);
pmc551_point(mtd, to, len, retlen, &ptr); pmc551_point(mtd, to, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) { if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot /* The whole thing fits within one access, so just one shot
@ -329,7 +335,8 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
goto out; goto out;
} }
soff_hi += priv->asize; soff_hi += priv->asize;
pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr); pmc551_point(mtd, soff_hi, priv->asize, retlen,
(void **)&ptr, NULL);
} }
memcpy(ptr, copyfrom, eoff_lo); memcpy(ptr, copyfrom, eoff_lo);
copyfrom += eoff_lo; copyfrom += eoff_lo;

View File

@ -76,8 +76,9 @@ static char *map;
static slram_mtd_list_t *slram_mtdlist = NULL; static slram_mtd_list_t *slram_mtdlist = NULL;
static int slram_erase(struct mtd_info *, struct erase_info *); static int slram_erase(struct mtd_info *, struct erase_info *);
static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **); static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
static void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t); resource_size_t *);
static void slram_unpoint(struct mtd_info *, loff_t, size_t);
static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@ -104,19 +105,23 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
static int slram_point(struct mtd_info *mtd, loff_t from, size_t len, static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
slram_priv_t *priv = mtd->priv; slram_priv_t *priv = mtd->priv;
/* can we return a physical address with this driver? */
if (phys)
return -EINVAL;
if (from + len > mtd->size) if (from + len > mtd->size)
return -EINVAL; return -EINVAL;
*mtdbuf = priv->start + from; *virt = priv->start + from;
*retlen = len; *retlen = len;
return(0); return(0);
} }
static void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{ {
} }

View File

@ -40,10 +40,12 @@ struct mtd_partition uclinux_romfs[] = {
/****************************************************************************/ /****************************************************************************/
int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len, int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
*mtdbuf = (u_char *) (map->virt + ((int) from)); *virt = map->virt + from;
if (phys)
*phys = map->phys + from;
*retlen = len; *retlen = len;
return(0); return(0);
} }

View File

@ -68,7 +68,7 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
} }
static int part_point (struct mtd_info *mtd, loff_t from, size_t len, static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **buf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
struct mtd_part *part = PART(mtd); struct mtd_part *part = PART(mtd);
if (from >= mtd->size) if (from >= mtd->size)
@ -76,14 +76,14 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
else if (from + len > mtd->size) else if (from + len > mtd->size)
len = mtd->size - from; len = mtd->size - from;
return part->master->point (part->master, from + part->offset, return part->master->point (part->master, from + part->offset,
len, retlen, buf); len, retlen, virt, phys);
} }
static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{ {
struct mtd_part *part = PART(mtd); struct mtd_part *part = PART(mtd);
part->master->unpoint (part->master, addr, from + part->offset, len); part->master->unpoint(part->master, from + part->offset, len);
} }
static int part_read_oob(struct mtd_info *mtd, loff_t from, static int part_read_oob(struct mtd_info *mtd, loff_t from,

View File

@ -332,7 +332,8 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (c->mtd->point) { if (c->mtd->point) {
unsigned long *wordebuf; unsigned long *wordebuf;
ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf); ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size,
&retlen, &ebuf, NULL);
if (ret) { if (ret) {
D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
goto do_flash_read; goto do_flash_read;
@ -340,7 +341,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (retlen < c->sector_size) { if (retlen < c->sector_size) {
/* Don't muck about if it won't let us point to the whole erase sector */ /* Don't muck about if it won't let us point to the whole erase sector */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen); c->mtd->unpoint(c->mtd, jeb->offset, retlen);
goto do_flash_read; goto do_flash_read;
} }
wordebuf = ebuf-sizeof(*wordebuf); wordebuf = ebuf-sizeof(*wordebuf);
@ -349,7 +350,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (*++wordebuf != ~0) if (*++wordebuf != ~0)
break; break;
} while(--retlen); } while(--retlen);
c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); c->mtd->unpoint(c->mtd, jeb->offset, c->sector_size);
if (retlen) { if (retlen) {
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
*wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));

View File

@ -63,10 +63,11 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
/* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
* adding and jffs2_flash_read_end() interface. */ * adding and jffs2_flash_read_end() interface. */
if (c->mtd->point) { if (c->mtd->point) {
err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); err = c->mtd->point(c->mtd, ofs, len, &retlen,
(void **)&buffer, NULL);
if (!err && retlen < len) { if (!err && retlen < len) {
JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
c->mtd->unpoint(c->mtd, buffer, ofs, retlen); c->mtd->unpoint(c->mtd, ofs, retlen);
} else if (err) } else if (err)
JFFS2_WARNING("MTD point failed: error code %d.\n", err); JFFS2_WARNING("MTD point failed: error code %d.\n", err);
else else
@ -100,7 +101,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
kfree(buffer); kfree(buffer);
#ifndef __ECOS #ifndef __ECOS
else else
c->mtd->unpoint(c->mtd, buffer, ofs, len); c->mtd->unpoint(c->mtd, ofs, len);
#endif #endif
if (crc != tn->data_crc) { if (crc != tn->data_crc) {
@ -136,7 +137,7 @@ free_out:
kfree(buffer); kfree(buffer);
#ifndef __ECOS #ifndef __ECOS
else else
c->mtd->unpoint(c->mtd, buffer, ofs, len); c->mtd->unpoint(c->mtd, ofs, len);
#endif #endif
return err; return err;
} }

View File

@ -97,11 +97,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
size_t pointlen; size_t pointlen;
if (c->mtd->point) { if (c->mtd->point) {
ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf); ret = c->mtd->point(c->mtd, 0, c->mtd->size, &pointlen,
(void **)&flashbuf, NULL);
if (!ret && pointlen < c->mtd->size) { if (!ret && pointlen < c->mtd->size) {
/* Don't muck about if it won't let us point to the whole flash */ /* Don't muck about if it won't let us point to the whole flash */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen); c->mtd->unpoint(c->mtd, 0, pointlen);
flashbuf = NULL; flashbuf = NULL;
} }
if (ret) if (ret)
@ -267,7 +268,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
kfree(flashbuf); kfree(flashbuf);
#ifndef __ECOS #ifndef __ECOS
else else
c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); c->mtd->unpoint(c->mtd, 0, c->mtd->size);
#endif #endif
if (s) if (s)
kfree(s); kfree(s);

View File

@ -143,10 +143,12 @@ struct mtd_info {
int (*erase) (struct mtd_info *mtd, struct erase_info *instr); int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */ /* This stuff for eXecute-In-Place */
int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); /* phys is optional and may be set to NULL */
int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, void **virt, resource_size_t *phys);
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */ /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len); void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);

View File

@ -36,8 +36,9 @@ struct mypriv {
* Function Prototypes * Function Prototypes
*/ */
static int pmc551_erase(struct mtd_info *, struct erase_info *); static int pmc551_erase(struct mtd_info *, struct erase_info *);
static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t); static void pmc551_unpoint(struct mtd_info *, loff_t, size_t);
static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, void **virt, resource_size_t *phys);
static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);