--- zzzz-none-000/linux-5.15.111/drivers/mtd/devices/block2mtd.c 2023-05-11 14:00:40.000000000 +0000 +++ puma7-atom-6670-761/linux-5.15.111/drivers/mtd/devices/block2mtd.c 2024-02-07 10:23:07.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_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,34 @@ 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 + mutex_lock(&dev->write_mutex); err = _block2mtd_erase(dev, from, len); mutex_unlock(&dev->write_mutex); @@ -97,6 +136,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) @@ -107,6 +168,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 @@ -178,6 +244,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); @@ -191,10 +262,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) { @@ -296,6 +410,10 @@ dev->mtd._read = block2mtd_read; dev->mtd.priv = dev; dev->mtd.owner = THIS_MODULE; +#ifdef CONFIG_TFFS_PANIC_LOG + dev->mtd.dev.parent = &bdev->bd_device; + 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 */