diff --git a/Documentation/porting.txt b/Documentation/porting.txt index a350e5e5f..bd807a318 100644 --- a/Documentation/porting.txt +++ b/Documentation/porting.txt @@ -50,7 +50,7 @@ extra-y += barebox.lds is not ported yet. - Call devfs_add_partition() to add an environment partition for your device: - devfs_add_partition("nor0", 0x40000, 0x20000, "env0"); + devfs_add_partition("nor0", 0x40000, 0x20000, DEVFS_PARTITION_FIXED, "env0"); This will add an area starting at 0x40000 of size 0x20000 of the device nor0 as env0. diff --git a/arch/arm/boards/a9m2410/a9m2410.c b/arch/arm/boards/a9m2410/a9m2410.c index b2b6c8711..943b7709b 100644 --- a/arch/arm/boards/a9m2410/a9m2410.c +++ b/arch/arm/boards/a9m2410/a9m2410.c @@ -82,6 +82,24 @@ static int a9m2410_mem_init(void) } mem_initcall(a9m2410_mem_init); +static const struct devfs_partition a9m2410_nand0_partitions[] = { + { + .offset = 0, + .size = 0x40000, + .flags = DEVFS_PARTITION_FIXED, + .name = "self_raw", + .bbname = "self0", + }, { + .offset = DEVFS_PARTITION_APPEND, + .size = 0x20000, + .flags = DEVFS_PARTITION_FIXED, + .name = "env_raw", + .bbname = "env0", + }, { + /* sentinel */ + } +}; + static int a9m2410_devices_init(void) { uint32_t reg; @@ -116,14 +134,9 @@ static int a9m2410_devices_init(void) add_generic_device("smc91c111", DEVICE_ID_DYNAMIC, NULL, S3C_CS1_BASE + 0x300, 16, IORESOURCE_MEM, NULL); -#ifdef CONFIG_NAND - /* ----------- add some vital partitions -------- */ - devfs_add_partition("nand0", 0x00000, 0x40000, DEVFS_PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); + if (IS_ENABLED(CONFIG_NAND)) + devfs_create_partitions("nand0", a9m2410_nand0_partitions); - devfs_add_partition("nand0", 0x40000, 0x20000, DEVFS_PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); -#endif armlinux_set_architecture(MACH_TYPE_A9M2410); return 0; diff --git a/arch/arm/boards/freescale-mx35-3ds/3stack.c b/arch/arm/boards/freescale-mx35-3ds/3stack.c index dbd1c7adc..2be1554b6 100644 --- a/arch/arm/boards/freescale-mx35-3ds/3stack.c +++ b/arch/arm/boards/freescale-mx35-3ds/3stack.c @@ -129,6 +129,40 @@ static void set_board_rev(int rev) imx35_3ds_system_rev = (imx35_3ds_system_rev & ~(0xF << 8)) | (rev & 0xF) << 8; } +static const struct devfs_partition f3s_nand0_partitions[] = { + { + .offset = 0, + .size = 0x40000, + .flags = DEVFS_PARTITION_FIXED, + .name = "self_raw", + .bbname = "self0", + }, { + .offset = DEVFS_PARTITION_APPEND, /* 0x40000 */ + .size = 0x80000, + .flags = DEVFS_PARTITION_FIXED, + .name = "env_raw", + .bbname = "env0", + }, { + /* sentinel */ + } +}; + +static const struct devfs_partition f3s_nor0_partitions[] = { + { + .offset = 0, + .size = 0x40000, + .flags = DEVFS_PARTITION_FIXED, + .name = "self0", + }, { + .offset = DEVFS_PARTITION_APPEND, /* 0x40000 */ + .size = 0x80000, + .flags = DEVFS_PARTITION_FIXED, + .name = "env0", + }, { + /* sentinel */ + } +}; + static int f3s_devices_init(void) { uint32_t reg; @@ -151,15 +185,11 @@ static int f3s_devices_init(void) switch ((reg >> 25) & 0x3) { case 0x01: /* NAND is the source */ - devfs_add_partition("nand0", 0x00000, 0x40000, DEVFS_PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", 0x40000, 0x80000, DEVFS_PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); + devfs_create_partitions("nand0", f3s_nand0_partitions); break; case 0x00: /* NOR is the source */ - devfs_add_partition("nor0", 0x00000, 0x40000, DEVFS_PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x40000, 0x80000, DEVFS_PARTITION_FIXED, "env0"); + devfs_create_partitions("nor0", f3s_nor0_partitions); protect_file("/dev/env0", 1); break; } diff --git a/arch/arm/boards/phytec-phycore-imx27/pcm038.c b/arch/arm/boards/phytec-phycore-imx27/pcm038.c index 1733261f7..7df0ddc31 100644 --- a/arch/arm/boards/phytec-phycore-imx27/pcm038.c +++ b/arch/arm/boards/phytec-phycore-imx27/pcm038.c @@ -199,6 +199,40 @@ struct imxusb_platformdata pcm038_otg_pdata = { .flags = MXC_EHCI_MODE_ULPI | MXC_EHCI_INTERFACE_DIFF_UNI, }; +static const struct devfs_partition pcm038_nand0_partitions[] = { + { + .offset = 0, + .size = SZ_512K, + .flags = DEVFS_PARTITION_FIXED, + .name = "self_raw", + .bbname = "self0", + }, { + .offset = DEVFS_PARTITION_APPEND, /* 512 KiB */ + .size = SZ_128K, + .flags = DEVFS_PARTITION_FIXED, + .name = "env_raw", + .bbname = "env0", + }, { + /* sentinel */ + } +}; + +static const struct devfs_partition pcm038_nor0_partitions[] = { + { + .offset = 0, + .size = SZ_512K, + .flags = DEVFS_PARTITION_FIXED, + .name = "self0", + }, { + .offset = DEVFS_PARTITION_APPEND, /* 512 KiB */ + .size = SZ_128K, + .flags = DEVFS_PARTITION_FIXED, + .name = "env0", + }, { + /* sentinel */ + } +}; + static int pcm038_devices_init(void) { int i; @@ -336,19 +370,12 @@ static int pcm038_devices_init(void) switch (bootsource_get()) { case BOOTSOURCE_NAND: - devfs_add_partition("nand0", 0, SZ_512K, - DEVFS_PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", SZ_512K, SZ_128K, - DEVFS_PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); + devfs_create_partitions("nand0", pcm038_nand0_partitions); + envdev = "NAND"; break; default: - devfs_add_partition("nor0", 0, SZ_512K, - DEVFS_PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", SZ_512K, SZ_128K, - DEVFS_PARTITION_FIXED, "env0"); + devfs_create_partitions("nor0", pcm038_nor0_partitions); protect_file("/dev/env0", 1); envdev = "NOR"; } diff --git a/arch/arm/boards/sama5d3xek/init.c b/arch/arm/boards/sama5d3xek/init.c index 4f866aa6f..e07864224 100644 --- a/arch/arm/boards/sama5d3xek/init.c +++ b/arch/arm/boards/sama5d3xek/init.c @@ -400,6 +400,38 @@ static void ek_add_device_hdmi(void) } #endif +static const struct devfs_partition at91sama5d3xek_nand0_partitions[] = { + { + .offset = 0x00000, + .size = SZ_256K, + .flags = DEVFS_PARTITION_FIXED, + .name = "at91bootstrap_raw", + .bbname = "at91bootstrap", + }, { + .offset = DEVFS_PARTITION_APPEND, /* 256 KiB */ + .size = SZ_256K + SZ_128K, + .flags = DEVFS_PARTITION_FIXED, + .name = "self_raw", + .bbname = "self0", + }, + /* hole of 128 KiB */ + { + .offset = SZ_512K + SZ_256K, + .size = SZ_256K, + .flags = DEVFS_PARTITION_FIXED, + .name = "env_raw", + .bbname = "env0", + }, { + .offset = DEVFS_PARTITION_APPEND, /* 1 MiB */ + .size = SZ_256K, + .flags = DEVFS_PARTITION_FIXED, + .name = "env_raw1", + .bbname = "env1", + }, { + /* sentinel */ + } +}; + static int at91sama5d3xek_devices_init(void) { ek_add_device_w1(); @@ -411,14 +443,7 @@ static int at91sama5d3xek_devices_init(void) ek_add_device_mci(); ek_add_device_lcdc(); - devfs_add_partition("nand0", 0x00000, SZ_256K, DEVFS_PARTITION_FIXED, "at91bootstrap_raw"); - dev_add_bb_dev("at91bootstrap_raw", "at91bootstrap"); - devfs_add_partition("nand0", SZ_256K, SZ_256K + SZ_128K, DEVFS_PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", SZ_512K + SZ_256K, SZ_256K, DEVFS_PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); - devfs_add_partition("nand0", SZ_1M, SZ_256K, DEVFS_PARTITION_FIXED, "env_raw1"); - dev_add_bb_dev("env_raw1", "env1"); + devfs_create_partitions("nand0", at91sama5d3xek_nand0_partitions); return 0; } diff --git a/drivers/mtd/nand/nand-bb.c b/drivers/mtd/nand/nand-bb.c index 0292f2f42..f387ef687 100644 --- a/drivers/mtd/nand/nand-bb.c +++ b/drivers/mtd/nand/nand-bb.c @@ -261,7 +261,7 @@ static LIST_HEAD(bb_list); * @param[in] name Partition name (can be obtained with devinfo command) * @return The device representing the new partition. */ -int dev_add_bb_dev(char *path, const char *name) +int dev_add_bb_dev(const char *path, const char *name) { struct nand_bb *bb; int ret = -ENOMEM; diff --git a/fs/devfs-core.c b/fs/devfs-core.c index bd6d48286..eafdc878a 100644 --- a/fs/devfs-core.c +++ b/fs/devfs-core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -260,47 +261,88 @@ int devfs_remove(struct cdev *cdev) return 0; } -struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size, - int flags, const char *name) +static struct cdev *__devfs_add_partition(struct cdev *cdev, + const struct devfs_partition *partinfo, loff_t *end) { - struct cdev *cdev, *new; + loff_t offset, size; + static struct cdev *new; - cdev = cdev_by_name(name); - if (cdev) + if (cdev_by_name(partinfo->name)) return ERR_PTR(-EEXIST); - cdev = cdev_by_name(devname); - if (!cdev) - return ERR_PTR(-ENOENT); + if (partinfo->offset > 0) + offset = partinfo->offset; + else if (partinfo->offset == 0) + /* append to previous partition */ + offset = *end; + else + /* relative to end of cdev */ + offset = cdev->size + partinfo->offset; - if (offset + size > cdev->size) + if (partinfo->size > 0) + size = partinfo->size; + else + size = cdev->size + partinfo->size - offset; + + if (offset >= 0 && offset < *end) + pr_debug("partition %s not after previous partition\n", + partinfo->name); + + *end = offset + size; + + if (offset < 0 || *end > cdev->size) { + pr_warn("partition %s not completely inside device %s\n", + partinfo->name, cdev->name); return ERR_PTR(-EINVAL); + } if (IS_ENABLED(CONFIG_PARTITION_NEED_MTD) && cdev->mtd) { struct mtd_info *mtd; - mtd = mtd_add_partition(cdev->mtd, offset, size, flags, name); + mtd = mtd_add_partition(cdev->mtd, offset, size, + partinfo->flags, partinfo->name); if (IS_ERR(mtd)) return (void *)mtd; return 0; } - new = xzalloc(sizeof (*new)); - new->name = strdup(name); - if (!strncmp(devname, name, strlen(devname))) - new->partname = xstrdup(name + strlen(devname) + 1); + new = xzalloc(sizeof(*new)); + new->name = strdup(partinfo->name); + if (!strncmp(cdev->name, partinfo->name, strlen(cdev->name))) + new->partname = xstrdup(partinfo->name + strlen(cdev->name) + 1); + new->ops = cdev->ops; new->priv = cdev->priv; new->size = size; - new->offset = offset + cdev->offset; + new->offset = cdev->offset + offset; + new->dev = cdev->dev; - new->flags = flags | DEVFS_IS_PARTITION; + new->flags = partinfo->flags | DEVFS_IS_PARTITION; devfs_create(new); return new; } +struct cdev *devfs_add_partition(const char *devname, loff_t offset, + loff_t size, unsigned int flags, const char *name) +{ + struct cdev *cdev; + loff_t end = 0; + const struct devfs_partition partinfo = { + .offset = offset, + .size = size, + .flags = flags, + .name = name, + }; + + cdev = cdev_by_name(devname); + if (!cdev) + return ERR_PTR(-ENOENT); + + return __devfs_add_partition(cdev, &partinfo, &end); +} + int devfs_del_partition(const char *name) { struct cdev *cdev; @@ -330,3 +372,27 @@ int devfs_del_partition(const char *name) return 0; } + +int devfs_create_partitions(const char *devname, + const struct devfs_partition partinfo[]) +{ + loff_t offset = 0; + struct cdev *cdev; + + cdev = cdev_by_name(devname); + if (!cdev) + return -ENOENT; + + for (; partinfo->name; ++partinfo) { + struct cdev *new; + + new = __devfs_add_partition(cdev, partinfo, &offset); + if (IS_ERR(new)) + return PTR_ERR(new); + + if (partinfo->bbname) + dev_add_bb_dev(partinfo->name, partinfo->bbname); + } + + return 0; +} diff --git a/include/driver.h b/include/driver.h index cbb040170..01b181ddb 100644 --- a/include/driver.h +++ b/include/driver.h @@ -482,15 +482,48 @@ ssize_t cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offs int cdev_ioctl(struct cdev *cdev, int cmd, void *buf); int cdev_erase(struct cdev *cdev, size_t count, loff_t offset); -#define DEVFS_PARTITION_FIXED (1 << 0) -#define DEVFS_PARTITION_READONLY (1 << 1) +#define DEVFS_PARTITION_FIXED (1U << 0) +#define DEVFS_PARTITION_READONLY (1U << 1) #define DEVFS_IS_PARTITION (1 << 2) #define DEVFS_IS_CHARACTER_DEV (1 << 3) -struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size, - int flags, const char *name); +struct cdev *devfs_add_partition(const char *devname, loff_t offset, + loff_t size, unsigned int flags, const char *name); int devfs_del_partition(const char *name); +#define DEVFS_PARTITION_APPEND 0 + +/** + * struct devfs_partition - defines parameters for a single partition + * @offset: start of partition + * a negative offset requests to start the partition relative to the + * device's end. DEVFS_PARTITION_APPEND (i.e. 0) means start directly at + * the end of the previous partition. + * @size: size of partition + * a non-positive value requests to use a size that keeps -size free space + * after the current partition. A special case of this is passing 0, which + * means "until end of device". + * @flags: flags passed to devfs_add_partition + * @name: name passed to devfs_add_partition + * @bbname: if non-NULL also dev_add_bb_dev() is called for the partition during + * devfs_create_partitions(). + */ +struct devfs_partition { + loff_t offset; + loff_t size; + unsigned int flags; + const char *name; + const char *bbname; +}; +/** + * devfs_create_partitions - create a set of partitions for a device + * @devname: name of the device to partition + * @partinfo: array of partition parameters + * The array is processed until an entry with .name = NULL is found. + */ +int devfs_create_partitions(const char *devname, + const struct devfs_partition partinfo[]); + #define DRV_OF_COMPAT(compat) \ IS_ENABLED(CONFIG_OFDEVICE) ? (compat) : NULL diff --git a/include/nand.h b/include/nand.h index b1762dfa4..a0e77cc8c 100644 --- a/include/nand.h +++ b/include/nand.h @@ -5,10 +5,10 @@ struct nand_bb; #ifdef CONFIG_NAND -int dev_add_bb_dev(char *filename, const char *name); +int dev_add_bb_dev(const char *filename, const char *name); int dev_remove_bb_dev(const char *name); #else -static inline int dev_add_bb_dev(char *filename, const char *name) { +static inline int dev_add_bb_dev(const char *filename, const char *name) { return 0; } static inline int dev_remove_bb_dev(const char *name)