1fd534e9bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Direct MTD block device access 41da177e4SLinus Torvalds * 5a1452a37SDavid Woodhouse * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org> 6a1452a37SDavid Woodhouse * Copyright © 2000-2003 Nicolas Pitre <nico@fluxnic.net> 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/fs.h> 101da177e4SLinus Torvalds #include <linux/init.h> 1115fdc52fSThomas Gleixner #include <linux/kernel.h> 1215fdc52fSThomas Gleixner #include <linux/module.h> 1315fdc52fSThomas Gleixner #include <linux/sched.h> 141da177e4SLinus Torvalds #include <linux/slab.h> 1515fdc52fSThomas Gleixner #include <linux/types.h> 161da177e4SLinus Torvalds #include <linux/vmalloc.h> 1715fdc52fSThomas Gleixner 181da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 191da177e4SLinus Torvalds #include <linux/mtd/blktrans.h> 2048b19268SIngo Molnar #include <linux/mutex.h> 21f83c3838SEzequiel Garcia #include <linux/major.h> 2248b19268SIngo Molnar 231da177e4SLinus Torvalds 24cbfe93e9SBen Hutchings struct mtdblk_dev { 25cbfe93e9SBen Hutchings struct mtd_blktrans_dev mbd; 261da177e4SLinus Torvalds int count; 2748b19268SIngo Molnar struct mutex cache_mutex; 281da177e4SLinus Torvalds unsigned char *cache_data; 291da177e4SLinus Torvalds unsigned long cache_offset; 301da177e4SLinus Torvalds unsigned int cache_size; 311da177e4SLinus Torvalds enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; 32cbfe93e9SBen Hutchings }; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /* 351da177e4SLinus Torvalds * Cache stuff... 361da177e4SLinus Torvalds * 371da177e4SLinus Torvalds * Since typical flash erasable sectors are much larger than what Linux's 381da177e4SLinus Torvalds * buffer cache can handle, we must implement read-modify-write on flash 391da177e4SLinus Torvalds * sectors for each block write requests. To avoid over-erasing flash sectors 401da177e4SLinus Torvalds * and to speed things up, we locally cache a whole flash sector while it is 411da177e4SLinus Torvalds * being written to until a different sector is required. 421da177e4SLinus Torvalds */ 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds static int erase_write (struct mtd_info *mtd, unsigned long pos, 45bafae538Shuijin.park unsigned int len, const char *buf) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds struct erase_info erase; 481da177e4SLinus Torvalds size_t retlen; 491da177e4SLinus Torvalds int ret; 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds /* 521da177e4SLinus Torvalds * First, let's erase the flash block. 531da177e4SLinus Torvalds */ 541da177e4SLinus Torvalds erase.addr = pos; 551da177e4SLinus Torvalds erase.len = len; 561da177e4SLinus Torvalds 577e1f0dc0SArtem Bityutskiy ret = mtd_erase(mtd, &erase); 581da177e4SLinus Torvalds if (ret) { 591da177e4SLinus Torvalds printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] " 601da177e4SLinus Torvalds "on \"%s\" failed\n", 611da177e4SLinus Torvalds pos, len, mtd->name); 621da177e4SLinus Torvalds return ret; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds /* 66dff15509SMatthias Kaehlcke * Next, write the data to flash. 671da177e4SLinus Torvalds */ 681da177e4SLinus Torvalds 69eda95cbfSArtem Bityutskiy ret = mtd_write(mtd, pos, len, &retlen, buf); 701da177e4SLinus Torvalds if (ret) 711da177e4SLinus Torvalds return ret; 721da177e4SLinus Torvalds if (retlen != len) 731da177e4SLinus Torvalds return -EIO; 741da177e4SLinus Torvalds return 0; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds static int write_cached_data (struct mtdblk_dev *mtdblk) 791da177e4SLinus Torvalds { 80cbfe93e9SBen Hutchings struct mtd_info *mtd = mtdblk->mbd.mtd; 811da177e4SLinus Torvalds int ret; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds if (mtdblk->cache_state != STATE_DIRTY) 841da177e4SLinus Torvalds return 0; 851da177e4SLinus Torvalds 86289c0522SBrian Norris pr_debug("mtdblock: writing cached data for \"%s\" " 871da177e4SLinus Torvalds "at 0x%lx, size 0x%x\n", mtd->name, 881da177e4SLinus Torvalds mtdblk->cache_offset, mtdblk->cache_size); 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds ret = erase_write (mtd, mtdblk->cache_offset, 911da177e4SLinus Torvalds mtdblk->cache_size, mtdblk->cache_data); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds /* 9425985edcSLucas De Marchi * Here we could arguably set the cache state to STATE_CLEAN. 951da177e4SLinus Torvalds * However this could lead to inconsistency since we will not 961da177e4SLinus Torvalds * be notified if this content is altered on the flash by other 971da177e4SLinus Torvalds * means. Let's declare it empty and leave buffering tasks to 981da177e4SLinus Torvalds * the buffer cache instead. 995788ccf3SXiaoming Ni * 1005788ccf3SXiaoming Ni * If this cache_offset points to a bad block, data cannot be 1015788ccf3SXiaoming Ni * written to the device. Clear cache_state to avoid writing to 1025788ccf3SXiaoming Ni * bad blocks repeatedly. 1031da177e4SLinus Torvalds */ 1045788ccf3SXiaoming Ni if (ret == 0 || ret == -EIO) 1051da177e4SLinus Torvalds mtdblk->cache_state = STATE_EMPTY; 1065788ccf3SXiaoming Ni return ret; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, 1111da177e4SLinus Torvalds int len, const char *buf) 1121da177e4SLinus Torvalds { 113cbfe93e9SBen Hutchings struct mtd_info *mtd = mtdblk->mbd.mtd; 1141da177e4SLinus Torvalds unsigned int sect_size = mtdblk->cache_size; 1151da177e4SLinus Torvalds size_t retlen; 1161da177e4SLinus Torvalds int ret; 1171da177e4SLinus Torvalds 118289c0522SBrian Norris pr_debug("mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", 1191da177e4SLinus Torvalds mtd->name, pos, len); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds if (!sect_size) 122eda95cbfSArtem Bityutskiy return mtd_write(mtd, pos, len, &retlen, buf); 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds while (len > 0) { 1251da177e4SLinus Torvalds unsigned long sect_start = (pos/sect_size)*sect_size; 1261da177e4SLinus Torvalds unsigned int offset = pos - sect_start; 1271da177e4SLinus Torvalds unsigned int size = sect_size - offset; 1281da177e4SLinus Torvalds if( size > len ) 1291da177e4SLinus Torvalds size = len; 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds if (size == sect_size) { 1321da177e4SLinus Torvalds /* 1331da177e4SLinus Torvalds * We are covering a whole sector. Thus there is no 1341da177e4SLinus Torvalds * need to bother with the cache while it may still be 1351da177e4SLinus Torvalds * useful for other partial writes. 1361da177e4SLinus Torvalds */ 1371da177e4SLinus Torvalds ret = erase_write (mtd, pos, size, buf); 1381da177e4SLinus Torvalds if (ret) 1391da177e4SLinus Torvalds return ret; 1401da177e4SLinus Torvalds } else { 1411da177e4SLinus Torvalds /* Partial sector: need to use the cache */ 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds if (mtdblk->cache_state == STATE_DIRTY && 1441da177e4SLinus Torvalds mtdblk->cache_offset != sect_start) { 1451da177e4SLinus Torvalds ret = write_cached_data(mtdblk); 1461da177e4SLinus Torvalds if (ret) 1471da177e4SLinus Torvalds return ret; 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds if (mtdblk->cache_state == STATE_EMPTY || 1511da177e4SLinus Torvalds mtdblk->cache_offset != sect_start) { 1521da177e4SLinus Torvalds /* fill the cache with the current sector */ 1531da177e4SLinus Torvalds mtdblk->cache_state = STATE_EMPTY; 154329ad399SArtem Bityutskiy ret = mtd_read(mtd, sect_start, sect_size, 155f4a43cfcSThomas Gleixner &retlen, mtdblk->cache_data); 1560c308960SBang Li if (ret && !mtd_is_bitflip(ret)) 1571da177e4SLinus Torvalds return ret; 1581da177e4SLinus Torvalds if (retlen != sect_size) 1591da177e4SLinus Torvalds return -EIO; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds mtdblk->cache_offset = sect_start; 1621da177e4SLinus Torvalds mtdblk->cache_size = sect_size; 1631da177e4SLinus Torvalds mtdblk->cache_state = STATE_CLEAN; 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds /* write data to our local cache */ 1671da177e4SLinus Torvalds memcpy (mtdblk->cache_data + offset, buf, size); 1681da177e4SLinus Torvalds mtdblk->cache_state = STATE_DIRTY; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds buf += size; 1721da177e4SLinus Torvalds pos += size; 1731da177e4SLinus Torvalds len -= size; 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds return 0; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, 1811da177e4SLinus Torvalds int len, char *buf) 1821da177e4SLinus Torvalds { 183cbfe93e9SBen Hutchings struct mtd_info *mtd = mtdblk->mbd.mtd; 1841da177e4SLinus Torvalds unsigned int sect_size = mtdblk->cache_size; 1851da177e4SLinus Torvalds size_t retlen; 1861da177e4SLinus Torvalds int ret; 1871da177e4SLinus Torvalds 188289c0522SBrian Norris pr_debug("mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", 1891da177e4SLinus Torvalds mtd->name, pos, len); 1901da177e4SLinus Torvalds 1910c308960SBang Li if (!sect_size) { 1920c308960SBang Li ret = mtd_read(mtd, pos, len, &retlen, buf); 1930c308960SBang Li if (ret && !mtd_is_bitflip(ret)) 1940c308960SBang Li return ret; 1950c308960SBang Li return 0; 1960c308960SBang Li } 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds while (len > 0) { 1991da177e4SLinus Torvalds unsigned long sect_start = (pos/sect_size)*sect_size; 2001da177e4SLinus Torvalds unsigned int offset = pos - sect_start; 2011da177e4SLinus Torvalds unsigned int size = sect_size - offset; 2021da177e4SLinus Torvalds if (size > len) 2031da177e4SLinus Torvalds size = len; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds /* 2061da177e4SLinus Torvalds * Check if the requested data is already cached 2071da177e4SLinus Torvalds * Read the requested amount of data from our internal cache if it 2081da177e4SLinus Torvalds * contains what we want, otherwise we read the data directly 2091da177e4SLinus Torvalds * from flash. 2101da177e4SLinus Torvalds */ 2111da177e4SLinus Torvalds if (mtdblk->cache_state != STATE_EMPTY && 2121da177e4SLinus Torvalds mtdblk->cache_offset == sect_start) { 2131da177e4SLinus Torvalds memcpy (buf, mtdblk->cache_data + offset, size); 2141da177e4SLinus Torvalds } else { 215329ad399SArtem Bityutskiy ret = mtd_read(mtd, pos, size, &retlen, buf); 2160c308960SBang Li if (ret && !mtd_is_bitflip(ret)) 2171da177e4SLinus Torvalds return ret; 2181da177e4SLinus Torvalds if (retlen != size) 2191da177e4SLinus Torvalds return -EIO; 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds buf += size; 2231da177e4SLinus Torvalds pos += size; 2241da177e4SLinus Torvalds len -= size; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds return 0; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds static int mtdblock_readsect(struct mtd_blktrans_dev *dev, 2311da177e4SLinus Torvalds unsigned long block, char *buf) 2321da177e4SLinus Torvalds { 233cbfe93e9SBen Hutchings struct mtdblk_dev *mtdblk = container_of(dev, struct mtdblk_dev, mbd); 2341da177e4SLinus Torvalds return do_cached_read(mtdblk, block<<9, 512, buf); 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds static int mtdblock_writesect(struct mtd_blktrans_dev *dev, 2381da177e4SLinus Torvalds unsigned long block, char *buf) 2391da177e4SLinus Torvalds { 240cbfe93e9SBen Hutchings struct mtdblk_dev *mtdblk = container_of(dev, struct mtdblk_dev, mbd); 2411da177e4SLinus Torvalds if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) { 242cbfe93e9SBen Hutchings mtdblk->cache_data = vmalloc(mtdblk->mbd.mtd->erasesize); 2431da177e4SLinus Torvalds if (!mtdblk->cache_data) 2441da177e4SLinus Torvalds return -EINTR; 2451da177e4SLinus Torvalds /* -EINTR is not really correct, but it is the best match 2461da177e4SLinus Torvalds * documented in man 2 write for all cases. We could also 2471da177e4SLinus Torvalds * return -EAGAIN sometimes, but why bother? 2481da177e4SLinus Torvalds */ 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds return do_cached_write(mtdblk, block<<9, 512, buf); 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds static int mtdblock_open(struct mtd_blktrans_dev *mbd) 2541da177e4SLinus Torvalds { 255cbfe93e9SBen Hutchings struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); 2561da177e4SLinus Torvalds 257289c0522SBrian Norris pr_debug("mtdblock_open\n"); 2581da177e4SLinus Torvalds 259cbfe93e9SBen Hutchings if (mtdblk->count) { 260cbfe93e9SBen Hutchings mtdblk->count++; 2611da177e4SLinus Torvalds return 0; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds 26496a3295cSBjørn Mork if (mtd_type_is_nand(mbd->mtd)) 26596a3295cSBjørn Mork pr_warn("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n", 26696a3295cSBjørn Mork mbd->tr->name, mbd->mtd->name); 26796a3295cSBjørn Mork 2681da177e4SLinus Torvalds /* OK, it's not open. Create cache info for it */ 2691da177e4SLinus Torvalds mtdblk->count = 1; 27048b19268SIngo Molnar mutex_init(&mtdblk->cache_mutex); 2711da177e4SLinus Torvalds mtdblk->cache_state = STATE_EMPTY; 272cbfe93e9SBen Hutchings if (!(mbd->mtd->flags & MTD_NO_ERASE) && mbd->mtd->erasesize) { 273cbfe93e9SBen Hutchings mtdblk->cache_size = mbd->mtd->erasesize; 2741da177e4SLinus Torvalds mtdblk->cache_data = NULL; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 277289c0522SBrian Norris pr_debug("ok\n"); 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds return 0; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 282a8ca889eSAl Viro static void mtdblock_release(struct mtd_blktrans_dev *mbd) 2831da177e4SLinus Torvalds { 284cbfe93e9SBen Hutchings struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); 2851da177e4SLinus Torvalds 286289c0522SBrian Norris pr_debug("mtdblock_release\n"); 2871da177e4SLinus Torvalds 28848b19268SIngo Molnar mutex_lock(&mtdblk->cache_mutex); 2891da177e4SLinus Torvalds write_cached_data(mtdblk); 29048b19268SIngo Molnar mutex_unlock(&mtdblk->cache_mutex); 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds if (!--mtdblk->count) { 29370d5098aSAlexander Stein /* 29470d5098aSAlexander Stein * It was the last usage. Free the cache, but only sync if 29570d5098aSAlexander Stein * opened for writing. 29670d5098aSAlexander Stein */ 297*658afed1SChristoph Hellwig if (mbd->writable) 29885f2f2a8SArtem Bityutskiy mtd_sync(mbd->mtd); 2991da177e4SLinus Torvalds vfree(mtdblk->cache_data); 3001da177e4SLinus Torvalds } 301d676c117SMatthias Kaehlcke 302289c0522SBrian Norris pr_debug("ok\n"); 3031da177e4SLinus Torvalds } 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds static int mtdblock_flush(struct mtd_blktrans_dev *dev) 3061da177e4SLinus Torvalds { 307cbfe93e9SBen Hutchings struct mtdblk_dev *mtdblk = container_of(dev, struct mtdblk_dev, mbd); 3084e4a9a82SXiaoming Ni int ret; 3091da177e4SLinus Torvalds 31048b19268SIngo Molnar mutex_lock(&mtdblk->cache_mutex); 3114e4a9a82SXiaoming Ni ret = write_cached_data(mtdblk); 31248b19268SIngo Molnar mutex_unlock(&mtdblk->cache_mutex); 31385f2f2a8SArtem Bityutskiy mtd_sync(dev->mtd); 3144e4a9a82SXiaoming Ni return ret; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) 3181da177e4SLinus Torvalds { 319cbfe93e9SBen Hutchings struct mtdblk_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds if (!dev) 3221da177e4SLinus Torvalds return; 3231da177e4SLinus Torvalds 324cbfe93e9SBen Hutchings dev->mbd.mtd = mtd; 325cbfe93e9SBen Hutchings dev->mbd.devnum = mtd->index; 32619187672SRichard Purdie 327cbfe93e9SBen Hutchings dev->mbd.size = mtd->size >> 9; 328cbfe93e9SBen Hutchings dev->mbd.tr = tr; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds if (!(mtd->flags & MTD_WRITEABLE)) 331cbfe93e9SBen Hutchings dev->mbd.readonly = 1; 3321da177e4SLinus Torvalds 333298304f1SMaxim Levitsky if (add_mtd_blktrans_dev(&dev->mbd)) 334298304f1SMaxim Levitsky kfree(dev); 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) 3381da177e4SLinus Torvalds { 3391da177e4SLinus Torvalds del_mtd_blktrans_dev(dev); 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds static struct mtd_blktrans_ops mtdblock_tr = { 3431da177e4SLinus Torvalds .name = "mtdblock", 3442aabeb20SEzequiel Garcia .major = MTD_BLOCK_MAJOR, 3451da177e4SLinus Torvalds .part_bits = 0, 34619187672SRichard Purdie .blksize = 512, 3471da177e4SLinus Torvalds .open = mtdblock_open, 3481da177e4SLinus Torvalds .flush = mtdblock_flush, 3491da177e4SLinus Torvalds .release = mtdblock_release, 3501da177e4SLinus Torvalds .readsect = mtdblock_readsect, 3511da177e4SLinus Torvalds .writesect = mtdblock_writesect, 3521da177e4SLinus Torvalds .add_mtd = mtdblock_add_mtd, 3531da177e4SLinus Torvalds .remove_dev = mtdblock_remove_dev, 3541da177e4SLinus Torvalds .owner = THIS_MODULE, 3551da177e4SLinus Torvalds }; 3561da177e4SLinus Torvalds 35727b08bf3SDejin Zheng module_mtd_blktrans(mtdblock_tr); 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3602f82af08SNicolas Pitre MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net> et al."); 3611da177e4SLinus Torvalds MODULE_DESCRIPTION("Caching read/erase/writeback block device emulation access to MTD devices"); 362