From: Felix Fietkau Date: Mon, 21 Sep 2009 12:38:22 +0000 (+0000) Subject: merge mtd fis table changes from r17657-r17660 to 8.09 to provide a better upgrade... X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fsvn-archive%2Farchive.git;a=commitdiff_plain;hb=1bf8e2e388fd8d01546a3636c1602e5b148cc16f merge mtd fis table changes from r17657-r17660 to 8.09 to provide a better upgrade path from 8.09 to trunk and back SVN-Revision: 17662 --- diff --git a/package/mtd/Makefile b/package/mtd/Makefile index efb61d0590..cf98609a49 100644 --- a/package/mtd/Makefile +++ b/package/mtd/Makefile @@ -4,15 +4,15 @@ # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # -# $Id$ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mtd -PKG_RELEASE:=8.1 +PKG_RELEASE:=8.2 PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME) +STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS) include $(INCLUDE_DIR)/package.mk @@ -34,12 +34,13 @@ endef target=$(firstword $(subst -, ,$(BOARD))) -define Build/Compile - $(MAKE) -C $(PKG_BUILD_DIR) \ - $(TARGET_CONFIGURE_OPTS) \ - TARGET=$(target) \ - CFLAGS="$(TARGET_CFLAGS) -Dtarget_$(target)=1 -Wall" -endef +MAKE_FLAGS += TARGET="$(target)" +TARGET_CFLAGS += -Dtarget_$(target)=1 -Wall + +ifdef CONFIG_MTD_REDBOOT_PARTS + MAKE_FLAGS += FIS_SUPPORT=1 + TARGET_CFLAGS += -DFIS_SUPPORT=1 +endif define Package/mtd/install $(INSTALL_DIR) $(1)/sbin diff --git a/package/mtd/src/Makefile b/package/mtd/src/Makefile index 68a632d5ac..bb509be8ba 100644 --- a/package/mtd/src/Makefile +++ b/package/mtd/src/Makefile @@ -5,6 +5,10 @@ obj = mtd.o jffs2.o crc32.o obj.brcm = trx.o obj.brcm47xx = $(obj.brcm) +ifdef FIS_SUPPORT + obj += fis.o +endif + mtd: $(obj) $(obj.$(TARGET)) clean: rm -f *.o jffs2 diff --git a/package/mtd/src/fis.c b/package/mtd/src/fis.c new file mode 100644 index 0000000000..f99101988d --- /dev/null +++ b/package/mtd/src/fis.c @@ -0,0 +1,240 @@ +/* + * FIS table updating code for mtd + * + * Copyright (C) 2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License v2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include "crc32.h" +#include "mtd.h" +#include "fis.h" + +struct fis_image_hdr { + unsigned char name[16]; + uint32_t flash_base; + uint32_t mem_base; + uint32_t size; + uint32_t entry_point; + uint32_t data_length; +} __attribute__((packed)); + +struct fis_image_crc { + uint32_t desc; + uint32_t file; +} __attribute__((packed)); + +struct fis_image_desc { + struct fis_image_hdr hdr; + char _pad[256 - sizeof(struct fis_image_hdr) - sizeof(struct fis_image_crc)]; + struct fis_image_crc crc; +} __attribute__((packed)); + +static int fis_fd = -1; +static struct fis_image_desc *fis_desc; +static int fis_erasesize = 0; + +static void +fis_close(void) +{ + if (fis_desc) + munmap(fis_desc, fis_erasesize); + + if (fis_fd >= 0) + close(fis_fd); + + fis_fd = -1; + fis_desc = NULL; +} + +static struct fis_image_desc * +fis_open(void) +{ + struct fis_image_desc *desc; + + if (fis_fd >= 0) + fis_close(); + + fis_fd = mtd_check_open("FIS directory"); + if (fis_fd < 0) + goto error; + + close(fis_fd); + fis_fd = mtd_open("FIS directory", true); + if (fis_fd < 0) + goto error; + + fis_erasesize = erasesize; + desc = mmap(NULL, erasesize, PROT_READ|PROT_WRITE, MAP_SHARED, fis_fd, 0); + if (desc == MAP_FAILED) + goto error; + + fis_desc = desc; + return desc; + +error: + fis_close(); + return NULL; +} + +int +fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new) +{ + struct fis_image_desc *desc; + void *end; + int found = 0; + int i; + + desc = fis_open(); + if (!desc) + return 0; + + for (i = 0; i < n_new - 1; i++) { + if (!new[i].size) { + fprintf(stderr, "FIS error: only the last partition can detect the size automatically\n"); + i = -1; + goto done; + } + } + + end = desc; + end = (char *) end + fis_erasesize; + while ((void *) desc < end) { + if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff)) + break; + + for (i = 0; i < n_old; i++) { + if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) { + found++; + goto next; + } + } +next: + desc++; + continue; + } + + if (found == n_old) + i = 1; + else + i = -1; + +done: + fis_close(); + return i; +} + +int +fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new) +{ + struct fis_image_desc *fisdir = NULL; + struct fis_image_desc *redboot = NULL; + struct fis_image_desc *first = NULL; + struct fis_image_desc *last = NULL; + struct fis_image_desc *desc; + struct fis_part *part; + uint32_t offset = 0, size = 0; + char *end, *tmp; + int i; + + desc = fis_open(); + if (!desc) + return -1; + + if (!quiet) + fprintf(stderr, "Updating FIS table... \n"); + + end = (char *) desc + fis_erasesize; + while ((char *) desc < end) { + if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff)) + break; + + if (!strcmp((char *) desc->hdr.name, "FIS directory")) + fisdir = desc; + + if (!strcmp((char *) desc->hdr.name, "RedBoot")) + redboot = desc; + + for (i = 0; i < n_old; i++) { + if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) { + size += desc->hdr.size; + last = desc; + if (!first) + first = desc; + break; + } + } + desc++; + } + desc--; + + if (desc == last) { + desc = fisdir; + } + + /* size fixup */ + if (desc && (last->hdr.flash_base < desc->hdr.flash_base - last->hdr.size)) + size += (desc->hdr.flash_base - last->hdr.flash_base) - last->hdr.size; + +#ifdef notyet + desc = first - 1; + if (redboot && (desc >= redboot)) { + if (first->hdr.flash_base - desc->hdr.size > desc->hdr.flash_base) { + int delta = first->hdr.flash_base - desc->hdr.size - desc->hdr.flash_base; + + offset -= delta; + size += delta; + } + } +#endif + + last++; + desc = first + n_new; + offset = first->hdr.flash_base; + + if (desc != last) { + if (desc > last) + tmp = (char *) desc; + else + tmp = (char *) last; + + memmove(desc, last, end - tmp); + if (desc < last) { + tmp = end - (last - desc) * sizeof(struct fis_image_desc); + memset(tmp, 0xff, tmp - end); + } + } + + for (part = new, desc = first; desc < first + n_new; desc++, part++) { + memset(desc, 0, sizeof(struct fis_image_desc)); + memcpy(desc->hdr.name, part->name, sizeof(desc->hdr.name)); + desc->crc.desc = 0; + desc->crc.file = 0; + + desc->hdr.flash_base = offset; + desc->hdr.mem_base = part->loadaddr; + desc->hdr.entry_point = part->loadaddr; + desc->hdr.size = (part->size > 0) ? part->size : size; + desc->hdr.data_length = desc->hdr.size; + + offset += desc->hdr.size; + size -= desc->hdr.size; + } + + msync(fis_desc, fis_erasesize, MS_SYNC|MS_INVALIDATE); + fis_close(); + + return 0; +} diff --git a/package/mtd/src/fis.h b/package/mtd/src/fis.h new file mode 100644 index 0000000000..bdf1103d8a --- /dev/null +++ b/package/mtd/src/fis.h @@ -0,0 +1,14 @@ +#ifndef __FIS_H +#define __FIS_H + +struct fis_part { + unsigned char name[16]; + uint32_t offset; + uint32_t loadaddr; + uint32_t size; +}; + +int fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new); +int fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new); + +#endif diff --git a/package/mtd/src/jffs2.c b/package/mtd/src/jffs2.c index c683b51d18..18eb4e6869 100644 --- a/package/mtd/src/jffs2.c +++ b/package/mtd/src/jffs2.c @@ -1,3 +1,21 @@ +/* + * jffs2 on-disk structure generator for mtd + * + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License v2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * Based on: + * JFFS2 -- Journalling Flash File System, Version 2. + * Copyright © 2001-2007 Red Hat, Inc. + * Created by David Woodhouse + */ #include #include #include diff --git a/package/mtd/src/jffs2.h b/package/mtd/src/jffs2.h index 70d4619534..858e77a017 100644 --- a/package/mtd/src/jffs2.h +++ b/package/mtd/src/jffs2.h @@ -8,7 +8,6 @@ * For licensing information, see the file 'LICENCE' in the * jffs2 directory. * - * $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $ * */ diff --git a/package/mtd/src/mtd-api.h b/package/mtd/src/mtd-api.h index 6ce62611e3..272043ddb2 100644 --- a/package/mtd/src/mtd-api.h +++ b/package/mtd/src/mtd-api.h @@ -1,5 +1,4 @@ -/* $Id: mtd.h,v 1.38 2003/01/12 16:30:19 spse Exp $ */ #ifndef __MTD_MTD_H__ #define __MTD_MTD_H__ diff --git a/package/mtd/src/mtd.c b/package/mtd/src/mtd.c index fb650a0da3..bd966ab7dc 100644 --- a/package/mtd/src/mtd.c +++ b/package/mtd/src/mtd.c @@ -1,13 +1,12 @@ /* * mtd - simple memory technology device manipulation tool * - * Copyright (C) 2005 Waldemar Brodkorb , - * Felix Fietkau + * Copyright (C) 2005 Waldemar Brodkorb , + * Copyright (C) 2005-2009 Felix Fietkau * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * modify it under the terms of the GNU General Public License v2 + * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,7 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * $Id$ * * The code is based on the linux-mtd examples. */ @@ -44,6 +42,7 @@ #include #include #include "mtd-api.h" +#include "fis.h" #include "mtd.h" #define MAX_ARGS 8 @@ -120,10 +119,9 @@ int mtd_erase_block(int fd, int offset) mtdEraseInfo.start = offset; mtdEraseInfo.length = erasesize; ioctl(fd, MEMUNLOCK, &mtdEraseInfo); - if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0) { - fprintf(stderr, "Erasing mtd failed.\n"); - exit(1); - } + if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0) + return -1; + return 0; } @@ -147,42 +145,78 @@ image_check(int imagefd, const char *mtd) static int mtd_check(const char *mtd) { + char *next = NULL; + char *str = NULL; int fd; - fd = mtd_check_open(mtd); - if (!fd) - return 0; + if (strchr(mtd, ':')) { + str = strdup(mtd); + mtd = str; + } - if (!buf) - buf = malloc(erasesize); + do { + next = strchr(mtd, ':'); + if (next) { + *next = 0; + next++; + } + + fd = mtd_check_open(mtd); + if (!fd) + return 0; + + if (!buf) + buf = malloc(erasesize); + + close(fd); + mtd = next; + } while (next); + + if (str) + free(str); - close(fd); return 1; } static int mtd_unlock(const char *mtd) { - int fd; struct erase_info_user mtdLockInfo; + char *next = NULL; + char *str = NULL; + int fd; - fd = mtd_check_open(mtd); - if(fd <= 0) { - fprintf(stderr, "Could not open mtd device: %s\n", mtd); - exit(1); + if (strchr(mtd, ':')) { + str = strdup(mtd); + mtd = str; } - if (quiet < 2) - fprintf(stderr, "Unlocking %s ...\n", mtd); + do { + next = strchr(mtd, ':'); + if (next) { + *next = 0; + next++; + } + + fd = mtd_check_open(mtd); + if(fd <= 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + exit(1); + } - mtdLockInfo.start = 0; - mtdLockInfo.length = mtdsize; - if(ioctl(fd, MEMUNLOCK, &mtdLockInfo)) { + if (quiet < 2) + fprintf(stderr, "Unlocking %s ...\n", mtd); + + mtdLockInfo.start = 0; + mtdLockInfo.length = mtdsize; + ioctl(fd, MEMUNLOCK, &mtdLockInfo); close(fd); - return 0; - } - - close(fd); + mtd = next; + } while (next); + + if (str) + free(str); + return 0; } @@ -206,11 +240,11 @@ mtd_erase(const char *mtd) for (mtdEraseInfo.start = 0; mtdEraseInfo.start < mtdsize; mtdEraseInfo.start += erasesize) { - + ioctl(fd, MEMUNLOCK, &mtdEraseInfo); if(ioctl(fd, MEMERASE, &mtdEraseInfo)) fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start); - } + } close(fd); return 0; @@ -245,27 +279,99 @@ mtd_refresh(const char *mtd) } static int -mtd_write(int imagefd, const char *mtd) +mtd_write(int imagefd, const char *mtd, char *fis_layout) { + char *next = NULL; + char *str = NULL; int fd, result; ssize_t r, w, e; + uint32_t offset = 0; + +#ifdef FIS_SUPPORT + static struct fis_part new_parts[MAX_ARGS]; + static struct fis_part old_parts[MAX_ARGS]; + int n_new = 0, n_old = 0; + + if (fis_layout) { + const char *tmp = mtd; + char *word, *brkt; + int ret; + + memset(&old_parts, 0, sizeof(old_parts)); + memset(&new_parts, 0, sizeof(new_parts)); + + do { + next = strchr(tmp, ':'); + if (!next) + next = (char *) tmp + strlen(tmp); + + memcpy(old_parts[n_old].name, tmp, next - tmp); + + n_old++; + tmp = next + 1; + } while(*next); + + for (word = strtok_r(fis_layout, ",", &brkt); + word; + word = strtok_r(NULL, ",", &brkt)) { + + tmp = strtok(word, ":"); + strncpy((char *) new_parts[n_new].name, tmp, sizeof(new_parts[n_new].name) - 1); + + tmp = strtok(NULL, ":"); + if (!tmp) + goto next; + + new_parts[n_new].size = strtoul(tmp, NULL, 0); + + tmp = strtok(NULL, ":"); + if (!tmp) + goto next; + + new_parts[n_new].loadaddr = strtoul(tmp, NULL, 16); +next: + n_new++; + } + ret = fis_validate(old_parts, n_old, new_parts, n_new); + if (ret < 0) { + fprintf(stderr, "Failed to validate the new FIS partition table\n"); + exit(1); + } + if (ret == 0) + fis_layout = NULL; + } +#endif + + if (strchr(mtd, ':')) { + str = strdup(mtd); + mtd = str; + } + + r = 0; + +resume: + next = strchr(mtd, ':'); + if (next) { + *next = 0; + next++; + } fd = mtd_check_open(mtd); if(fd < 0) { fprintf(stderr, "Could not open mtd device: %s\n", mtd); exit(1); } - + if (quiet < 2) fprintf(stderr, "Writing from %s to %s ... ", imagefile, mtd); - r = w = e = 0; + w = e = 0; if (!quiet) fprintf(stderr, " [ ]"); for (;;) { - /* buffer may contain data already (from trx check) */ - do { + /* buffer may contain data already (from trx check or last mtd partition write attempt) */ + while (buflen < erasesize) { r = read(imagefd, buf + buflen, erasesize - buflen); if (r < 0) { if ((errno == EINTR) || (errno == EAGAIN)) @@ -280,7 +386,7 @@ mtd_write(int imagefd, const char *mtd) break; buflen += r; - } while (buflen < erasesize); + } if (buflen == 0) break; @@ -305,16 +411,33 @@ mtd_write(int imagefd, const char *mtd) if (!quiet) fprintf(stderr, "\b\b\b[e]"); - mtd_erase_block(fd, e); + + if (mtd_erase_block(fd, e) < 0) { + if (next) { + if (w < e) { + write(fd, buf + offset, e - w); + offset = e - w; + } + w = 0; + e = 0; + close(fd); + mtd = next; + fprintf(stderr, "\b\b\b \n"); + goto resume; + } else { + fprintf(stderr, "Failed to erase block\n"); + exit(1); + } + } /* erase the chunk */ e += erasesize; } - + if (!quiet) fprintf(stderr, "\b\b\b[w]"); - - if ((result = write(fd, buf, buflen)) < buflen) { + + if ((result = write(fd, buf + offset, buflen)) < buflen) { if (result < 0) { fprintf(stderr, "Error writing image.\n"); exit(1); @@ -326,21 +449,30 @@ mtd_write(int imagefd, const char *mtd) w += buflen; buflen = 0; + offset = 0; } + if (!quiet) - fprintf(stderr, "\b\b\b\b"); + fprintf(stderr, "\b\b\b\b "); done: if (quiet < 2) fprintf(stderr, "\n"); +#ifdef FIS_SUPPORT + if (fis_layout) { + if (fis_remap(old_parts, n_old, new_parts, n_new) < 0) + fprintf(stderr, "Failed to update the FIS partition table\n"); + } +#endif + close(fd); return 0; } static void usage(void) { - fprintf(stderr, "Usage: mtd [ ...] [ ...] \n\n" + fprintf(stderr, "Usage: mtd [ ...] [ ...] [:...]\n\n" "The device is in the format of mtdX (eg: mtd4) or its label.\n" "mtd recognizes these commands:\n" " unlock unlock the device\n" @@ -356,6 +488,12 @@ static void usage(void) " -e erase before executing the command\n" " -d directory for jffs2write, defaults to \"tmp\"\n" " -j integrate into jffs2 data when writing an image\n" +#ifdef FIS_SUPPORT + " -F [:[:]][,...]\n" + " alter the fis partition table to create new partitions replacing\n" + " the partitions provided as argument to the write command\n" + " (only valid together with the write command)\n" +#endif "\n" "Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n" " mtd -r write linux.trx linux\n\n"); @@ -379,6 +517,7 @@ int main (int argc, char **argv) { int ch, i, boot, imagefd = 0, force, unlocked; char *erase[MAX_ARGS], *device = NULL; + char *fis_layout = NULL; enum { CMD_ERASE, CMD_WRITE, @@ -386,14 +525,18 @@ int main (int argc, char **argv) CMD_REFRESH, CMD_JFFS2WRITE } cmd = -1; - + erase[0] = NULL; boot = 0; force = 0; buflen = 0; quiet = 0; - while ((ch = getopt(argc, argv, "frqe:d:j:")) != -1) + while ((ch = getopt(argc, argv, +#ifdef FIS_SUPPORT + "F:" +#endif + "frqe:d:j:")) != -1) switch (ch) { case 'f': force = 1; @@ -411,20 +554,25 @@ int main (int argc, char **argv) i = 0; while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS)) i++; - + erase[i++] = optarg; erase[i] = NULL; break; case 'd': jffs2dir = optarg; break; +#ifdef FIS_SUPPORT + case 'F': + fis_layout = optarg; + break; +#endif case '?': default: usage(); } argc -= optind; argv += optind; - + if (argc < 2) usage(); @@ -440,7 +588,7 @@ int main (int argc, char **argv) } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) { cmd = CMD_WRITE; device = argv[2]; - + if (strcmp(argv[1], "-") == 0) { imagefile = ""; imagefd = 0; @@ -451,7 +599,7 @@ int main (int argc, char **argv) exit(1); } } - + if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); exit(1); @@ -464,7 +612,7 @@ int main (int argc, char **argv) } else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) { cmd = CMD_JFFS2WRITE; device = argv[2]; - + imagefile = argv[1]; if (!mtd_check(device)) { fprintf(stderr, "Can't open device for writing!\n"); @@ -475,7 +623,7 @@ int main (int argc, char **argv) } sync(); - + i = 0; unlocked = 0; while (erase[i] != NULL) { @@ -485,8 +633,7 @@ int main (int argc, char **argv) unlocked = 1; i++; } - - + switch (cmd) { case CMD_UNLOCK: if (!unlocked) @@ -500,7 +647,7 @@ int main (int argc, char **argv) case CMD_WRITE: if (!unlocked) mtd_unlock(device); - mtd_write(imagefd, device); + mtd_write(imagefd, device, fis_layout); break; case CMD_JFFS2WRITE: if (!unlocked) @@ -513,7 +660,7 @@ int main (int argc, char **argv) } sync(); - + if (boot) do_reboot(); diff --git a/target/linux/atheros/config-default b/target/linux/atheros/config-default index 8ffd759ef8..72ed3870ae 100644 --- a/target/linux/atheros/config-default +++ b/target/linux/atheros/config-default @@ -161,7 +161,7 @@ CONFIG_MTD_PHYSMAP_START=0x0 # CONFIG_MTD_RAM is not set CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-3 CONFIG_MTD_REDBOOT_PARTS=y -CONFIG_MTD_REDBOOT_PARTS_READONLY=y +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_SLRAM is not set CONFIG_MTD_SPIFLASH=y diff --git a/target/linux/atheros/files/drivers/mtd/devices/spiflash.c b/target/linux/atheros/files/drivers/mtd/devices/spiflash.c index c4c2016d8b..3fd5422b0f 100644 --- a/target/linux/atheros/files/drivers/mtd/devices/spiflash.c +++ b/target/linux/atheros/files/drivers/mtd/devices/spiflash.c @@ -317,7 +317,7 @@ spiflash_erase (struct mtd_info *mtd,struct erase_info *instr) spiflash_done(); instr->state = MTD_ERASE_DONE; - if (instr->callback) instr->callback (instr); + mtd_erase_callback(instr); return 0; } diff --git a/target/linux/generic-2.6/patches-2.6.26/222-partial_eraseblock_write.patch b/target/linux/generic-2.6/patches-2.6.26/222-partial_eraseblock_write.patch new file mode 100644 index 0000000000..10f21945aa --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.26/222-partial_eraseblock_write.patch @@ -0,0 +1,140 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -23,6 +23,8 @@ + #include + #include + ++#define MTD_ERASE_PARTIAL 0x8000 /* partition only covers parts of an erase block */ ++ + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); + +@@ -214,12 +216,56 @@ static int part_erase (struct mtd_info * + return -EROFS; + if (instr->addr >= mtd->size) + return -EINVAL; ++ ++ instr->partial_start = false; ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ size_t readlen = 0; ++ u32 mtd_ofs; ++ ++ instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC); ++ if (!instr->erase_buf) ++ return -ENOMEM; ++ ++ instr->erase_buf_ofs = (part->offset + instr->addr) % ++ part->master->erasesize; ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->addr -= instr->erase_buf_ofs; ++ ret = part->master->read(part->master, ++ instr->addr + part->offset, ++ part->master->erasesize, ++ &readlen, instr->erase_buf); ++ ++ instr->partial_start = true; ++ } else { ++ instr->erase_buf_ofs = part->master->erasesize - ++ ((part->offset + part->mtd.size) % part->master->erasesize); ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->len += instr->erase_buf_ofs; ++ ret = part->master->read(part->master, ++ part->offset + instr->addr + ++ instr->len - part->master->erasesize, ++ part->master->erasesize, &readlen, ++ instr->erase_buf); ++ } else { ++ ret = 0; ++ } ++ } ++ if (ret < 0) { ++ kfree(instr->erase_buf); ++ return ret; ++ } ++ } + instr->addr += part->offset; + ret = part->master->erase(part->master, instr); ++ instr->partial_start = false; + if (ret) { + if (instr->fail_addr != 0xffffffff) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; ++ if (mtd->flags & MTD_ERASE_PARTIAL) ++ kfree(instr->erase_buf); + } + return ret; + } +@@ -228,7 +274,25 @@ void mtd_erase_callback(struct erase_inf + { + if (instr->mtd->erase == part_erase) { + struct mtd_part *part = PART(instr->mtd); ++ size_t wrlen = 0; + ++ if (instr->mtd->flags & MTD_ERASE_PARTIAL) { ++ if (instr->partial_start) { ++ part->master->write(part->master, ++ instr->addr, instr->erase_buf_ofs, ++ &wrlen, instr->erase_buf); ++ instr->addr += instr->erase_buf_ofs; ++ } else { ++ instr->len -= instr->erase_buf_ofs; ++ part->master->write(part->master, ++ instr->addr + instr->len, ++ instr->erase_buf_ofs, &wrlen, ++ instr->erase_buf + ++ part->master->erasesize - ++ instr->erase_buf_ofs); ++ } ++ kfree(instr->erase_buf); ++ } + if (instr->fail_addr != 0xffffffff) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; +@@ -456,17 +520,24 @@ static int add_one_partition(struct mtd_ + if ((slave->mtd.flags & MTD_WRITEABLE) && + (slave->offset % slave->mtd.erasesize)) { + /* Doesn't start on a boundary of major erase size */ +- /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", +- part->name); ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ if (((u32) slave->mtd.size) > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; + } + if ((slave->mtd.flags & MTD_WRITEABLE) && + (slave->mtd.size % slave->mtd.erasesize)) { +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", +- part->name); +- } ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ ++ if ((u32) slave->mtd.size > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; ++ } ++ if ((slave->mtd.flags & (MTD_ERASE_PARTIAL|MTD_WRITEABLE)) == MTD_ERASE_PARTIAL) ++ printk(KERN_WARNING"mtd: partition \"%s\" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only\n", ++ part->name); + + slave->mtd.ecclayout = master->ecclayout; + if (master->block_isbad) { +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -43,6 +43,10 @@ struct erase_info { + u_long priv; + u_char state; + struct erase_info *next; ++ ++ u8 *erase_buf; ++ u32 erase_buf_ofs; ++ bool partial_start; + }; + + struct mtd_erase_region_info {