source: trunk/target/linux/generic/patches-2.6.37/222-partial_eraseblock_write.patch @ 23828

Last change on this file since 23828 was 23828, checked in by acoul, 6 years ago

target/linux: add preliminary 2.6.37 kernel support

File size: 4.4 KB
  • drivers/mtd/mtdpart.c

    a b  
    3333#include <linux/magic.h> 
    3434#include <linux/err.h> 
    3535 
     36#define MTD_ERASE_PARTIAL       0x8000 /* partition only covers parts of an erase block */ 
     37 
    3638/* Our partition linked list */ 
    3739static LIST_HEAD(mtd_partitions); 
    3840static DEFINE_MUTEX(mtd_partitions_mutex); 
    static int part_erase(struct mtd_info *m 
    239241                return -EROFS; 
    240242        if (instr->addr >= mtd->size) 
    241243                return -EINVAL; 
     244 
     245        instr->partial_start = false; 
     246        if (mtd->flags & MTD_ERASE_PARTIAL) { 
     247                size_t readlen = 0; 
     248                u64 mtd_ofs; 
     249 
     250                instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC); 
     251                if (!instr->erase_buf) 
     252                        return -ENOMEM; 
     253 
     254                mtd_ofs = part->offset + instr->addr; 
     255                instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize); 
     256 
     257                if (instr->erase_buf_ofs > 0) { 
     258                        instr->addr -= instr->erase_buf_ofs; 
     259                        ret = part->master->read(part->master, 
     260                                instr->addr + part->offset, 
     261                                part->master->erasesize, 
     262                                &readlen, instr->erase_buf); 
     263 
     264                        instr->partial_start = true; 
     265                } else { 
     266                        mtd_ofs = part->offset + part->mtd.size; 
     267                        instr->erase_buf_ofs = part->master->erasesize - 
     268                                do_div(mtd_ofs, part->master->erasesize); 
     269 
     270                        if (instr->erase_buf_ofs > 0) { 
     271                                instr->len += instr->erase_buf_ofs; 
     272                                ret = part->master->read(part->master, 
     273                                        part->offset + instr->addr + 
     274                                        instr->len - part->master->erasesize, 
     275                                        part->master->erasesize, &readlen, 
     276                                        instr->erase_buf); 
     277                        } else { 
     278                                ret = 0; 
     279                        } 
     280                } 
     281                if (ret < 0) { 
     282                        kfree(instr->erase_buf); 
     283                        return ret; 
     284                } 
     285 
     286        } 
     287 
    242288        instr->addr += part->offset; 
    243289        ret = part->master->erase(part->master, instr); 
    244290        if (ret) { 
    245291                if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) 
    246292                        instr->fail_addr -= part->offset; 
    247293                instr->addr -= part->offset; 
     294                if (mtd->flags & MTD_ERASE_PARTIAL) 
     295                        kfree(instr->erase_buf); 
    248296        } 
     297 
    249298        return ret; 
    250299} 
    251300 
    void mtd_erase_callback(struct erase_inf 
    253302{ 
    254303        if (instr->mtd->erase == part_erase) { 
    255304                struct mtd_part *part = PART(instr->mtd); 
     305                size_t wrlen = 0; 
    256306 
     307                if (instr->mtd->flags & MTD_ERASE_PARTIAL) { 
     308                        if (instr->partial_start) { 
     309                                part->master->write(part->master, 
     310                                        instr->addr, instr->erase_buf_ofs, 
     311                                        &wrlen, instr->erase_buf); 
     312                                instr->addr += instr->erase_buf_ofs; 
     313                        } else { 
     314                                instr->len -= instr->erase_buf_ofs; 
     315                                part->master->write(part->master, 
     316                                        instr->addr + instr->len, 
     317                                        instr->erase_buf_ofs, &wrlen, 
     318                                        instr->erase_buf + 
     319                                        part->master->erasesize - 
     320                                        instr->erase_buf_ofs); 
     321                        } 
     322                        kfree(instr->erase_buf); 
     323                } 
    257324                if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) 
    258325                        instr->fail_addr -= part->offset; 
    259326                instr->addr -= part->offset; 
    static struct mtd_part *allocate_partiti 
    511578        if ((slave->mtd.flags & MTD_WRITEABLE) && 
    512579            mtd_mod_by_eb(slave->offset, &slave->mtd)) { 
    513580                /* Doesn't start on a boundary of major erase size */ 
    514                 /* FIXME: Let it be writable if it is on a boundary of 
    515                  * _minor_ erase size though */ 
    516                 slave->mtd.flags &= ~MTD_WRITEABLE; 
    517                 printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", 
    518                         part->name); 
     581                slave->mtd.flags |= MTD_ERASE_PARTIAL; 
     582                if (((u32) slave->mtd.size) > master->erasesize) 
     583                        slave->mtd.flags &= ~MTD_WRITEABLE; 
     584                else 
     585                        slave->mtd.erasesize = slave->mtd.size; 
    519586        } 
    520587        if ((slave->mtd.flags & MTD_WRITEABLE) && 
    521             mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) { 
    522                 slave->mtd.flags &= ~MTD_WRITEABLE; 
    523                 printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", 
    524                         part->name); 
    525         } 
     588            mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) { 
     589                slave->mtd.flags |= MTD_ERASE_PARTIAL; 
     590 
     591                if ((u32) slave->mtd.size > master->erasesize) 
     592                        slave->mtd.flags &= ~MTD_WRITEABLE; 
     593                else 
     594                        slave->mtd.erasesize = slave->mtd.size; 
     595        } 
     596        if ((slave->mtd.flags & (MTD_ERASE_PARTIAL|MTD_WRITEABLE)) == MTD_ERASE_PARTIAL) 
     597                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", 
     598                                part->name); 
    526599 
    527600        slave->mtd.ecclayout = master->ecclayout; 
    528601        if (master->block_isbad) { 
  • include/linux/mtd/mtd.h

    a b struct erase_info { 
    5757        u_long priv; 
    5858        u_char state; 
    5959        struct erase_info *next; 
     60 
     61        u8 *erase_buf; 
     62        u32 erase_buf_ofs; 
     63        bool partial_start; 
    6064}; 
    6165 
    6266struct mtd_erase_region_info { 
Note: See TracBrowser for help on using the repository browser.