* MTD Mapping driver - out of vmalloc space
@ 2005-04-08 14:42 Chris Elston
2005-04-08 17:51 ` Ho Lee
0 siblings, 1 reply; 7+ messages in thread
From: Chris Elston @ 2005-04-08 14:42 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 1774 bytes --]
Dear all,
I'm writing an MTD mapping driver for a board with (up to) 512M SDRAM, and
(up to) 256M Flash and I've hit a bit of a problem. The standard way to write
a mapping driver seems to be to map the whole of the Flash into kernel virtual
memory space. While this is not a problem for small Flash devices, I'm hitting
the limit of the vmalloc space.
So I decided to modify my mapping driver to work through a smaller virtual
addressing window.
Basically, all reads/writes are redirected through my custom functions which
first ensure that the correct physical address range is mapped into virtual
space and then drop through to the standard read/write functions. The mapping
is achieved using ioremap/iounmap calls. (code attached)
David Woodhouse pointed out that this approach is not viable because the reads
and writes must be atomic - and ioremap can potentially sleep. So I'm stuck as
to how to proceed.
Ideally what I'd like is to be able to allocate a block of virtual addresses at
init time and then dynamically modify the physical address range that it refers to.
Since I wouldn't be requesting any more vmalloc space - just changing the mapping
for the space I have got - I'd hopefully be able to make this a non-blocking
operation. Unfortunately I have no idea how to go about this - or even if it's
possible :)
Thanks in advance,
Chris.
________________________________________________________________________
This e-mail has been scanned for all viruses by Star. The
service is powered by MessageLabs. For more information on a proactive
anti-virus service working around the clock, around the globe, visit:
http://www.star.net.uk
________________________________________________________________________
[-- Attachment #2: rsppc7d-flash.c --]
[-- Type: application/octet-stream, Size: 8944 bytes --]
/*
* Radstone Technology PPC7D Flash memory driver.
* Copyright (C) 2005 Radstone Technology <chris.elston@radstone.co.uk>
*
* Based on: ceiva.c, which has the following copyright:
* Ceiva flash memory driver.
* Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net>
*
* Based on: sa1100-flash.c, which has the following copyright:
* Flash memory access on SA11x0 based devices
*
* (C) 2000 Nicolas Pitre <nico@cam.org>
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/concat.h>
#include <asm/io.h>
#include <asm/ppcboot.h>
#include <platforms/radstone_ppc7d.h>
extern unsigned char __res[]; /* residual data structure */
static bd_t *binfo = (bd_t *)__res;
/*
* See include/linux/mtd/partitions.h for definition of the mtd_partition
* structure.
*/
#define RSPPC7D_BOOT_PARTITION_SIZE 0x800000
#define RSPPC7D_KERNEL_PARTITION_SIZE 0x400000
static struct mtd_partition rsppc7d_partitions[] = {
{
.name = "User",
.size = 0, /* set at runtime */
.offset = 0
},{
.name = "Kernel",
.size = RSPPC7D_KERNEL_PARTITION_SIZE,
.offset = MTDPART_OFS_APPEND
},{
.name = "PPCBoot",
.size = RSPPC7D_BOOT_PARTITION_SIZE,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE /* force read-only */
}
};
static int __init rsppc7d_static_partitions(struct mtd_partition **parts)
{
int nb_parts = 0;
rsppc7d_partitions[0].size = binfo->bi_flashsize -
RSPPC7D_KERNEL_PARTITION_SIZE -
RSPPC7D_BOOT_PARTITION_SIZE;
*parts = rsppc7d_partitions;
nb_parts = ARRAY_SIZE(rsppc7d_partitions);
return nb_parts;
}
struct rsppc7d_info {
unsigned long base;
unsigned long size;
int width;
void __iomem *vbase;
struct map_info *map;
struct mtd_info *mtd;
struct resource *res;
};
static struct map_info *io_mapped_map = NULL;
/*
* In order to avoid running out of vmalloc space, this
* function is used to 'page' the map which is currently
* being used in and out of vmalloc.
*/
static void __iomem *rsppc7d_ioremap_flash(struct map_info *map)
{
if (map != io_mapped_map) {
if (io_mapped_map) {
iounmap(io_mapped_map->virt);
io_mapped_map->virt = NULL;
}
io_mapped_map = map;
io_mapped_map->virt = ioremap(map->phys, map->size);
if (!io_mapped_map->virt) {
printk(KERN_ERR "rsppc7d_flash: unable to ioremap Flash\n");
}
}
return io_mapped_map->virt;
}
/*
* Flash access functions - fall through to default
* functions after ioremapping the current map.
*/
static inline map_word rsppc7d_flash_read(struct map_info *map, unsigned long ofs)
{
rsppc7d_ioremap_flash(map);
return inline_map_read(map, ofs);
}
static void rsppc7d_flash_write(struct map_info *map, const map_word datum, unsigned long ofs)
{
rsppc7d_ioremap_flash(map);
inline_map_write(map, datum, ofs);
}
static void rsppc7d_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
rsppc7d_ioremap_flash(map);
inline_map_copy_from(map, to, from, len);
}
static void rsppc7d_flash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
rsppc7d_ioremap_flash(map);
inline_map_copy_to(map, to, from, len);
}
#define MAX_NR_SUBMTD 4
static struct rsppc7d_info info[MAX_NR_SUBMTD];
static int __init rsppc7d_setup_mtd(struct rsppc7d_info *rsppc7d, int nr, struct mtd_info **rmtd)
{
struct mtd_info *subdev[nr];
struct map_info *maps;
int i, found = 0, ret = 0;
/*
* Allocate the map_info structs in one go.
*/
maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
if (!maps)
return -ENOMEM;
memset(maps, 0, sizeof(struct map_info) * nr);
/*
* Claim and then map the memory regions.
*/
for (i = 0; i < nr; i++) {
if (rsppc7d[i].base == (unsigned long)-1)
break;
rsppc7d[i].res = request_mem_region(rsppc7d[i].base, rsppc7d[i].size, "rsppc7d flash");
if (!rsppc7d[i].res) {
ret = -EBUSY;
break;
}
rsppc7d[i].map = maps + i;
rsppc7d[i].map->name = "rsppc7d flash";
rsppc7d[i].map->size = rsppc7d[i].size;
rsppc7d[i].map->phys = rsppc7d[i].base;
rsppc7d[i].map->bankwidth = rsppc7d[i].width;
rsppc7d[i].map->read = rsppc7d_flash_read;
rsppc7d[i].map->write = rsppc7d_flash_write;
rsppc7d[i].map->copy_from = rsppc7d_flash_copy_from;
rsppc7d[i].map->copy_to = rsppc7d_flash_copy_to;
rsppc7d[i].mtd = do_map_probe("cfi_probe", rsppc7d[i].map);
if (rsppc7d[i].mtd == NULL) {
ret = -ENXIO;
break;
}
rsppc7d[i].mtd->owner = THIS_MODULE;
subdev[i] = rsppc7d[i].mtd;
printk(KERN_INFO "rsppc7d flash: CFI device at 0x%08lx, %dMiB, "
"%d-bit\n", rsppc7d[i].base, rsppc7d[i].mtd->size >> 20,
rsppc7d[i].width * 8);
found += 1;
}
/*
* ENXIO is special. It means we didn't find a chip when
* we probed. We need to tear down the mapping, free the
* resource and mark it as such.
*/
if (ret == -ENXIO) {
release_resource(rsppc7d[i].res);
rsppc7d[i].res = NULL;
}
/*
* If we found one device, don't bother with concat support.
* If we found multiple devices, use concat if we have it
* available, otherwise fail.
*/
if (ret == 0 || ret == -ENXIO) {
if (found == 1) {
*rmtd = subdev[0];
ret = 0;
} else if (found > 1) {
/*
* We detected multiple devices. Concatenate
* them together.
*/
#ifdef CONFIG_MTD_CONCAT
*rmtd = mtd_concat_create(subdev, found,
"rsppc7d flash");
if (*rmtd == NULL)
ret = -ENXIO;
#else
printk(KERN_ERR "rsppc7d flash: multiple devices "
"found but MTD concat support disabled.\n");
ret = -ENXIO;
#endif
}
}
/*
* If we failed, clean up.
*/
if (ret) {
do {
if (rsppc7d[i].mtd)
map_destroy(rsppc7d[i].mtd);
if (rsppc7d[i].res)
release_resource(rsppc7d[i].res);
} while (i--);
kfree(maps);
}
return ret;
}
static void __exit rsppc7d_destroy_mtd(struct rsppc7d_info *rsppc7d, struct mtd_info *mtd)
{
int i;
del_mtd_partitions(mtd);
if (mtd != rsppc7d[0].mtd)
mtd_concat_destroy(mtd);
for (i = MAX_NR_SUBMTD; i >= 0; i--) {
if (rsppc7d[i].mtd)
map_destroy(rsppc7d[i].mtd);
if (rsppc7d[i].res)
release_resource(rsppc7d[i].res);
}
if (io_mapped_map)
iounmap(io_mapped_map->virt);
kfree(rsppc7d[0].map);
}
/*
* We define the memory space, size, and width for the flash memory
* space here.
*/
#define RSPPC7D_FLASH_BANK_WIDTH 4
static int __init rsppc7d_setup_flash(void)
{
int nr, banksz, banknr;
unsigned char memcfg;
static int flash_sizes[4] = { 0x04000000, 0x02000000, 0, 0x01000000 };
static int flash_banks[4] = { 4, 3, 2, 1 };
memcfg = inb(PPC7D_CPLD_MEM_CONFIG_EXTEND);
banksz = flash_sizes[memcfg & PPC7D_CPLD_FLASH_DEV_SIZE_MASK];
banknr = flash_banks[(memcfg & PPC7D_CPLD_FLASH_BANK_NUM_MASK) >> 2];
for (nr = 0; nr < banknr; nr++)
{
info[nr].base = binfo->bi_flashstart + (nr * banksz);
info[nr].size = banksz;
info[nr].width = RSPPC7D_FLASH_BANK_WIDTH;
}
return banknr;
}
static struct mtd_partition *parsed_parts;
static const char *probes[] = { "cmdlinepart", NULL };
static void __init rsppc7d_locate_partitions(struct mtd_info *mtd)
{
const char *part_type = NULL;
int nr_parts = 0;
do {
/*
* Partition selection stuff.
*/
nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0);
if (nr_parts > 0) {
part_type = "command line";
break;
}
nr_parts = rsppc7d_static_partitions(&parsed_parts);
if (nr_parts > 0) {
part_type = "static";
break;
}
printk("found: %d partitions\n", nr_parts);
} while (0);
if (nr_parts == 0) {
printk(KERN_NOTICE "rsppc7d flash: no partition info "
"available, registering whole flash\n");
add_mtd_device(mtd);
} else {
printk(KERN_NOTICE "rsppc7d flash: using %s partition "
"definition\n", part_type);
add_mtd_partitions(mtd, parsed_parts, nr_parts);
}
/* Always succeeds. */
}
static void __exit rsppc7d_destroy_partitions(void)
{
if (parsed_parts)
kfree(parsed_parts);
}
static struct mtd_info *mymtd;
static int __init rsppc7d_mtd_init(void)
{
int ret;
int nr;
nr = rsppc7d_setup_flash();
if (nr < 0)
return nr;
ret = rsppc7d_setup_mtd(info, nr, &mymtd);
if (ret)
return ret;
rsppc7d_locate_partitions(mymtd);
return 0;
}
static void __exit rsppc7d_mtd_cleanup(void)
{
rsppc7d_destroy_mtd(info, mymtd);
rsppc7d_destroy_partitions();
}
module_init(rsppc7d_mtd_init);
module_exit(rsppc7d_mtd_cleanup);
MODULE_AUTHOR("Chris Elston <chris.elston@radstone.co.uk>");
MODULE_DESCRIPTION("MTD map driver for Radstone PPC7D");
MODULE_LICENSE("GPL");
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: MTD Mapping driver - out of vmalloc space
2005-04-08 14:42 MTD Mapping driver - out of vmalloc space Chris Elston
@ 2005-04-08 17:51 ` Ho Lee
2005-04-08 18:39 ` Matt Porter
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Ho Lee @ 2005-04-08 17:51 UTC (permalink / raw)
To: Chris Elston; +Cc: linuxppc-embedded
Hi Chris,
How about setting PAGE_OFFSET to 0x80000000, that is 2G/2G split?
It would make enough virtual address space. I've never tried on PPC,
so I don't know the side effect of this.
-- Ho
----- Original Message -----
From: "Chris Elston" <chris.elston@radstone.co.uk>
To: <linuxppc-embedded@ozlabs.org>
Sent: Friday, April 08, 2005 7:42 AM
Subject: MTD Mapping driver - out of vmalloc space
Dear all,
I'm writing an MTD mapping driver for a board with (up to) 512M SDRAM, and
(up to) 256M Flash and I've hit a bit of a problem. The standard way to write
a mapping driver seems to be to map the whole of the Flash into kernel virtual
memory space. While this is not a problem for small Flash devices, I'm hitting
the limit of the vmalloc space.
So I decided to modify my mapping driver to work through a smaller virtual
addressing window.
Basically, all reads/writes are redirected through my custom functions which
first ensure that the correct physical address range is mapped into virtual
space and then drop through to the standard read/write functions. The mapping
is achieved using ioremap/iounmap calls. (code attached)
David Woodhouse pointed out that this approach is not viable because the reads
and writes must be atomic - and ioremap can potentially sleep. So I'm stuck as
to how to proceed.
Ideally what I'd like is to be able to allocate a block of virtual addresses at
init time and then dynamically modify the physical address range that it refers to.
Since I wouldn't be requesting any more vmalloc space - just changing the mapping
for the space I have got - I'd hopefully be able to make this a non-blocking
operation. Unfortunately I have no idea how to go about this - or even if it's
possible :)
Thanks in advance,
Chris.
________________________________________________________________________
This e-mail has been scanned for all viruses by Star. The
service is powered by MessageLabs. For more information on a proactive
anti-virus service working around the clock, around the globe, visit:
http://www.star.net.uk
________________________________________________________________________
--------------------------------------------------------------------------------
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: MTD Mapping driver - out of vmalloc space
2005-04-08 17:51 ` Ho Lee
@ 2005-04-08 18:39 ` Matt Porter
2005-04-08 18:39 ` Mark A. Greer
2005-04-08 18:48 ` Eugene Surovegin
2 siblings, 0 replies; 7+ messages in thread
From: Matt Porter @ 2005-04-08 18:39 UTC (permalink / raw)
To: Ho Lee; +Cc: linuxppc-embedded
On Fri, Apr 08, 2005 at 10:51:05AM -0700, Ho Lee wrote:
>
> Hi Chris,
>
> How about setting PAGE_OFFSET to 0x80000000, that is 2G/2G split?
> It would make enough virtual address space. I've never tried on PPC,
> so I don't know the side effect of this.
This is the ideal solution. It works fine with the caveat that
you have to be very aware of the virtual memory map of your board
port when doing this. On ppc32, we have very fine grained options
for manipulating this and other parameters under Advanced Options.
If the original poster can provide more details then we can tell
him the exact settings to use.
-Matt
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: MTD Mapping driver - out of vmalloc space
2005-04-08 17:51 ` Ho Lee
2005-04-08 18:39 ` Matt Porter
@ 2005-04-08 18:39 ` Mark A. Greer
2005-04-08 18:48 ` Eugene Surovegin
2 siblings, 0 replies; 7+ messages in thread
From: Mark A. Greer @ 2005-04-08 18:39 UTC (permalink / raw)
To: Ho Lee; +Cc: linuxppc-embedded
Ho Lee wrote:
>
> Hi Chris,
>
> How about setting PAGE_OFFSET to 0x80000000, that is 2G/2G split?
> It would make enough virtual address space. I've never tried on PPC,
> so I don't know the side effect of this.
> -- Ho
>
Chris,
Like Ho says, you need to lower PAGE_OFFSET (although you may not want
to drop it all the way to 0x80000000). That will increase your vmalloc
space. On ppc, you do this via the 'Advanced setup' config menu.
Mark
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: MTD Mapping driver - out of vmalloc space
2005-04-08 17:51 ` Ho Lee
2005-04-08 18:39 ` Matt Porter
2005-04-08 18:39 ` Mark A. Greer
@ 2005-04-08 18:48 ` Eugene Surovegin
2 siblings, 0 replies; 7+ messages in thread
From: Eugene Surovegin @ 2005-04-08 18:48 UTC (permalink / raw)
To: Ho Lee; +Cc: linuxppc-embedded
On Fri, Apr 08, 2005 at 10:51:05AM -0700, Ho Lee wrote:
>
> Hi Chris,
>
> How about setting PAGE_OFFSET to 0x80000000, that is 2G/2G split?
> It would make enough virtual address space. I've never tried on PPC,
> so I don't know the side effect of this.
I successfully use PAGE_OFFSET equal to 0xA000'0000 on 405-based
designs (2.4 of course :)).
--
Eugene
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: MTD Mapping driver - out of vmalloc space
@ 2005-04-12 10:07 Chris Elston
2005-04-15 5:45 ` Jörn Engel
0 siblings, 1 reply; 7+ messages in thread
From: Chris Elston @ 2005-04-12 10:07 UTC (permalink / raw)
To: linuxppc-embedded
>=20>=20How=20about=20setting=20PAGE_OFFSET=20to=200x80000000,=20that=20is=
=202G/2G=20split?
>=20>=20It=20would=20make=20enough=20virtual=20address=20space.=20I've=20n=
ever=20tried=20on=20PPC,
>=20>=20so=20I=20don't=20know=20the=20side=20effect=20of=20this.=20
>=20
>=20This=20is=20the=20ideal=20solution.=20=20It=20works=20fine=20with=20th=
e=20caveat=20that
>=20you=20have=20to=20be=20very=20aware=20of=20the=20virtual=20memory=20ma=
p=20of=20your=20board
>=20port=20when=20doing=20this.=20=20On=20ppc32,=20we=20have=20very=20fine=
=20grained=20options
>=20for=20manipulating=20this=20and=20other=20parameters=20under=20Advance=
d=20Options.
>=20If=20the=20original=20poster=20can=20provide=20more=20details=20then=20=
we=20can=20tell
>=20him=20the=20exact=20settings=20to=20use.
Thanks=20for=20everyone's=20input=20on=20this,=20I've=20moved=20the=20kern=
el=20virtual
base=20address=20to=200xa0000000,=20and=20it=20works=20fine=20now.=20=20
I'm=20still=20not=20convinced=20that=20this=20is=20a=20future=20proof=20so=
lution=20
though.=20=20What=20happens=20when=20I=20get=20a=20board=20with=20512MB=20=
Flash=201GB=20SDRAM?
I=20can=20push=20the=20top=20of=20the=20SDRAM=20out=20to=20the=20high=20me=
m=20area,=20but=20I'll=20
have=20to=20encroach=20further=20into=20user=20space=20to=20map=20the=20Fl=
ash.=20=20There's
no=20good=20reason=20that=20the=20whole=20of=20the=20Flash=20need=20be=20m=
apped=20at=20the=20same
time.=20(Perhaps=20performance?)
Thanks,
Chris.
________________________________________________________________________
This=20e-mail=20has=20been=20scanned=20for=20all=20viruses=20by=20Star.=20=
The
service=20is=20powered=20by=20MessageLabs.=20For=20more=20information=20on=
=20a=20proactive
anti-virus=20service=20working=20around=20the=20clock,=20around=20the=20gl=
obe,=20visit:
http://www.star.net.uk
________________________________________________________________________
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: MTD Mapping driver - out of vmalloc space
2005-04-12 10:07 Chris Elston
@ 2005-04-15 5:45 ` Jörn Engel
0 siblings, 0 replies; 7+ messages in thread
From: Jörn Engel @ 2005-04-15 5:45 UTC (permalink / raw)
To: Chris Elston; +Cc: linuxppc-embedded
On Tue, 12 April 2005 11:07:38 +0100, Chris Elston wrote:
>
> Thanks for everyone's input on this, I've moved the kernel virtual
> base address to 0xa0000000, and it works fine now.
>
> I'm still not convinced that this is a future proof solution
> though. What happens when I get a board with 512MB Flash 1GB SDRAM?
> I can push the top of the SDRAM out to the high mem area, but I'll
> have to encroach further into user space to map the Flash. There's
> no good reason that the whole of the Flash need be mapped at the same
> time. (Perhaps performance?)
Definitely performance. At the end of the day, you need a bigger
namespace of some sorts. Possible solutions are:
o a 64bit machine,
o a 4GiB/4GiB kernel/user split and
o a PPC440 with 36bit addressing and some hardware and ioremap tricks
to move flash above the 32bit limit.
The 4/4 split also costs some performance. It doesn't violate the
'flash read must be atomic' requirement, though.
Jörn
--
...one more straw can't possibly matter...
-- Kirby Bakken
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2005-04-15 5:45 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-04-08 14:42 MTD Mapping driver - out of vmalloc space Chris Elston
2005-04-08 17:51 ` Ho Lee
2005-04-08 18:39 ` Matt Porter
2005-04-08 18:39 ` Mark A. Greer
2005-04-08 18:48 ` Eugene Surovegin
-- strict thread matches above, loose matches on Subject: below --
2005-04-12 10:07 Chris Elston
2005-04-15 5:45 ` Jörn Engel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).