--- zzzz-none-000/linux-4.9.279/drivers/mtd/devices/block2mtd.c 2021-08-08 06:38:54.000000000 +0000 +++ puma7-atom-6591-750/linux-4.9.279/drivers/mtd/devices/block2mtd.c 2023-02-08 11:43:42.000000000 +0000 @@ -30,6 +30,8 @@ #include #include #include +#include +#include /* Info for the block device */ struct block2mtd_dev { @@ -37,6 +39,9 @@ struct block_device *blkdev; struct mtd_info mtd; struct mutex write_mutex; +#if defined(CONFIG_TFFS_PANIC_LOG) + bool in_panic; // AVM: Set for synchronous access +#endif }; @@ -81,6 +86,12 @@ } return 0; } + +static sector_t to_sector(const struct block_device *bdev, loff_t off) +{ + return bdev->bd_part->start_sect + (off >> 9); +} + static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { struct block2mtd_dev *dev = mtd->priv; @@ -88,6 +99,33 @@ size_t len = instr->len; int err; +#if defined(CONFIG_TFFS_PANIC_LOG) + if (dev->in_panic) { + struct block_device *bdev = dev->blkdev; + struct mmc_host *mmc; + u8 erasedblock[512]; + sector_t sect; + size_t blocks; + + mmc = mmc_blk_get_host(bdev->bd_disk); + if (IS_ERR_OR_NULL(mmc)) + return -ENODEV; + + memset(erasedblock, 0xFF, sizeof(erasedblock)); + blocks = DIV_ROUND_UP(len, sizeof(erasedblock)); + sect = to_sector(bdev, from); + + while (blocks) { + err = mmc->ops->avm_sync_io_rw_blocks(mmc, sect, + sizeof(erasedblock), erasedblock, NULL); + if (err) + break; + --blocks; + ++sect; + } + return err; + } +#endif instr->state = MTD_ERASING; mutex_lock(&dev->write_mutex); err = _block2mtd_erase(dev, from, len); @@ -102,6 +140,28 @@ return err; } +#ifdef CONFIG_TFFS_PANIC_LOG +static int block2mtd_sync_io_blocks(struct block2mtd_dev *dev, loff_t off, size_t len, + size_t *retlen, u_char *in, const u_char *out) +{ + struct block_device *bdev = dev->blkdev; + struct mmc_host *mmc; + int ret; + + if (!dev->in_panic) + return -EBUSY; + + mmc = mmc_blk_get_host(bdev->bd_disk); + if (IS_ERR_OR_NULL(mmc)) + return -ENODEV; + + ret = mmc->ops->avm_sync_io_rw_blocks(mmc, to_sector(bdev, off), + len, in, out); + if (retlen) + *retlen = ret ? 0 : len; + return ret; +} +#endif static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) @@ -112,6 +172,11 @@ int offset = from & (PAGE_SIZE-1); int cpylen; +#if defined(CONFIG_TFFS_PANIC_LOG) + if (dev->in_panic) + return block2mtd_sync_io_blocks(dev, from, len, retlen, + buf, NULL); +#endif while (len) { if ((offset + len) > PAGE_SIZE) cpylen = PAGE_SIZE - offset; // multiple pages @@ -183,6 +248,11 @@ struct block2mtd_dev *dev = mtd->priv; int err; +#if defined(CONFIG_TFFS_PANIC_LOG) + if (dev->in_panic) + return block2mtd_sync_io_blocks(dev, to, len, retlen, + NULL, buf); +#endif mutex_lock(&dev->write_mutex); err = _block2mtd_write(dev, buf, to, len, retlen); mutex_unlock(&dev->write_mutex); @@ -196,10 +266,53 @@ static void block2mtd_sync(struct mtd_info *mtd) { struct block2mtd_dev *dev = mtd->priv; + +#if defined(CONFIG_TFFS_PANIC_LOG) + /* We are always synced in panic. */ + if (dev->in_panic) + return; +#endif sync_blockdev(dev->blkdev); return; } +#if defined(CONFIG_TFFS_PANIC_LOG) +/* + * Call this to start using synchronous low level read/write functions in case + * of panic. + * + * Note: This only works if the bdev attached to this block2mtd is a emmc + * flash with sdhci host. + */ +static struct mtd_info *block2mtd_sync_io_init(struct mtd_info *mtd) +{ + struct block2mtd_dev *dev = mtd->priv; + struct gendisk *disk = dev->blkdev->bd_disk; + struct mmc_host *mmc; + + mmc = mmc_blk_get_host(disk); + if (IS_ERR_OR_NULL(mmc)) + return NULL; + + if (!mmc->ops->avm_sync_io_init || !mmc->ops->avm_sync_io_rw_blocks || + !mmc->ops->avm_sync_io_init) { + dev_err(disk_to_dev(disk), + "%s: disk driver does not support " + "synchronous panic I/O\n", + __func__); + return NULL; + } + + /* If this fails we might as well crash... */ + if (mmc->ops->avm_sync_io_init(mmc)) + return NULL; + + dev->in_panic = true; + + return mtd; +} +#endif + static void block2mtd_free_device(struct block2mtd_dev *dev) { @@ -301,6 +414,10 @@ dev->mtd._read = block2mtd_read; dev->mtd.priv = dev; dev->mtd.owner = THIS_MODULE; +#ifdef CONFIG_TFFS_PANIC_LOG + dev->mtd.dev.parent = part_to_dev(bdev->bd_part); + dev->mtd.avm_sync_io_init = block2mtd_sync_io_init; +#endif if (mtd_device_register(&dev->mtd, NULL, 0)) { /* Device didn't get added, so free the entry */ @@ -321,7 +438,6 @@ return NULL; } - /* This function works similar to reguler strtoul. In addition, it * allows some suffixes for a more human-readable number format: * ki, Ki, kiB, KiB - multiply result with 1024 @@ -430,7 +546,6 @@ return 0; } - static int block2mtd_setup(const char *val, struct kernel_param *kp) { #ifdef MODULE