[Feature][T8TSK-48][TCAM_T800_SW_261] add emmc health interface
Change-Id: I23caddce7d76c067a3661d7cfc29c027668fc2fa
diff --git a/src/kernel/linux/v4.19/arch/arm64/configs/auto2735evb_defconfig b/src/kernel/linux/v4.19/arch/arm64/configs/auto2735evb_defconfig
index cb84b4f..335e5da 100644
--- a/src/kernel/linux/v4.19/arch/arm64/configs/auto2735evb_defconfig
+++ b/src/kernel/linux/v4.19/arch/arm64/configs/auto2735evb_defconfig
@@ -807,3 +807,7 @@
#dongyu@2022.7.12 modify for RTC/PCF85063 start
CONFIG_RTC_DRV_PCF85063=y
#dongyu@2022.7.12 modify for RTC/PCF85063 end
+
+#you.chen@2022-07-16 for emmc health
+CONFIG_MMC_HEALTH=y
+
diff --git a/src/kernel/linux/v4.19/drivers/mmc/core/block.c b/src/kernel/linux/v4.19/drivers/mmc/core/block.c
index 87cfd13..e5566bd 100644
--- a/src/kernel/linux/v4.19/drivers/mmc/core/block.c
+++ b/src/kernel/linux/v4.19/drivers/mmc/core/block.c
@@ -139,6 +139,11 @@
/* debugfs files (only in main mmc_blk_data) */
struct dentry *status_dentry;
struct dentry *ext_csd_dentry;
+//you.chen@2022-07-16 for emmc health begin
+#ifdef CONFIG_MMC_HEALTH
+ struct dentry *health_dentry;
+#endif
+//you.chen@2022-07-16 for emmc health end
};
/* Device type for RPMB character devices */
@@ -1079,6 +1084,14 @@
ext_csd = mq_rq->drv_op_data;
ret = mmc_get_ext_csd(card, ext_csd);
break;
+//you.chen@2022-07-16 for emmc health begin
+#ifdef CONFIG_MMC_HEALTH
+ case MMC_DRV_OP_GET_HEALTH:
+ ext_csd = mq_rq->drv_op_data;
+ ret = mmc_get_health(card, ext_csd);
+ break;
+#endif
+//you.chen@2022-07-16 for emmc health end
default:
pr_err("%s: unknown driver specific operation\n",
md->disk->disk_name);
@@ -3074,6 +3087,96 @@
.llseek = default_llseek,
};
+//you.chen@2022-07-16 for emmc health begin
+#ifdef CONFIG_MMC_HEALTH
+#define HEALTH_STR_LEN 14
+static int mmc_health_open(struct inode *inode, struct file *filp)
+{
+ struct mmc_card *card = inode->i_private;
+ struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
+ struct mmc_queue *mq = &md->queue;
+ struct request *req;
+ char *buf;
+ u8 *ext_csd;
+ int err;
+ ssize_t n;
+ unsigned int amount, health;
+
+ //printk("cy-health open\n");
+ buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* Ask the block layer for the EXT CSD */
+ req = blk_get_request(mq->queue, REQ_OP_DRV_IN, 0);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto out_free;
+ }
+ req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_HEALTH;
+ req_to_mmc_queue_req(req)->drv_op_data = &ext_csd;
+ //printk("cy- blk_execute_rq begin\n");
+ blk_execute_rq(mq->queue, NULL, req, 0);
+ //printk("cy- blk_execute_rq end\n");
+ err = req_to_mmc_queue_req(req)->drv_op_result;
+ //printk("cy-blk_put_request begin\n");
+ blk_put_request(req);
+ //printk("cy-blk_put_request end\n");
+ if (err) {
+ pr_err("FAILED %d\n", err);
+ goto out_free;
+ }
+
+ memcpy(&amount, ext_csd + 64, 4);
+ memcpy(&health, ext_csd + 184, 4);
+ if (health > 100) {
+ pr_err("Health [%d] large than 100\n", health);
+ health = 100;
+ }
+
+ n = sprintf(buf, "%010u-%03u", amount*100, health);
+
+ if (n != HEALTH_STR_LEN) {
+ printk("cy-bad count %d , %d\n", (int)n , HEALTH_STR_LEN);
+ err = -EINVAL;
+ kfree(ext_csd);
+ goto out_free;
+ }
+
+ filp->private_data = buf;
+ kfree(ext_csd);
+ return 0;
+
+out_free:
+ kfree(buf);
+ return err;
+}
+
+static ssize_t mmc_health_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ char *buf = filp->private_data;
+
+ //printk("cy-mmc_ext_csd_read\n");
+ return simple_read_from_buffer(ubuf, cnt, ppos,
+ buf, HEALTH_STR_LEN);
+}
+
+static int mmc_health_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations mmc_dbg_health_fops = {
+ .open = mmc_health_open,
+ .read = mmc_health_read,
+ .release = mmc_health_release,
+ .llseek = default_llseek,
+};
+#endif
+//you.chen@2022-07-16 for emmc health end
+
static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md)
{
struct dentry *root;
@@ -3099,6 +3202,15 @@
return -EIO;
}
+//you.chen@2022-07-16 for emmc health begin
+#ifdef CONFIG_MMC_HEALTH
+ if (mmc_card_mmc(card)) {
+ md->health_dentry=
+ debugfs_create_file("health", S_IRUSR, root, card,
+ &mmc_dbg_health_fops);
+ }
+#endif
+//you.chen@2022-07-16 for emmc health end
return 0;
}
@@ -3117,6 +3229,15 @@
debugfs_remove(md->ext_csd_dentry);
md->ext_csd_dentry = NULL;
}
+
+//you.chen@2022-07-16 for emmc health begin
+#ifdef CONFIG_MMC_HEALTH
+ if (!IS_ERR_OR_NULL(md->health_dentry)) {
+ debugfs_remove(md->health_dentry);
+ md->health_dentry= NULL;
+ }
+#endif
+//you.chen@2022-07-16 for emmc health end
}
#else
diff --git a/src/kernel/linux/v4.19/drivers/mmc/core/mmc_ops.c b/src/kernel/linux/v4.19/drivers/mmc/core/mmc_ops.c
index 873b2aa..fa04e2f 100644
--- a/src/kernel/linux/v4.19/drivers/mmc/core/mmc_ops.c
+++ b/src/kernel/linux/v4.19/drivers/mmc/core/mmc_ops.c
@@ -381,6 +381,60 @@
}
EXPORT_SYMBOL_GPL(mmc_get_ext_csd);
+//you.chen@2022-07-16 for emmc health begin
+#ifdef CONFIG_MMC_HEALTH
+int mmc_get_health(struct mmc_card *card, u8 **new_health)
+{
+ int err;
+ u8 *ext_csd;
+
+ struct mmc_host *host = card->host;
+ struct mmc_command cmd = {};
+
+
+ if (!card || !new_health)
+ return -EINVAL;
+
+
+ /*
+ * As the ext_csd is so large and mostly unused, we don't store the
+ * raw block in mmc_card.
+ */
+ ext_csd = kzalloc(512, GFP_KERNEL);
+ if (!ext_csd)
+ return -ENOMEM;
+
+ mmc_retune_hold(host);
+
+ cmd.opcode = 62;
+ cmd.arg = 0x96C9D71C;
+ cmd.flags = MMC_CMD_AC;
+ cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+ cmd.busy_timeout = 1000;
+
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err)
+ {
+ //printk("cy2-return error 62\n");
+ mmc_retune_release(host);
+ return err;
+ }
+
+ err = mmc_send_cxd_data(card, card->host, 63, ext_csd,
+ 512);
+ if (err)
+ kfree(ext_csd);
+ else
+ *new_health = ext_csd;
+
+ mmc_retune_release(host);
+ //printk("cy2-return\n");
+ return err;
+}
+EXPORT_SYMBOL_GPL(mmc_get_health);
+#endif
+//you.chen@2022-07-16 for emmc health end
+
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
{
struct mmc_command cmd = {};
diff --git a/src/kernel/linux/v4.19/drivers/mmc/core/mmc_ops.h b/src/kernel/linux/v4.19/drivers/mmc/core/mmc_ops.h
index a1390d4..0bd4025 100644
--- a/src/kernel/linux/v4.19/drivers/mmc/core/mmc_ops.h
+++ b/src/kernel/linux/v4.19/drivers/mmc/core/mmc_ops.h
@@ -33,6 +33,11 @@
int mmc_interrupt_hpi(struct mmc_card *card);
int mmc_can_ext_csd(struct mmc_card *card);
int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
+//you.chen@2022-07-16 for emmc health begin
+#ifdef CONFIG_MMC_HEALTH
+int mmc_get_health(struct mmc_card *card, u8 **new_heath);
+#endif
+//you.chen@2022-07-16 for emmc health end
int mmc_switch_status(struct mmc_card *card);
int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
diff --git a/src/kernel/linux/v4.19/drivers/mmc/core/queue.h b/src/kernel/linux/v4.19/drivers/mmc/core/queue.h
index 9bf3c92..32ab77f 100644
--- a/src/kernel/linux/v4.19/drivers/mmc/core/queue.h
+++ b/src/kernel/linux/v4.19/drivers/mmc/core/queue.h
@@ -59,6 +59,11 @@
MMC_DRV_OP_BOOT_WP,
MMC_DRV_OP_GET_CARD_STATUS,
MMC_DRV_OP_GET_EXT_CSD,
+//you.chen@2022-07-16 for emmc health begin
+#ifdef CONFIG_MMC_HEALTH
+ MMC_DRV_OP_GET_HEALTH,
+#endif
+//you.chen@2022-07-16 for emmc health end
};
struct mmc_queue_req {
diff --git a/src/kernel/linux/v4.19/drivers/mmc/host/Kconfig b/src/kernel/linux/v4.19/drivers/mmc/host/Kconfig
index cae1c5a..43ea78c 100644
--- a/src/kernel/linux/v4.19/drivers/mmc/host/Kconfig
+++ b/src/kernel/linux/v4.19/drivers/mmc/host/Kconfig
@@ -952,3 +952,10 @@
If you have a controller with this interface, say Y or M here.
If unsure, say N.
+
+config MMC_HEALTH
+ tristate "SD/MMC Card Health Interface support"
+ depends on MMC_MTK
+ help
+ This selects the card health Interface.
+