Skip to content
Permalink
Browse files
mmc: Support kmsg dumper based on pstore/blk
This patch introduces to mmcpstore. The functioning of mmcpstore is
is similar to mtdpstore. mmcpstore works on FTL based flash devices
whereas mtdpstore works on raw flash devices. When the system crashes,
mmcpstore stores the kmsg panic and oops logs to a user specified
MMC device.

It collects the details about the host MMC device through pstore/blk
"blkdev" parameter. The user can specify the MMC device in many ways
by checking in Documentation/admin-guide/pstore-blk.rst.

The individual mmc host drivers have to define suitable polling
subroutines to write kmsg panic/oops logs through mmcpstore.

Signed-off-by: Bhaskara Budiredla <bbudiredla@marvell.com>
  • Loading branch information
Bhaskara Budiredla authored and intel-lab-lkp committed Nov 12, 2020
1 parent 3d5e28b commit fcb0b29143a613365939640cb07f0285fdab9a1f
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 0 deletions.
@@ -81,3 +81,10 @@ config MMC_TEST
This driver is only of interest to those developing or
testing a host driver. Most people should say N here.

config MMC_PSTORE
bool "Log panic/oops to a MMC buffer"
depends on PSTORE
depends on PSTORE_BLK
help
Backend driver to store the kmsg crash dumps to a user specified MMC
device. The driver is based on pstore/blk.
@@ -17,4 +17,5 @@ mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
obj-$(CONFIG_MMC_TEST) += mmc_test.o
obj-$(CONFIG_MMC_PSTORE) += mmcpstore.o
obj-$(CONFIG_SDIO_UART) += sdio_uart.o
@@ -2870,6 +2870,21 @@ static void mmc_blk_remove_debugfs(struct mmc_card *card,

#endif /* CONFIG_DEBUG_FS */

#ifdef CONFIG_MMC_PSTORE
sector_t mmc_blk_get_part(struct mmc_card *card, int part_num, sector_t *size)
{
struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
struct gendisk *disk = md->disk;
struct disk_part_tbl *part_tbl = disk->part_tbl;

if (part_num < 0 || part_num >= part_tbl->len)
return 0;

*size = part_tbl->part[part_num]->nr_sects << SECTOR_SHIFT;
return part_tbl->part[part_num]->start_sect;
}
#endif

static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md, *part_md;
@@ -2913,6 +2928,11 @@ static int mmc_blk_probe(struct mmc_card *card)
goto out;
}

#ifdef CONFIG_MMC_PSTORE
if (mmc_card_mmc(card) || mmc_card_sd(card))
mmcpstore_card_set(card, md->disk->disk_name);
#endif

/* Add two debugfs entries */
mmc_blk_add_debugfs(card, md);

@@ -16,5 +16,8 @@ void mmc_blk_mq_recovery(struct mmc_queue *mq);
struct work_struct;

void mmc_blk_mq_complete_work(struct work_struct *work);
#ifdef CONFIG_MMC_PSTORE
sector_t mmc_blk_get_part(struct mmc_card *card, int part_num, sector_t *size);
#endif

#endif
@@ -569,6 +569,30 @@ int mmc_cqe_recovery(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_cqe_recovery);


#ifdef CONFIG_MMC_PSTORE
/**
* mmc_wait_for_pstore_req - initiate a blocking mmc request
* @host: MMC host to start command
* @mrq: MMC request to start
*
* Start a new MMC custom command request for a host, and
* wait for the command to complete based on request data timeout.
*/
void mmc_wait_for_pstore_req(struct mmc_host *host, struct mmc_request *mrq)
{
unsigned int timeout;

host->ops->req_cleanup_pending(host);
mmc_start_request(host, mrq);

if (mrq->data) {
timeout = mrq->data->timeout_ns / NSEC_PER_MSEC;
host->ops->req_completion_poll(host, timeout);
}
}
#endif

/**
* mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
* @host: MMC host

0 comments on commit fcb0b29

Please sign in to comment.