summaryrefslogtreecommitdiff
path: root/drivers/mmc/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/Kconfig13
-rw-r--r--drivers/mmc/core/Makefile6
-rw-r--r--drivers/mmc/core/block.c3165
-rw-r--r--drivers/mmc/core/block.h13
-rw-r--r--drivers/mmc/core/bus.c139
-rw-r--r--drivers/mmc/core/bus.h12
-rw-r--r--drivers/mmc/core/card.h119
-rw-r--r--drivers/mmc/core/core.c1464
-rw-r--r--drivers/mmc/core/core.h150
-rw-r--r--drivers/mmc/core/crypto.c44
-rw-r--r--drivers/mmc/core/crypto.h40
-rw-r--r--drivers/mmc/core/debugfs.c271
-rw-r--r--drivers/mmc/core/host.c365
-rw-r--r--drivers/mmc/core/host.h36
-rw-r--r--drivers/mmc/core/mmc.c745
-rw-r--r--drivers/mmc/core/mmc_ops.c653
-rw-r--r--drivers/mmc/core/mmc_ops.h55
-rw-r--r--drivers/mmc/core/mmc_test.c531
-rw-r--r--drivers/mmc/core/pwrseq.c5
-rw-r--r--drivers/mmc/core/pwrseq.h3
-rw-r--r--drivers/mmc/core/pwrseq_emmc.c46
-rw-r--r--drivers/mmc/core/pwrseq_sd8787.c49
-rw-r--r--drivers/mmc/core/pwrseq_simple.c77
-rw-r--r--drivers/mmc/core/queue.c691
-rw-r--r--drivers/mmc/core/queue.h83
-rw-r--r--drivers/mmc/core/quirks.h159
-rw-r--r--drivers/mmc/core/regulator.c432
-rw-r--r--drivers/mmc/core/sd.c983
-rw-r--r--drivers/mmc/core/sd.h7
-rw-r--r--drivers/mmc/core/sd_ops.c233
-rw-r--r--drivers/mmc/core/sd_ops.h15
-rw-r--r--drivers/mmc/core/sd_uhs2.c1304
-rw-r--r--drivers/mmc/core/sdio.c472
-rw-r--r--drivers/mmc/core/sdio_bus.c127
-rw-r--r--drivers/mmc/core/sdio_bus.h6
-rw-r--r--drivers/mmc/core/sdio_cis.c57
-rw-r--r--drivers/mmc/core/sdio_cis.h6
-rw-r--r--drivers/mmc/core/sdio_io.c115
-rw-r--r--drivers/mmc/core/sdio_irq.c97
-rw-r--r--drivers/mmc/core/sdio_ops.c45
-rw-r--r--drivers/mmc/core/sdio_ops.h7
-rw-r--r--drivers/mmc/core/sdio_uart.c112
-rw-r--r--drivers/mmc/core/slot-gpio.c267
-rw-r--r--drivers/mmc/core/slot-gpio.h3
44 files changed, 8852 insertions, 4370 deletions
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 42e89060cd41..14d2ecbb04d3 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# MMC core configuration
#
@@ -14,7 +15,7 @@ config PWRSEQ_EMMC
config PWRSEQ_SD8787
tristate "HW reset support for SD8787 BT + Wifi module"
- depends on OF && (MWIFIEX || BT_MRVL_SDIO)
+ depends on OF && (MWIFIEX != n || BT_MRVL_SDIO != n || LIBERTAS_SDIO != n || WILC1000_SDIO != n)
help
This selects hardware reset support for the SD8787 BT + Wifi
module. By default this option is set to n.
@@ -36,6 +37,8 @@ config PWRSEQ_SIMPLE
config MMC_BLOCK
tristate "MMC block device driver"
depends on BLOCK
+ depends on RPMB || !RPMB
+ imply IOSCHED_BFQ
default y
help
Say Y here to enable the MMC block device driver support.
@@ -80,3 +83,11 @@ 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_CRYPTO
+ bool "MMC Crypto Engine Support"
+ depends on BLK_INLINE_ENCRYPTION
+ help
+ Enable Crypto Engine Support in MMC.
+ Enabling this makes it possible for the kernel to use the crypto
+ capabilities of the MMC device (if present) to perform crypto
+ operations on data being transferred to/from the device.
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 7e3ed1aeada2..15b067e8b0d1 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the kernel mmc core.
#
@@ -6,8 +7,8 @@ obj-$(CONFIG_MMC) += mmc_core.o
mmc_core-y := core.o bus.o host.o \
mmc.o mmc_ops.o sd.o sd_ops.o \
sdio.o sdio_ops.o sdio_bus.o \
- sdio_cis.o sdio_io.o sdio_irq.o \
- slot-gpio.o
+ sdio_cis.o sdio_io.o sdio_irq.o sd_uhs2.o\
+ slot-gpio.o regulator.o
mmc_core-$(CONFIG_OF) += pwrseq.o
obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o
obj-$(CONFIG_PWRSEQ_SD8787) += pwrseq_sd8787.o
@@ -17,3 +18,4 @@ obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
obj-$(CONFIG_MMC_TEST) += mmc_test.o
obj-$(CONFIG_SDIO_UART) += sdio_uart.o
+mmc_core-$(CONFIG_MMC_CRYPTO) += crypto.o
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index e5938c791330..fb6eb2d79b4f 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Block driver for media (i.e., flash cards)
*
@@ -27,15 +28,20 @@
#include <linux/errno.h>
#include <linux/hdreg.h>
#include <linux/kdev_t.h>
+#include <linux/kref.h>
#include <linux/blkdev.h>
+#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/scatterlist.h>
+#include <linux/string.h>
#include <linux/string_helpers.h>
#include <linux/delay.h>
#include <linux/capability.h>
#include <linux/compat.h>
#include <linux/pm_runtime.h>
#include <linux/idr.h>
+#include <linux/debugfs.h>
+#include <linux/rpmb.h>
#include <linux/mmc/ioctl.h>
#include <linux/mmc/card.h>
@@ -44,11 +50,13 @@
#include <linux/mmc/sd.h>
#include <linux/uaccess.h>
+#include <linux/unaligned.h>
#include "queue.h"
#include "block.h"
#include "core.h"
#include "card.h"
+#include "crypto.h"
#include "host.h"
#include "bus.h"
#include "mmc_ops.h"
@@ -61,12 +69,20 @@ MODULE_ALIAS("mmc:block");
#endif
#define MODULE_PARAM_PREFIX "mmcblk."
-#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
-#define MMC_SANITIZE_REQ_TIMEOUT 240000
+/*
+ * Set a 10 second timeout for polling write request busy state. Note, mmc core
+ * is setting a 3 second timeout for SD cards, and SDHCI has long had a 10
+ * second software timer to timeout the whole request, so 10 seconds should be
+ * ample.
+ */
+#define MMC_BLK_TIMEOUT_MS (10 * 1000)
#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
+#define MMC_EXTRACT_VALUE_FROM_ARG(x) ((x & 0x0000FF00) >> 8)
+
+#define RPMB_FRAME_SIZE sizeof(struct rpmb_frame)
+#define CHECK_SIZE_NEQ(val) ((val) != sizeof(struct rpmb_frame))
+#define CHECK_SIZE_ALIGNED(val) IS_ALIGNED((val), sizeof(struct rpmb_frame))
-#define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \
- (rq_data_dir(req) == WRITE))
static DEFINE_MUTEX(block_mutex);
/*
@@ -85,22 +101,28 @@ static int max_devices;
#define MAX_DEVICES 256
static DEFINE_IDA(mmc_blk_ida);
+static DEFINE_IDA(mmc_rpmb_ida);
+
+struct mmc_blk_busy_data {
+ struct mmc_card *card;
+ u32 status;
+};
/*
* There is one mmc_blk_data per slot.
*/
struct mmc_blk_data {
- spinlock_t lock;
struct device *parent;
struct gendisk *disk;
struct mmc_queue queue;
struct list_head part;
+ struct list_head rpmbs;
unsigned int flags;
#define MMC_BLK_CMD23 (1 << 0) /* Can do SET_BLOCK_COUNT for multiblock */
#define MMC_BLK_REL_WR (1 << 1) /* MMC Reliable write support */
- unsigned int usage;
+ struct kref kref;
unsigned int read_only;
unsigned int part_type;
unsigned int reset_done;
@@ -108,6 +130,8 @@ struct mmc_blk_data {
#define MMC_BLK_WRITE BIT(1)
#define MMC_BLK_DISCARD BIT(2)
#define MMC_BLK_SECDISCARD BIT(3)
+#define MMC_BLK_CQE_RECOVERY BIT(4)
+#define MMC_BLK_TRIM BIT(5)
/*
* Only set in main mmc_blk_data associated
@@ -115,9 +139,40 @@ struct mmc_blk_data {
* track of the current selected device partition.
*/
unsigned int part_curr;
- struct device_attribute force_ro;
- struct device_attribute power_ro_lock;
+#define MMC_BLK_PART_INVALID UINT_MAX /* Unknown partition active */
int area_type;
+
+ /* debugfs files (only in main mmc_blk_data) */
+ struct dentry *status_dentry;
+ struct dentry *ext_csd_dentry;
+};
+
+/* Device type for RPMB character devices */
+static dev_t mmc_rpmb_devt;
+
+/* Bus type for RPMB character devices */
+static const struct bus_type mmc_rpmb_bus_type = {
+ .name = "mmc_rpmb",
+};
+
+/**
+ * struct mmc_rpmb_data - special RPMB device type for these areas
+ * @dev: the device for the RPMB area
+ * @chrdev: character device for the RPMB area
+ * @id: unique device ID number
+ * @part_index: partition index (0 on first)
+ * @md: parent MMC block device
+ * @rdev: registered RPMB device
+ * @node: list item, so we can put this device on a list
+ */
+struct mmc_rpmb_data {
+ struct device dev;
+ struct cdev chrdev;
+ int id;
+ unsigned int part_index;
+ struct mmc_blk_data *md;
+ struct rpmb_dev *rdev;
+ struct list_head node;
};
static DEFINE_MUTEX(open_lock);
@@ -126,7 +181,14 @@ module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
static inline int mmc_blk_part_switch(struct mmc_card *card,
- struct mmc_blk_data *md);
+ unsigned int part_type);
+static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+ struct mmc_card *card,
+ int recovery_mode,
+ struct mmc_queue *mq);
+static void mmc_blk_hsq_req_done(struct mmc_request *mrq);
+static int mmc_spi_err_check(struct mmc_card *card);
+static int mmc_blk_busy_cb(void *cb_data, bool *busy);
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
@@ -134,10 +196,8 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
mutex_lock(&open_lock);
md = disk->private_data;
- if (md && md->usage == 0)
+ if (md && !kref_get_unless_zero(&md->kref))
md = NULL;
- if (md)
- md->usage++;
mutex_unlock(&open_lock);
return md;
@@ -149,18 +209,25 @@ static inline int mmc_get_devidx(struct gendisk *disk)
return devidx;
}
-static void mmc_blk_put(struct mmc_blk_data *md)
+static void mmc_blk_kref_release(struct kref *ref)
{
+ struct mmc_blk_data *md = container_of(ref, struct mmc_blk_data, kref);
+ int devidx;
+
+ devidx = mmc_get_devidx(md->disk);
+ ida_free(&mmc_blk_ida, devidx);
+
mutex_lock(&open_lock);
- md->usage--;
- if (md->usage == 0) {
- int devidx = mmc_get_devidx(md->disk);
- blk_cleanup_queue(md->queue.queue);
- ida_simple_remove(&mmc_blk_ida, devidx);
- put_disk(md->disk);
- kfree(md);
- }
+ md->disk->private_data = NULL;
mutex_unlock(&open_lock);
+
+ put_disk(md->disk);
+ kfree(md);
+}
+
+static void mmc_blk_put(struct mmc_blk_data *md)
+{
+ kref_put(&md->kref, mmc_blk_kref_release);
}
static ssize_t power_ro_lock_show(struct device *dev,
@@ -176,7 +243,7 @@ static ssize_t power_ro_lock_show(struct device *dev,
else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
locked = 1;
- ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
+ ret = sysfs_emit(buf, "%d\n", locked);
mmc_blk_put(md);
@@ -188,7 +255,6 @@ static ssize_t power_ro_lock_store(struct device *dev,
{
int ret;
struct mmc_blk_data *md, *part_md;
- struct mmc_card *card;
struct mmc_queue *mq;
struct request *req;
unsigned long set;
@@ -201,13 +267,18 @@ static ssize_t power_ro_lock_store(struct device *dev,
md = mmc_blk_get(dev_to_disk(dev));
mq = &md->queue;
- card = md->queue.card;
/* Dispatch locking to the block layer */
- req = blk_get_request(mq->queue, REQ_OP_DRV_OUT, __GFP_RECLAIM);
+ req = blk_mq_alloc_request(mq->queue, REQ_OP_DRV_OUT, 0);
+ if (IS_ERR(req)) {
+ count = PTR_ERR(req);
+ goto out_put;
+ }
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP;
- blk_execute_rq(mq->queue, NULL, req, 0);
+ req_to_mmc_queue_req(req)->drv_op_result = -EIO;
+ blk_execute_rq(req, false);
ret = req_to_mmc_queue_req(req)->drv_op_result;
+ blk_mq_free_request(req);
if (!ret) {
pr_info("%s: Locking boot partition ro until next power on\n",
@@ -220,20 +291,23 @@ static ssize_t power_ro_lock_store(struct device *dev,
set_disk_ro(part_md->disk, 1);
}
}
-
+out_put:
mmc_blk_put(md);
return count;
}
+static DEVICE_ATTR(ro_lock_until_next_power_on, 0,
+ power_ro_lock_show, power_ro_lock_store);
+
static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
int ret;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- ret = snprintf(buf, PAGE_SIZE, "%d\n",
- get_disk_ro(dev_to_disk(dev)) ^
- md->read_only);
+ ret = sysfs_emit(buf, "%d\n",
+ get_disk_ro(dev_to_disk(dev)) ^
+ md->read_only);
mmc_blk_put(md);
return ret;
}
@@ -242,10 +316,10 @@ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
- char *end;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- unsigned long set = simple_strtoul(buf, &end, 0);
- if (end == buf) {
+ unsigned long set;
+
+ if (kstrtoul(buf, 0, &set)) {
ret = -EINVAL;
goto out;
}
@@ -257,18 +331,53 @@ out:
return ret;
}
-static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
+static DEVICE_ATTR(force_ro, 0644, force_ro_show, force_ro_store);
+
+static struct attribute *mmc_disk_attrs[] = {
+ &dev_attr_force_ro.attr,
+ &dev_attr_ro_lock_until_next_power_on.attr,
+ NULL,
+};
+
+static umode_t mmc_disk_attrs_is_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ umode_t mode = a->mode;
+
+ if (a == &dev_attr_ro_lock_until_next_power_on.attr &&
+ (md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+ md->queue.card->ext_csd.boot_ro_lockable) {
+ mode = 0444;
+ if (!(md->queue.card->ext_csd.boot_ro_lock &
+ EXT_CSD_BOOT_WP_B_PWR_WP_DIS))
+ mode |= 0200;
+ }
+
+ mmc_blk_put(md);
+ return mode;
+}
+
+static const struct attribute_group mmc_disk_attr_group = {
+ .is_visible = mmc_disk_attrs_is_visible,
+ .attrs = mmc_disk_attrs,
+};
+
+static const struct attribute_group *mmc_disk_attr_groups[] = {
+ &mmc_disk_attr_group,
+ NULL,
+};
+
+static int mmc_blk_open(struct gendisk *disk, blk_mode_t mode)
{
- struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
+ struct mmc_blk_data *md = mmc_blk_get(disk);
int ret = -ENXIO;
mutex_lock(&block_mutex);
if (md) {
- if (md->usage == 2)
- check_disk_change(bdev);
ret = 0;
-
- if ((mode & FMODE_WRITE) && md->read_only) {
+ if ((mode & BLK_OPEN_WRITE) && md->read_only) {
mmc_blk_put(md);
ret = -EROFS;
}
@@ -278,7 +387,7 @@ static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
return ret;
}
-static void mmc_blk_release(struct gendisk *disk, fmode_t mode)
+static void mmc_blk_release(struct gendisk *disk)
{
struct mmc_blk_data *md = disk->private_data;
@@ -288,9 +397,9 @@ static void mmc_blk_release(struct gendisk *disk, fmode_t mode)
}
static int
-mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+mmc_blk_getgeo(struct gendisk *disk, struct hd_geometry *geo)
{
- geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
+ geo->cylinders = get_capacity(disk) / (4 * 16);
geo->heads = 4;
geo->sectors = 16;
return 0;
@@ -300,6 +409,11 @@ struct mmc_blk_ioc_data {
struct mmc_ioc_cmd ic;
unsigned char *buf;
u64 buf_bytes;
+ unsigned int flags;
+#define MMC_BLK_IOC_DROP BIT(0) /* drop this mrq */
+#define MMC_BLK_IOC_SBC BIT(1) /* use mrq.sbc */
+
+ struct mmc_rpmb_data *rpmb;
};
static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
@@ -308,7 +422,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
struct mmc_blk_ioc_data *idata;
int err;
- idata = kmalloc(sizeof(*idata), GFP_KERNEL);
+ idata = kzalloc(sizeof(*idata), GFP_KERNEL);
if (!idata) {
err = -ENOMEM;
goto out;
@@ -330,22 +444,15 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
return idata;
}
- idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL);
- if (!idata->buf) {
- err = -ENOMEM;
+ idata->buf = memdup_user((void __user *)(unsigned long)
+ idata->ic.data_ptr, idata->buf_bytes);
+ if (IS_ERR(idata->buf)) {
+ err = PTR_ERR(idata->buf);
goto idata_err;
}
- if (copy_from_user(idata->buf, (void __user *)(unsigned long)
- idata->ic.data_ptr, idata->buf_bytes)) {
- err = -EFAULT;
- goto copy_err;
- }
-
return idata;
-copy_err:
- kfree(idata->buf);
idata_err:
kfree(idata);
out:
@@ -370,82 +477,42 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr,
return 0;
}
-static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
- u32 retries_max)
-{
- int err;
- u32 retry_count = 0;
-
- if (!status || !retries_max)
- return -EINVAL;
-
- do {
- err = __mmc_send_status(card, status, 5);
- if (err)
- break;
-
- if (!R1_STATUS(*status) &&
- (R1_CURRENT_STATE(*status) != R1_STATE_PRG))
- break; /* RPMB programming operation complete */
-
- /*
- * Rechedule to give the MMC device a chance to continue
- * processing the previous command without being polled too
- * frequently.
- */
- usleep_range(1000, 5000);
- } while (++retry_count < retries_max);
-
- if (retry_count == retries_max)
- err = -EPERM;
-
- return err;
-}
-
-static int ioctl_do_sanitize(struct mmc_card *card)
-{
- int err;
-
- if (!mmc_can_sanitize(card)) {
- pr_warn("%s: %s - SANITIZE is not supported\n",
- mmc_hostname(card->host), __func__);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- pr_debug("%s: %s - SANITIZE IN PROGRESS...\n",
- mmc_hostname(card->host), __func__);
-
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_SANITIZE_START, 1,
- MMC_SANITIZE_REQ_TIMEOUT);
-
- if (err)
- pr_err("%s: %s - EXT_CSD_SANITIZE_START failed. err=%d\n",
- mmc_hostname(card->host), __func__, err);
-
- pr_debug("%s: %s - SANITIZE COMPLETED\n", mmc_hostname(card->host),
- __func__);
-out:
- return err;
-}
-
static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
- struct mmc_blk_ioc_data *idata)
+ struct mmc_blk_ioc_data **idatas, int i)
{
- struct mmc_command cmd = {};
+ struct mmc_command cmd = {}, sbc = {};
struct mmc_data data = {};
struct mmc_request mrq = {};
struct scatterlist sg;
+ bool r1b_resp;
+ unsigned int busy_timeout_ms;
int err;
- bool is_rpmb = false;
- u32 status = 0;
+ unsigned int target_part;
+ struct mmc_blk_ioc_data *idata = idatas[i];
+ struct mmc_blk_ioc_data *prev_idata = NULL;
if (!card || !md || !idata)
return -EINVAL;
- if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
- is_rpmb = true;
+ if (idata->flags & MMC_BLK_IOC_DROP)
+ return 0;
+
+ if (idata->flags & MMC_BLK_IOC_SBC && i > 0)
+ prev_idata = idatas[i - 1];
+
+ /*
+ * The RPMB accesses comes in from the character device, so we
+ * need to target these explicitly. Else we just target the
+ * partition type for the block device the ioctl() was issued
+ * on.
+ */
+ if (idata->rpmb) {
+ /* Support multiple RPMB partitions */
+ target_part = idata->rpmb->part_index;
+ target_part |= EXT_CSD_PART_CONFIG_ACC_RPMB;
+ } else {
+ target_part = md->part_type;
+ }
cmd.opcode = idata->ic.opcode;
cmd.arg = idata->ic.arg;
@@ -471,25 +538,12 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
if (idata->ic.data_timeout_ns)
data.timeout_ns = idata->ic.data_timeout_ns;
- if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
- /*
- * Pretend this is a data transfer and rely on the
- * host driver to compute timeout. When all host
- * drivers support cmd.cmd_timeout for R1B, this
- * can be changed to:
- *
- * mrq.data = NULL;
- * cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
- */
- data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
- }
-
mrq.data = &data;
}
mrq.cmd = &cmd;
- err = mmc_blk_part_switch(card, md);
+ err = mmc_blk_part_switch(card, target_part);
if (err)
return err;
@@ -499,25 +553,41 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
return err;
}
- if (is_rpmb) {
- err = mmc_set_blockcount(card, data.blocks,
- idata->ic.write_flag & (1 << 31));
- if (err)
- return err;
+ if (idata->rpmb || prev_idata) {
+ sbc.opcode = MMC_SET_BLOCK_COUNT;
+ /*
+ * We don't do any blockcount validation because the max size
+ * may be increased by a future standard. We just copy the
+ * 'Reliable Write' bit here.
+ */
+ sbc.arg = data.blocks | (idata->ic.write_flag & BIT(31));
+ if (prev_idata)
+ sbc.arg = prev_idata->ic.arg;
+ sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ mrq.sbc = &sbc;
}
if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) &&
- (cmd.opcode == MMC_SWITCH)) {
- err = ioctl_do_sanitize(card);
+ (cmd.opcode == MMC_SWITCH))
+ return mmc_sanitize(card, idata->ic.cmd_timeout_ms);
- if (err)
- pr_err("%s: ioctl_do_sanitize() failed. err = %d",
- __func__, err);
-
- return err;
- }
+ /* If it's an R1B response we need some more preparations. */
+ busy_timeout_ms = idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS;
+ r1b_resp = (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B;
+ if (r1b_resp)
+ mmc_prepare_busy_cmd(card->host, &cmd, busy_timeout_ms);
mmc_wait_for_req(card->host, &mrq);
+ memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp));
+
+ if (prev_idata) {
+ memcpy(&prev_idata->ic.response, sbc.resp, sizeof(sbc.resp));
+ if (sbc.error) {
+ dev_err(mmc_dev(card->host), "%s: sbc error %d\n",
+ __func__, sbc.error);
+ return sbc.error;
+ }
+ }
if (cmd.error) {
dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
@@ -531,57 +601,84 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
}
/*
+ * Make sure the cache of the PARTITION_CONFIG register and
+ * PARTITION_ACCESS bits is updated in case the ioctl ext_csd write
+ * changed it successfully.
+ */
+ if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_PART_CONFIG) &&
+ (cmd.opcode == MMC_SWITCH)) {
+ struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
+ u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd.arg);
+
+ /*
+ * Update cache so the next mmc_blk_part_switch call operates
+ * on up-to-date data.
+ */
+ card->ext_csd.part_config = value;
+ main_md->part_curr = value & EXT_CSD_PART_CONFIG_ACC_MASK;
+ }
+
+ /*
+ * Make sure to update CACHE_CTRL in case it was changed. The cache
+ * will get turned back on if the card is re-initialized, e.g.
+ * suspend/resume or hw reset in recovery.
+ */
+ if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_CACHE_CTRL) &&
+ (cmd.opcode == MMC_SWITCH)) {
+ u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd.arg) & 1;
+
+ card->ext_csd.cache_ctrl = value;
+ }
+
+ /*
* According to the SD specs, some commands require a delay after
* issuing the command.
*/
if (idata->ic.postsleep_min_us)
usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
- memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp));
+ if (mmc_host_is_spi(card->host)) {
+ if (idata->ic.write_flag || r1b_resp || cmd.flags & MMC_RSP_SPI_BUSY)
+ return mmc_spi_err_check(card);
+ return err;
+ }
- if (is_rpmb) {
- /*
- * Ensure RPMB command has completed by polling CMD13
- * "Send Status".
- */
- err = ioctl_rpmb_card_status_poll(card, &status, 5);
- if (err)
- dev_err(mmc_dev(card->host),
- "%s: Card Status=0x%08X, error %d\n",
- __func__, status, err);
+ /*
+ * Ensure RPMB, writes and R1B responses are completed by polling with
+ * CMD13. Note that, usually we don't need to poll when using HW busy
+ * detection, but here it's needed since some commands may indicate the
+ * error through the R1 status bits.
+ */
+ if (idata->rpmb || idata->ic.write_flag || r1b_resp) {
+ struct mmc_blk_busy_data cb_data = {
+ .card = card,
+ };
+
+ err = __mmc_poll_for_busy(card->host, 0, busy_timeout_ms,
+ &mmc_blk_busy_cb, &cb_data);
+
+ idata->ic.response[0] = cb_data.status;
}
return err;
}
-static int mmc_blk_ioctl_cmd(struct block_device *bdev,
- struct mmc_ioc_cmd __user *ic_ptr)
+static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
+ struct mmc_ioc_cmd __user *ic_ptr,
+ struct mmc_rpmb_data *rpmb)
{
struct mmc_blk_ioc_data *idata;
struct mmc_blk_ioc_data *idatas[1];
- struct mmc_blk_data *md;
struct mmc_queue *mq;
struct mmc_card *card;
int err = 0, ioc_err = 0;
struct request *req;
- /*
- * The caller must have CAP_SYS_RAWIO, and must be calling this on the
- * whole block device, not on a partition. This prevents overspray
- * between sibling partitions.
- */
- if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
- return -EPERM;
-
idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
if (IS_ERR(idata))
return PTR_ERR(idata);
-
- md = mmc_blk_get(bdev->bd_disk);
- if (!md) {
- err = -EINVAL;
- goto cmd_err;
- }
+ /* This will be NULL on non-RPMB ioctl():s */
+ idata->rpmb = rpmb;
card = md->queue.card;
if (IS_ERR(card)) {
@@ -593,46 +690,42 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
* Dispatch the ioctl() into the block request queue.
*/
mq = &md->queue;
- req = blk_get_request(mq->queue,
- idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
- __GFP_RECLAIM);
+ req = blk_mq_alloc_request(mq->queue,
+ idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto cmd_done;
+ }
idatas[0] = idata;
- req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;
- req_to_mmc_queue_req(req)->idata = idatas;
+ req_to_mmc_queue_req(req)->drv_op =
+ rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
+ req_to_mmc_queue_req(req)->drv_op_result = -EIO;
+ req_to_mmc_queue_req(req)->drv_op_data = idatas;
req_to_mmc_queue_req(req)->ioc_count = 1;
- blk_execute_rq(mq->queue, NULL, req, 0);
+ blk_execute_rq(req, false);
ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata);
- blk_put_request(req);
+ blk_mq_free_request(req);
cmd_done:
- mmc_blk_put(md);
-cmd_err:
kfree(idata->buf);
kfree(idata);
return ioc_err ? ioc_err : err;
}
-static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
- struct mmc_ioc_multi_cmd __user *user)
+static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
+ struct mmc_ioc_multi_cmd __user *user,
+ struct mmc_rpmb_data *rpmb)
{
struct mmc_blk_ioc_data **idata = NULL;
struct mmc_ioc_cmd __user *cmds = user->cmds;
struct mmc_card *card;
- struct mmc_blk_data *md;
struct mmc_queue *mq;
- int i, err = 0, ioc_err = 0;
+ int err = 0, ioc_err = 0;
__u64 num_of_cmds;
+ unsigned int i, n;
struct request *req;
- /*
- * The caller must have CAP_SYS_RAWIO, and must be calling this on the
- * whole block device, not on a partition. This prevents overspray
- * between sibling partitions.
- */
- if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
- return -EPERM;
-
if (copy_from_user(&num_of_cmds, &user->num_of_cmds,
sizeof(num_of_cmds)))
return -EFAULT;
@@ -643,29 +736,26 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
if (num_of_cmds > MMC_IOC_MAX_CMDS)
return -EINVAL;
- idata = kcalloc(num_of_cmds, sizeof(*idata), GFP_KERNEL);
+ n = num_of_cmds;
+ idata = kcalloc(n, sizeof(*idata), GFP_KERNEL);
if (!idata)
return -ENOMEM;
- for (i = 0; i < num_of_cmds; i++) {
+ for (i = 0; i < n; i++) {
idata[i] = mmc_blk_ioctl_copy_from_user(&cmds[i]);
if (IS_ERR(idata[i])) {
err = PTR_ERR(idata[i]);
- num_of_cmds = i;
+ n = i;
goto cmd_err;
}
- }
-
- md = mmc_blk_get(bdev->bd_disk);
- if (!md) {
- err = -EINVAL;
- goto cmd_err;
+ /* This will be NULL on non-RPMB ioctl():s */
+ idata[i]->rpmb = rpmb;
}
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
- goto cmd_done;
+ goto cmd_err;
}
@@ -673,25 +763,28 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
* Dispatch the ioctl()s into the block request queue.
*/
mq = &md->queue;
- req = blk_get_request(mq->queue,
- idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
- __GFP_RECLAIM);
- req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;
- req_to_mmc_queue_req(req)->idata = idata;
- req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
- blk_execute_rq(mq->queue, NULL, req, 0);
+ req = blk_mq_alloc_request(mq->queue,
+ idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto cmd_err;
+ }
+ req_to_mmc_queue_req(req)->drv_op =
+ rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
+ req_to_mmc_queue_req(req)->drv_op_result = -EIO;
+ req_to_mmc_queue_req(req)->drv_op_data = idata;
+ req_to_mmc_queue_req(req)->ioc_count = n;
+ blk_execute_rq(req, false);
ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
/* copy to user if data and response */
- for (i = 0; i < num_of_cmds && !err; i++)
+ for (i = 0; i < n && !err; i++)
err = mmc_blk_ioctl_copy_to_user(&cmds[i], idata[i]);
- blk_put_request(req);
+ blk_mq_free_request(req);
-cmd_done:
- mmc_blk_put(md);
cmd_err:
- for (i = 0; i < num_of_cmds; i++) {
+ for (i = 0; i < n; i++) {
kfree(idata[i]->buf);
kfree(idata[i]);
}
@@ -699,29 +792,82 @@ cmd_err:
return ioc_err ? ioc_err : err;
}
-static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
+static int mmc_blk_check_blkdev(struct block_device *bdev)
+{
+ /*
+ * The caller must have CAP_SYS_RAWIO, and must be calling this on the
+ * whole block device, not on a partition. This prevents overspray
+ * between sibling partitions.
+ */
+ if (!capable(CAP_SYS_RAWIO) || bdev_is_partition(bdev))
+ return -EPERM;
+ return 0;
+}
+
+static int mmc_blk_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg)
{
+ struct mmc_blk_data *md;
+ int ret;
+
switch (cmd) {
case MMC_IOC_CMD:
- return mmc_blk_ioctl_cmd(bdev,
- (struct mmc_ioc_cmd __user *)arg);
+ ret = mmc_blk_check_blkdev(bdev);
+ if (ret)
+ return ret;
+ md = mmc_blk_get(bdev->bd_disk);
+ if (!md)
+ return -EINVAL;
+ ret = mmc_blk_ioctl_cmd(md,
+ (struct mmc_ioc_cmd __user *)arg,
+ NULL);
+ mmc_blk_put(md);
+ return ret;
case MMC_IOC_MULTI_CMD:
- return mmc_blk_ioctl_multi_cmd(bdev,
- (struct mmc_ioc_multi_cmd __user *)arg);
+ ret = mmc_blk_check_blkdev(bdev);
+ if (ret)
+ return ret;
+ md = mmc_blk_get(bdev->bd_disk);
+ if (!md)
+ return -EINVAL;
+ ret = mmc_blk_ioctl_multi_cmd(md,
+ (struct mmc_ioc_multi_cmd __user *)arg,
+ NULL);
+ mmc_blk_put(md);
+ return ret;
default:
return -EINVAL;
}
}
#ifdef CONFIG_COMPAT
-static int mmc_blk_compat_ioctl(struct block_device *bdev, fmode_t mode,
+static int mmc_blk_compat_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg)
{
return mmc_blk_ioctl(bdev, mode, cmd, (unsigned long) compat_ptr(arg));
}
#endif
+static int mmc_blk_alternative_gpt_sector(struct gendisk *disk,
+ sector_t *sector)
+{
+ struct mmc_blk_data *md;
+ int ret;
+
+ md = mmc_blk_get(disk);
+ if (!md)
+ return -EINVAL;
+
+ if (md->queue.card)
+ ret = mmc_card_alternative_gpt_sector(md->queue.card, sector);
+ else
+ ret = -ENODEV;
+
+ mmc_blk_put(md);
+
+ return ret;
+}
+
static const struct block_device_operations mmc_bdops = {
.open = mmc_blk_open,
.release = mmc_blk_release,
@@ -731,14 +877,17 @@ static const struct block_device_operations mmc_bdops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = mmc_blk_compat_ioctl,
#endif
+ .alternative_gpt_sector = mmc_blk_alternative_gpt_sector,
};
static int mmc_blk_part_switch_pre(struct mmc_card *card,
unsigned int part_type)
{
+ const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_MASK;
+ const unsigned int rpmb = EXT_CSD_PART_CONFIG_ACC_RPMB;
int ret = 0;
- if (part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
+ if ((part_type & mask) == rpmb) {
if (card->ext_csd.cmdq_en) {
ret = mmc_cmdq_disable(card);
if (ret)
@@ -753,9 +902,11 @@ static int mmc_blk_part_switch_pre(struct mmc_card *card,
static int mmc_blk_part_switch_post(struct mmc_card *card,
unsigned int part_type)
{
+ const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_MASK;
+ const unsigned int rpmb = EXT_CSD_PART_CONFIG_ACC_RPMB;
int ret = 0;
- if (part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
+ if ((part_type & mask) == rpmb) {
mmc_retune_unpause(card->host);
if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
ret = mmc_cmdq_enable(card);
@@ -765,29 +916,29 @@ static int mmc_blk_part_switch_post(struct mmc_card *card,
}
static inline int mmc_blk_part_switch(struct mmc_card *card,
- struct mmc_blk_data *md)
+ unsigned int part_type)
{
int ret = 0;
struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
- if (main_md->part_curr == md->part_type)
+ if (main_md->part_curr == part_type)
return 0;
if (mmc_card_mmc(card)) {
u8 part_config = card->ext_csd.part_config;
- ret = mmc_blk_part_switch_pre(card, md->part_type);
+ ret = mmc_blk_part_switch_pre(card, part_type);
if (ret)
return ret;
part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
- part_config |= md->part_type;
+ part_config |= part_type;
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PART_CONFIG, part_config,
card->ext_csd.part_time);
if (ret) {
- mmc_blk_part_switch_post(card, md->part_type);
+ mmc_blk_part_switch_post(card, part_type);
return ret;
}
@@ -796,7 +947,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
ret = mmc_blk_part_switch_post(card, main_md->part_curr);
}
- main_md->part_curr = md->part_type;
+ main_md->part_curr = part_type;
return ret;
}
@@ -805,30 +956,22 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
int err;
u32 result;
__be32 *blocks;
+ u8 resp_sz = mmc_card_ult_capacity(card) ? 8 : 4;
struct mmc_request mrq = {};
struct mmc_command cmd = {};
struct mmc_data data = {};
-
struct scatterlist sg;
- cmd.opcode = MMC_APP_CMD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ err = mmc_app_cmd(card->host, card);
if (err)
return err;
- if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
- return -EIO;
-
- memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- data.blksz = 4;
+ data.blksz = resp_sz;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
@@ -838,15 +981,27 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
mrq.cmd = &cmd;
mrq.data = &data;
- blocks = kmalloc(4, GFP_KERNEL);
+ blocks = kmalloc(resp_sz, GFP_NOIO);
if (!blocks)
return -ENOMEM;
- sg_init_one(&sg, blocks, 4);
+ sg_init_one(&sg, blocks, resp_sz);
mmc_wait_for_req(card->host, &mrq);
- result = ntohl(*blocks);
+ if (mmc_card_ult_capacity(card)) {
+ /*
+ * Normally, ACMD22 returns the number of written sectors as
+ * u32. SDUC, however, returns it as u64. This is not a
+ * superfluous requirement, because SDUC writes may exceed 2TB.
+ * For Linux mmc however, the previously write operation could
+ * not be more than the block layer limits, thus just make room
+ * for a u64 and cast the response back to u32.
+ */
+ result = clamp_val(get_unaligned_be64(blocks), 0, UINT_MAX);
+ } else {
+ result = ntohl(*blocks);
+ }
kfree(blocks);
if (cmd.error || data.error)
@@ -857,298 +1012,67 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
return 0;
}
-static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
- bool hw_busy_detect, struct request *req, bool *gen_err)
+static unsigned int mmc_blk_clock_khz(struct mmc_host *host)
{
- unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
- int err = 0;
- u32 status;
+ if (host->actual_clock)
+ return host->actual_clock / 1000;
- do {
- err = __mmc_send_status(card, &status, 5);
- if (err) {
- pr_err("%s: error %d requesting status\n",
- req->rq_disk->disk_name, err);
- return err;
- }
-
- if (status & R1_ERROR) {
- pr_err("%s: %s: error sending status cmd, status %#x\n",
- req->rq_disk->disk_name, __func__, status);
- *gen_err = true;
- }
-
- /* We may rely on the host hw to handle busy detection.*/
- if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) &&
- hw_busy_detect)
- break;
-
- /*
- * Timeout if the device never becomes ready for data and never
- * leaves the program state.
- */
- if (time_after(jiffies, timeout)) {
- pr_err("%s: Card stuck in programming state! %s %s\n",
- mmc_hostname(card->host),
- req->rq_disk->disk_name, __func__);
- return -ETIMEDOUT;
- }
-
- /*
- * Some cards mishandle the status bits,
- * so make sure to check both the busy
- * indication and the card state.
- */
- } while (!(status & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+ /* Clock may be subject to a divisor, fudge it by a factor of 2. */
+ if (host->ios.clock)
+ return host->ios.clock / 2000;
- return err;
+ /* How can there be no clock */
+ WARN_ON_ONCE(1);
+ return 100; /* 100 kHz is minimum possible value */
}
-static int send_stop(struct mmc_card *card, unsigned int timeout_ms,
- struct request *req, bool *gen_err, u32 *stop_status)
+static unsigned int mmc_blk_data_timeout_ms(struct mmc_host *host,
+ struct mmc_data *data)
{
- struct mmc_host *host = card->host;
- struct mmc_command cmd = {};
- int err;
- bool use_r1b_resp = rq_data_dir(req) == WRITE;
+ unsigned int ms = DIV_ROUND_UP(data->timeout_ns, 1000000);
+ unsigned int khz;
- /*
- * Normally we use R1B responses for WRITE, but in cases where the host
- * has specified a max_busy_timeout we need to validate it. A failure
- * means we need to prevent the host from doing hw busy detection, which
- * is done by converting to a R1 response instead.
- */
- if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout))
- use_r1b_resp = false;
-
- cmd.opcode = MMC_STOP_TRANSMISSION;
- if (use_r1b_resp) {
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- cmd.busy_timeout = timeout_ms;
- } else {
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ if (data->timeout_clks) {
+ khz = mmc_blk_clock_khz(host);
+ ms += DIV_ROUND_UP(data->timeout_clks, khz);
}
- err = mmc_wait_for_cmd(host, &cmd, 5);
- if (err)
- return err;
-
- *stop_status = cmd.resp[0];
-
- /* No need to check card status in case of READ. */
- if (rq_data_dir(req) == READ)
- return 0;
-
- if (!mmc_host_is_spi(host) &&
- (*stop_status & R1_ERROR)) {
- pr_err("%s: %s: general error sending stop command, resp %#x\n",
- req->rq_disk->disk_name, __func__, *stop_status);
- *gen_err = true;
- }
-
- return card_busy_detect(card, timeout_ms, use_r1b_resp, req, gen_err);
-}
-
-#define ERR_NOMEDIUM 3
-#define ERR_RETRY 2
-#define ERR_ABORT 1
-#define ERR_CONTINUE 0
-
-static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
- bool status_valid, u32 status)
-{
- switch (error) {
- case -EILSEQ:
- /* response crc error, retry the r/w cmd */
- pr_err("%s: %s sending %s command, card status %#x\n",
- req->rq_disk->disk_name, "response CRC error",
- name, status);
- return ERR_RETRY;
-
- case -ETIMEDOUT:
- pr_err("%s: %s sending %s command, card status %#x\n",
- req->rq_disk->disk_name, "timed out", name, status);
-
- /* If the status cmd initially failed, retry the r/w cmd */
- if (!status_valid) {
- pr_err("%s: status not valid, retrying timeout\n",
- req->rq_disk->disk_name);
- return ERR_RETRY;
- }
-
- /*
- * If it was a r/w cmd crc error, or illegal command
- * (eg, issued in wrong state) then retry - we should
- * have corrected the state problem above.
- */
- if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) {
- pr_err("%s: command error, retrying timeout\n",
- req->rq_disk->disk_name);
- return ERR_RETRY;
- }
-
- /* Otherwise abort the command */
- return ERR_ABORT;
-
- default:
- /* We don't understand the error code the driver gave us */
- pr_err("%s: unknown error %d sending read/write command, card status %#x\n",
- req->rq_disk->disk_name, error, status);
- return ERR_ABORT;
- }
+ return ms;
}
/*
- * Initial r/w and stop cmd error recovery.
- * We don't know whether the card received the r/w cmd or not, so try to
- * restore things back to a sane state. Essentially, we do this as follows:
- * - Obtain card status. If the first attempt to obtain card status fails,
- * the status word will reflect the failed status cmd, not the failed
- * r/w cmd. If we fail to obtain card status, it suggests we can no
- * longer communicate with the card.
- * - Check the card state. If the card received the cmd but there was a
- * transient problem with the response, it might still be in a data transfer
- * mode. Try to send it a stop command. If this fails, we can't recover.
- * - If the r/w cmd failed due to a response CRC error, it was probably
- * transient, so retry the cmd.
- * - If the r/w cmd timed out, but we didn't get the r/w cmd status, retry.
- * - If the r/w cmd timed out, and the r/w cmd failed due to CRC error or
- * illegal cmd, retry.
- * Otherwise we don't understand what happened, so abort.
+ * Attempts to reset the card and get back to the requested partition.
+ * Therefore any error here must result in cancelling the block layer
+ * request, it must not be reattempted without going through the mmc_blk
+ * partition sanity checks.
*/
-static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
- struct mmc_blk_request *brq, bool *ecc_err, bool *gen_err)
-{
- bool prev_cmd_status_valid = true;
- u32 status, stop_status = 0;
- int err, retry;
-
- if (mmc_card_removed(card))
- return ERR_NOMEDIUM;
-
- /*
- * Try to get card status which indicates both the card state
- * and why there was no response. If the first attempt fails,
- * we can't be sure the returned status is for the r/w command.
- */
- for (retry = 2; retry >= 0; retry--) {
- err = __mmc_send_status(card, &status, 0);
- if (!err)
- break;
-
- /* Re-tune if needed */
- mmc_retune_recheck(card->host);
-
- prev_cmd_status_valid = false;
- pr_err("%s: error %d sending status command, %sing\n",
- req->rq_disk->disk_name, err, retry ? "retry" : "abort");
- }
-
- /* We couldn't get a response from the card. Give up. */
- if (err) {
- /* Check if the card is removed */
- if (mmc_detect_card_removed(card->host))
- return ERR_NOMEDIUM;
- return ERR_ABORT;
- }
-
- /* Flag ECC errors */
- if ((status & R1_CARD_ECC_FAILED) ||
- (brq->stop.resp[0] & R1_CARD_ECC_FAILED) ||
- (brq->cmd.resp[0] & R1_CARD_ECC_FAILED))
- *ecc_err = true;
-
- /* Flag General errors */
- if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ)
- if ((status & R1_ERROR) ||
- (brq->stop.resp[0] & R1_ERROR)) {
- pr_err("%s: %s: general error sending stop or status command, stop cmd response %#x, card status %#x\n",
- req->rq_disk->disk_name, __func__,
- brq->stop.resp[0], status);
- *gen_err = true;
- }
-
- /*
- * Check the current card state. If it is in some data transfer
- * mode, tell it to stop (and hopefully transition back to TRAN.)
- */
- if (R1_CURRENT_STATE(status) == R1_STATE_DATA ||
- R1_CURRENT_STATE(status) == R1_STATE_RCV) {
- err = send_stop(card,
- DIV_ROUND_UP(brq->data.timeout_ns, 1000000),
- req, gen_err, &stop_status);
- if (err) {
- pr_err("%s: error %d sending stop command\n",
- req->rq_disk->disk_name, err);
- /*
- * If the stop cmd also timed out, the card is probably
- * not present, so abort. Other errors are bad news too.
- */
- return ERR_ABORT;
- }
-
- if (stop_status & R1_CARD_ECC_FAILED)
- *ecc_err = true;
- }
-
- /* Check for set block count errors */
- if (brq->sbc.error)
- return mmc_blk_cmd_error(req, "SET_BLOCK_COUNT", brq->sbc.error,
- prev_cmd_status_valid, status);
-
- /* Check for r/w command errors */
- if (brq->cmd.error)
- return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error,
- prev_cmd_status_valid, status);
-
- /* Data errors */
- if (!brq->stop.error)
- return ERR_CONTINUE;
-
- /* Now for stop errors. These aren't fatal to the transfer. */
- pr_info("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
- req->rq_disk->disk_name, brq->stop.error,
- brq->cmd.resp[0], status);
-
- /*
- * Subsitute in our own stop status as this will give the error
- * state which happened during the execution of the r/w command.
- */
- if (stop_status) {
- brq->stop.resp[0] = stop_status;
- brq->stop.error = 0;
- }
- return ERR_CONTINUE;
-}
-
static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
int type)
{
int err;
+ struct mmc_blk_data *main_md = dev_get_drvdata(&host->card->dev);
if (md->reset_done & type)
return -EEXIST;
md->reset_done |= type;
- err = mmc_hw_reset(host);
+ err = mmc_hw_reset(host->card);
+ /*
+ * A successful reset will leave the card in the main partition, but
+ * upon failure it might not be, so set it to MMC_BLK_PART_INVALID
+ * in that case.
+ */
+ main_md->part_curr = err ? MMC_BLK_PART_INVALID : main_md->part_type;
+ if (err)
+ return err;
/* Ensure we switch back to the correct partition */
- if (err != -EOPNOTSUPP) {
- struct mmc_blk_data *main_md =
- dev_get_drvdata(&host->card->dev);
- int part_err;
-
- main_md->part_curr = main_md->part_type;
- part_err = mmc_blk_part_switch(host->card, md);
- if (part_err) {
- /*
- * We have failed to get back into the correct
- * partition, so we need to abort the whole request.
- */
- return -ENODEV;
- }
- }
- return err;
+ if (mmc_blk_part_switch(host->card, md->part_type))
+ /*
+ * We have failed to get back into the correct
+ * partition, so we need to abort the whole request.
+ */
+ return -ENODEV;
+ return 0;
}
static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
@@ -1156,16 +1080,18 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
md->reset_done &= ~type;
}
-int mmc_access_rpmb(struct mmc_queue *mq)
+static void mmc_blk_check_sbc(struct mmc_queue_req *mq_rq)
{
- struct mmc_blk_data *md = mq->blkdata;
- /*
- * If this is a RPMB partition access, return ture
- */
- if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
- return true;
+ struct mmc_blk_ioc_data **idata = mq_rq->drv_op_data;
+ int i;
- return false;
+ for (i = 1; i < mq_rq->ioc_count; i++) {
+ if (idata[i - 1]->ic.opcode == MMC_SET_BLOCK_COUNT &&
+ mmc_op_multi(idata[i]->ic.opcode)) {
+ idata[i - 1]->flags |= MMC_BLK_IOC_DROP;
+ idata[i]->flags |= MMC_BLK_IOC_SBC;
+ }
+ }
}
/*
@@ -1178,21 +1104,39 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
struct mmc_queue_req *mq_rq;
struct mmc_card *card = mq->card;
struct mmc_blk_data *md = mq->blkdata;
+ struct mmc_blk_ioc_data **idata;
+ bool rpmb_ioctl;
+ u8 **ext_csd;
+ u32 status;
int ret;
int i;
mq_rq = req_to_mmc_queue_req(req);
+ rpmb_ioctl = (mq_rq->drv_op == MMC_DRV_OP_IOCTL_RPMB);
switch (mq_rq->drv_op) {
case MMC_DRV_OP_IOCTL:
+ if (card->ext_csd.cmdq_en) {
+ ret = mmc_cmdq_disable(card);
+ if (ret)
+ break;
+ }
+
+ mmc_blk_check_sbc(mq_rq);
+
+ fallthrough;
+ case MMC_DRV_OP_IOCTL_RPMB:
+ idata = mq_rq->drv_op_data;
for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
- ret = __mmc_blk_ioctl_cmd(card, md, mq_rq->idata[i]);
+ ret = __mmc_blk_ioctl_cmd(card, md, idata, i);
if (ret)
break;
}
/* Always switch back to main area after RPMB access */
- if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
- mmc_blk_part_switch(card, dev_get_drvdata(&card->dev));
+ if (rpmb_ioctl)
+ mmc_blk_part_switch(card, 0);
+ else if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
+ mmc_cmdq_enable(card);
break;
case MMC_DRV_OP_BOOT_WP:
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -1206,6 +1150,15 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
card->ext_csd.boot_ro_lock |=
EXT_CSD_BOOT_WP_B_PWR_WP_EN;
break;
+ case MMC_DRV_OP_GET_CARD_STATUS:
+ ret = mmc_send_status(card, &status);
+ if (!ret)
+ ret = status;
+ break;
+ case MMC_DRV_OP_GET_EXT_CSD:
+ ext_csd = mq_rq->drv_op_data;
+ ret = mmc_get_ext_csd(card, ext_csd);
+ break;
default:
pr_err("%s: unknown driver specific operation\n",
md->disk->disk_name);
@@ -1213,18 +1166,20 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
break;
}
mq_rq->drv_op_result = ret;
- blk_end_request_all(req, ret);
+ blk_mq_end_request(req, ret ? BLK_STS_IOERR : BLK_STS_OK);
}
-static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
+static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req,
+ int type, unsigned int erase_arg)
{
struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card;
- unsigned int from, nr, arg;
- int err = 0, type = MMC_BLK_DISCARD;
+ unsigned int nr;
+ sector_t from;
+ int err = 0;
blk_status_t status = BLK_STS_OK;
- if (!mmc_can_erase(card)) {
+ if (!mmc_card_can_erase(card)) {
status = BLK_STS_NOTSUPP;
goto fail;
}
@@ -1232,31 +1187,42 @@ static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
- if (mmc_can_discard(card))
- arg = MMC_DISCARD_ARG;
- else if (mmc_can_trim(card))
- arg = MMC_TRIM_ARG;
- else
- arg = MMC_ERASE_ARG;
do {
err = 0;
if (card->quirks & MMC_QUIRK_INAND_CMD38) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
INAND_CMD38_ARG_EXT_CSD,
- arg == MMC_TRIM_ARG ?
+ erase_arg == MMC_TRIM_ARG ?
INAND_CMD38_ARG_TRIM :
INAND_CMD38_ARG_ERASE,
- 0);
+ card->ext_csd.generic_cmd6_time);
}
if (!err)
- err = mmc_erase(card, from, nr, arg);
+ err = mmc_erase(card, from, nr, erase_arg);
} while (err == -EIO && !mmc_blk_reset(md, card->host, type));
if (err)
status = BLK_STS_IOERR;
else
mmc_blk_reset_success(md, type);
fail:
- blk_end_request(req, status, blk_rq_bytes(req));
+ blk_mq_end_request(req, status);
+}
+
+static void mmc_blk_issue_trim_rq(struct mmc_queue *mq, struct request *req)
+{
+ mmc_blk_issue_erase_rq(mq, req, MMC_BLK_TRIM, MMC_TRIM_ARG);
+}
+
+static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_blk_data *md = mq->blkdata;
+ struct mmc_card *card = md->queue.card;
+ unsigned int arg = card->erase_arg;
+
+ if (mmc_card_broken_sd_discard(card))
+ arg = SD_ERASE_ARG;
+
+ mmc_blk_issue_erase_rq(mq, req, MMC_BLK_DISCARD, arg);
}
static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
@@ -1264,11 +1230,12 @@ static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
{
struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card;
- unsigned int from, nr, arg;
+ unsigned int nr, arg;
+ sector_t from;
int err = 0, type = MMC_BLK_SECDISCARD;
blk_status_t status = BLK_STS_OK;
- if (!(mmc_can_secure_erase_trim(card))) {
+ if (!(mmc_card_can_secure_erase_trim(card))) {
status = BLK_STS_NOTSUPP;
goto out;
}
@@ -1276,7 +1243,7 @@ static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
- if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
+ if (mmc_card_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
arg = MMC_SECURE_TRIM1_ARG;
else
arg = MMC_SECURE_ERASE_ARG;
@@ -1288,7 +1255,7 @@ retry:
arg == MMC_SECURE_TRIM1_ARG ?
INAND_CMD38_ARG_SECTRIM1 :
INAND_CMD38_ARG_SECERASE,
- 0);
+ card->ext_csd.generic_cmd6_time);
if (err)
goto out_retry;
}
@@ -1306,7 +1273,7 @@ retry:
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
INAND_CMD38_ARG_EXT_CSD,
INAND_CMD38_ARG_SECTRIM2,
- 0);
+ card->ext_csd.generic_cmd6_time);
if (err)
goto out_retry;
}
@@ -1326,7 +1293,7 @@ out_retry:
if (!err)
mmc_blk_reset_success(md, type);
out:
- blk_end_request(req, status, blk_rq_bytes(req));
+ blk_mq_end_request(req, status);
}
static void mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
@@ -1335,8 +1302,8 @@ static void mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
struct mmc_card *card = md->queue.card;
int ret = 0;
- ret = mmc_flush_cache(card);
- blk_end_request_all(req, ret ? BLK_STS_IOERR : BLK_STS_OK);
+ ret = mmc_flush_cache(card->host);
+ blk_mq_end_request(req, ret ? BLK_STS_IOERR : BLK_STS_OK);
}
/*
@@ -1362,150 +1329,84 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
}
}
-#define CMD_ERRORS \
- (R1_OUT_OF_RANGE | /* Command argument out of range */ \
- R1_ADDRESS_ERROR | /* Misaligned address */ \
+#define CMD_ERRORS_EXCL_OOR \
+ (R1_ADDRESS_ERROR | /* Misaligned address */ \
R1_BLOCK_LEN_ERROR | /* Transferred block length incorrect */\
R1_WP_VIOLATION | /* Tried to write to protected block */ \
R1_CARD_ECC_FAILED | /* Card ECC failed */ \
R1_CC_ERROR | /* Card controller error */ \
R1_ERROR) /* General/unknown error */
-static bool mmc_blk_has_cmd_err(struct mmc_command *cmd)
-{
- if (!cmd->error && cmd->resp[0] & CMD_ERRORS)
- cmd->error = -EIO;
-
- return cmd->error;
-}
+#define CMD_ERRORS \
+ (CMD_ERRORS_EXCL_OOR | \
+ R1_OUT_OF_RANGE) /* Command argument out of range */ \
-static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card,
- struct mmc_async_req *areq)
+static void mmc_blk_eval_resp_error(struct mmc_blk_request *brq)
{
- struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req,
- areq);
- struct mmc_blk_request *brq = &mq_mrq->brq;
- struct request *req = mmc_queue_req_to_req(mq_mrq);
- int need_retune = card->host->need_retune;
- bool ecc_err = false;
- bool gen_err = false;
+ u32 val;
/*
- * sbc.error indicates a problem with the set block count
- * command. No data will have been transferred.
+ * Per the SD specification(physical layer version 4.10)[1],
+ * section 4.3.3, it explicitly states that "When the last
+ * block of user area is read using CMD18, the host should
+ * ignore OUT_OF_RANGE error that may occur even the sequence
+ * is correct". And JESD84-B51 for eMMC also has a similar
+ * statement on section 6.8.3.
*
- * cmd.error indicates a problem with the r/w command. No
- * data will have been transferred.
+ * Multiple block read/write could be done by either predefined
+ * method, namely CMD23, or open-ending mode. For open-ending mode,
+ * we should ignore the OUT_OF_RANGE error as it's normal behaviour.
*
- * stop.error indicates a problem with the stop command. Data
- * may have been transferred, or may still be transferring.
- */
- if (brq->sbc.error || brq->cmd.error || mmc_blk_has_cmd_err(&brq->stop) ||
- brq->data.error) {
- switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err, &gen_err)) {
- case ERR_RETRY:
- return MMC_BLK_RETRY;
- case ERR_ABORT:
- return MMC_BLK_ABORT;
- case ERR_NOMEDIUM:
- return MMC_BLK_NOMEDIUM;
- case ERR_CONTINUE:
- break;
- }
- }
-
- /*
- * Check for errors relating to the execution of the
- * initial command - such as address errors. No data
- * has been transferred.
- */
- if (brq->cmd.resp[0] & CMD_ERRORS) {
- pr_err("%s: r/w command failed, status = %#x\n",
- req->rq_disk->disk_name, brq->cmd.resp[0]);
- return MMC_BLK_ABORT;
- }
-
- /*
- * Everything else is either success, or a data error of some
- * kind. If it was a write, we may have transitioned to
- * program mode, which we have to wait for it to complete.
+ * However the spec[1] doesn't tell us whether we should also
+ * ignore that for predefined method. But per the spec[1], section
+ * 4.15 Set Block Count Command, it says"If illegal block count
+ * is set, out of range error will be indicated during read/write
+ * operation (For example, data transfer is stopped at user area
+ * boundary)." In another word, we could expect a out of range error
+ * in the response for the following CMD18/25. And if argument of
+ * CMD23 + the argument of CMD18/25 exceed the max number of blocks,
+ * we could also expect to get a -ETIMEDOUT or any error number from
+ * the host drivers due to missing data response(for write)/data(for
+ * read), as the cards will stop the data transfer by itself per the
+ * spec. So we only need to check R1_OUT_OF_RANGE for open-ending mode.
*/
- if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
- int err;
- /* Check stop command response */
- if (brq->stop.resp[0] & R1_ERROR) {
- pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n",
- req->rq_disk->disk_name, __func__,
- brq->stop.resp[0]);
- gen_err = true;
- }
+ if (!brq->stop.error) {
+ bool oor_with_open_end;
+ /* If there is no error yet, check R1 response */
- err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, false, req,
- &gen_err);
- if (err)
- return MMC_BLK_CMD_ERR;
- }
+ val = brq->stop.resp[0] & CMD_ERRORS;
+ oor_with_open_end = val & R1_OUT_OF_RANGE && !brq->mrq.sbc;
- /* if general error occurs, retry the write operation. */
- if (gen_err) {
- pr_warn("%s: retrying write for general error\n",
- req->rq_disk->disk_name);
- return MMC_BLK_RETRY;
+ if (val && !oor_with_open_end)
+ brq->stop.error = -EIO;
}
-
- /* Some errors (ECC) are flagged on the next commmand, so check stop, too */
- if (brq->data.error || brq->stop.error) {
- if (need_retune && !brq->retune_retry_done) {
- pr_debug("%s: retrying because a re-tune was needed\n",
- req->rq_disk->disk_name);
- brq->retune_retry_done = 1;
- return MMC_BLK_RETRY;
- }
- pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
- req->rq_disk->disk_name, brq->data.error ?: brq->stop.error,
- (unsigned)blk_rq_pos(req),
- (unsigned)blk_rq_sectors(req),
- brq->cmd.resp[0], brq->stop.resp[0]);
-
- if (rq_data_dir(req) == READ) {
- if (ecc_err)
- return MMC_BLK_ECC_ERR;
- return MMC_BLK_DATA_ERR;
- } else {
- return MMC_BLK_CMD_ERR;
- }
- }
-
- if (!brq->data.bytes_xfered)
- return MMC_BLK_RETRY;
-
- if (blk_rq_bytes(req) != brq->data.bytes_xfered)
- return MMC_BLK_PARTIAL;
-
- return MMC_BLK_SUCCESS;
}
static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
- int disable_multi, bool *do_rel_wr,
- bool *do_data_tag)
+ int recovery_mode, bool *do_rel_wr_p,
+ bool *do_data_tag_p)
{
struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card;
struct mmc_blk_request *brq = &mqrq->brq;
struct request *req = mmc_queue_req_to_req(mqrq);
+ bool do_rel_wr, do_data_tag;
/*
* Reliable writes are used to implement Forced Unit Access and
* are supported only on MMCs.
*/
- *do_rel_wr = (req->cmd_flags & REQ_FUA) &&
- rq_data_dir(req) == WRITE &&
- (md->flags & MMC_BLK_REL_WR);
+ do_rel_wr = (req->cmd_flags & REQ_FUA) &&
+ rq_data_dir(req) == WRITE &&
+ (md->flags & MMC_BLK_REL_WR);
memset(brq, 0, sizeof(struct mmc_blk_request));
+ mmc_crypto_prepare_req(mqrq);
+
brq->mrq.data = &brq->data;
+ brq->mrq.tag = req->tag;
brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0;
@@ -1520,6 +1421,14 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
brq->data.blksz = 512;
brq->data.blocks = blk_rq_sectors(req);
+ brq->data.blk_addr = blk_rq_pos(req);
+
+ /*
+ * The command queue supports 2 priorities: "high" (1) and "simple" (0).
+ * The eMMC will give "high" priority tasks priority over "simple"
+ * priority tasks. Here we always set "simple" priority by not setting
+ * MMC_DATA_PRIO.
+ */
/*
* The block layer doesn't support all sector count
@@ -1531,12 +1440,22 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
if (brq->data.blocks > 1) {
/*
- * After a read error, we redo the request one sector
+ * Some SD cards in SPI mode return a CRC error or even lock up
+ * completely when trying to read the last block using a
+ * multiblock read command.
+ */
+ if (mmc_host_is_spi(card->host) && (rq_data_dir(req) == READ) &&
+ (blk_rq_pos(req) + blk_rq_sectors(req) ==
+ get_capacity(md->disk)))
+ brq->data.blocks--;
+
+ /*
+ * After a read error, we redo the request one (native) sector
* at a time in order to accurately determine which
* sectors can be read successfully.
*/
- if (disable_multi)
- brq->data.blocks = 1;
+ if (recovery_mode)
+ brq->data.blocks = queue_physical_block_size(mq->queue) >> 9;
/*
* Some controllers have HW issues while operating
@@ -1549,18 +1468,23 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
brq->data.blocks);
}
- if (*do_rel_wr)
+ if (do_rel_wr) {
mmc_apply_rel_rw(brq, card, req);
+ brq->data.flags |= MMC_DATA_REL_WR;
+ }
/*
* Data tag is used only during writing meta data to speed
* up write and any subsequent read of this meta data
*/
- *do_data_tag = card->ext_csd.data_tag_unit_size &&
- (req->cmd_flags & REQ_META) &&
- (rq_data_dir(req) == WRITE) &&
- ((brq->data.blocks * brq->data.blksz) >=
- card->ext_csd.data_tag_unit_size);
+ do_data_tag = card->ext_csd.data_tag_unit_size &&
+ (req->cmd_flags & REQ_META) &&
+ (rq_data_dir(req) == WRITE) &&
+ ((brq->data.blocks * brq->data.blksz) >=
+ card->ext_csd.data_tag_unit_size);
+
+ if (do_data_tag)
+ brq->data.flags |= MMC_DATA_DAT_TAG;
mmc_set_data_timeout(&brq->data, card);
@@ -1586,14 +1510,171 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
brq->data.sg_len = i;
}
- mqrq->areq.mrq = &brq->mrq;
+ if (do_rel_wr_p)
+ *do_rel_wr_p = do_rel_wr;
- mmc_queue_bounce_pre(mqrq);
+ if (do_data_tag_p)
+ *do_data_tag_p = do_data_tag;
+}
+
+#define MMC_CQE_RETRIES 2
+
+static void mmc_blk_cqe_complete_rq(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_request *mrq = &mqrq->brq.mrq;
+ struct request_queue *q = req->q;
+ struct mmc_host *host = mq->card->host;
+ enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
+ unsigned long flags;
+ bool put_card;
+ int err;
+
+ mmc_cqe_post_req(host, mrq);
+
+ if (mrq->cmd && mrq->cmd->error)
+ err = mrq->cmd->error;
+ else if (mrq->data && mrq->data->error)
+ err = mrq->data->error;
+ else
+ err = 0;
+
+ if (err) {
+ if (mqrq->retries++ < MMC_CQE_RETRIES)
+ blk_mq_requeue_request(req, true);
+ else
+ blk_mq_end_request(req, BLK_STS_IOERR);
+ } else if (mrq->data) {
+ if (blk_update_request(req, BLK_STS_OK, mrq->data->bytes_xfered))
+ blk_mq_requeue_request(req, true);
+ else
+ __blk_mq_end_request(req, BLK_STS_OK);
+ } else if (mq->in_recovery) {
+ blk_mq_requeue_request(req, true);
+ } else {
+ blk_mq_end_request(req, BLK_STS_OK);
+ }
+
+ spin_lock_irqsave(&mq->lock, flags);
+
+ mq->in_flight[issue_type] -= 1;
+
+ put_card = (mmc_tot_in_flight(mq) == 0);
+
+ mmc_cqe_check_busy(mq);
+
+ spin_unlock_irqrestore(&mq->lock, flags);
+
+ if (!mq->cqe_busy)
+ blk_mq_run_hw_queues(q, true);
+
+ if (put_card)
+ mmc_put_card(mq->card, &mq->ctx);
+}
+
+void mmc_blk_cqe_recovery(struct mmc_queue *mq)
+{
+ struct mmc_card *card = mq->card;
+ struct mmc_host *host = card->host;
+ int err;
+
+ pr_debug("%s: CQE recovery start\n", mmc_hostname(host));
+
+ err = mmc_cqe_recovery(host);
+ if (err)
+ mmc_blk_reset(mq->blkdata, host, MMC_BLK_CQE_RECOVERY);
+ mmc_blk_reset_success(mq->blkdata, MMC_BLK_CQE_RECOVERY);
+
+ pr_debug("%s: CQE recovery done\n", mmc_hostname(host));
+}
+
+static void mmc_blk_cqe_req_done(struct mmc_request *mrq)
+{
+ struct mmc_queue_req *mqrq = container_of(mrq, struct mmc_queue_req,
+ brq.mrq);
+ struct request *req = mmc_queue_req_to_req(mqrq);
+ struct request_queue *q = req->q;
+ struct mmc_queue *mq = q->queuedata;
+
+ /*
+ * Block layer timeouts race with completions which means the normal
+ * completion path cannot be used during recovery.
+ */
+ if (mq->in_recovery)
+ mmc_blk_cqe_complete_rq(mq, req);
+ else if (likely(!blk_should_fake_timeout(req->q)))
+ blk_mq_complete_request(req);
+}
+
+static int mmc_blk_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ mrq->done = mmc_blk_cqe_req_done;
+ mrq->recovery_notifier = mmc_cqe_recovery_notifier;
+
+ return mmc_cqe_start_req(host, mrq);
+}
+
+static struct mmc_request *mmc_blk_cqe_prep_dcmd(struct mmc_queue_req *mqrq,
+ struct request *req)
+{
+ struct mmc_blk_request *brq = &mqrq->brq;
+
+ memset(brq, 0, sizeof(*brq));
+
+ brq->mrq.cmd = &brq->cmd;
+ brq->mrq.tag = req->tag;
+
+ return &brq->mrq;
+}
+
+static int mmc_blk_cqe_issue_flush(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_request *mrq = mmc_blk_cqe_prep_dcmd(mqrq, req);
+
+ mrq->cmd->opcode = MMC_SWITCH;
+ mrq->cmd->arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_FLUSH_CACHE << 16) |
+ (1 << 8) |
+ EXT_CSD_CMD_SET_NORMAL;
+ mrq->cmd->flags = MMC_CMD_AC | MMC_RSP_R1B;
+
+ return mmc_blk_cqe_start_req(mq->card->host, mrq);
+}
+
+static int mmc_blk_hsq_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_host *host = mq->card->host;
+ int err;
+
+ mmc_blk_rw_rq_prep(mqrq, mq->card, 0, mq);
+ mqrq->brq.mrq.done = mmc_blk_hsq_req_done;
+ mmc_pre_req(host, &mqrq->brq.mrq);
+
+ err = mmc_cqe_start_req(host, &mqrq->brq.mrq);
+ if (err)
+ mmc_post_req(host, &mqrq->brq.mrq, err);
+
+ return err;
+}
+
+static int mmc_blk_cqe_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_host *host = mq->card->host;
+
+ if (host->hsq_enabled)
+ return mmc_blk_hsq_issue_rw_rq(mq, req);
+
+ mmc_blk_data_prep(mq, mqrq, 0, NULL, NULL);
+
+ return mmc_blk_cqe_start_req(mq->card->host, &mqrq->brq.mrq);
}
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct mmc_card *card,
- int disable_multi,
+ int recovery_mode,
struct mmc_queue *mq)
{
u32 readcmd, writecmd;
@@ -1602,7 +1683,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct mmc_blk_data *md = mq->blkdata;
bool do_rel_wr, do_data_tag;
- mmc_blk_data_prep(mq, mqrq, disable_multi, &do_rel_wr, &do_data_tag);
+ mmc_blk_data_prep(mq, mqrq, recovery_mode, &do_rel_wr, &do_data_tag);
brq->mrq.cmd = &brq->cmd;
@@ -1646,8 +1727,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
* these, while retaining features like reliable writes.
*/
if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
- (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
- do_data_tag)) {
+ (do_rel_wr || !mmc_card_blk_no_cmd23(card) || do_data_tag)) {
brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
brq->sbc.arg = brq->data.blocks |
(do_rel_wr ? (1 << 31) : 0) |
@@ -1656,318 +1736,744 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
brq->mrq.sbc = &brq->sbc;
}
- mqrq->areq.err_check = mmc_blk_err_check;
+ if (mmc_card_ult_capacity(card)) {
+ brq->cmd.ext_addr = blk_rq_pos(req) >> 32;
+ brq->cmd.has_ext_addr = true;
+ }
}
-static bool mmc_blk_rw_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
- struct mmc_blk_request *brq, struct request *req,
- bool old_req_pending)
+#define MMC_MAX_RETRIES 5
+#define MMC_DATA_RETRIES 2
+#define MMC_NO_RETRIES (MMC_MAX_RETRIES + 1)
+
+static int mmc_blk_send_stop(struct mmc_card *card, unsigned int timeout)
{
- bool req_pending;
+ struct mmc_command cmd = {
+ .opcode = MMC_STOP_TRANSMISSION,
+ .flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC,
+ /* Some hosts wait for busy anyway, so provide a busy timeout */
+ .busy_timeout = timeout,
+ };
+
+ return mmc_wait_for_cmd(card->host, &cmd, 5);
+}
+
+static int mmc_blk_fix_state(struct mmc_card *card, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_blk_request *brq = &mqrq->brq;
+ unsigned int timeout = mmc_blk_data_timeout_ms(card->host, &brq->data);
+ int err;
+
+ mmc_retune_hold_now(card->host);
+
+ mmc_blk_send_stop(card, timeout);
+
+ err = mmc_poll_for_busy(card, timeout, false, MMC_BUSY_IO);
+
+ mmc_retune_release(card->host);
+
+ return err;
+}
+
+#define MMC_READ_SINGLE_RETRIES 2
+
+/* Single (native) sector read during recovery */
+static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_request *mrq = &mqrq->brq.mrq;
+ struct mmc_card *card = mq->card;
+ struct mmc_host *host = card->host;
+ blk_status_t error = BLK_STS_OK;
+ size_t bytes_per_read = queue_physical_block_size(mq->queue);
+
+ do {
+ u32 status;
+ int err;
+ int retries = 0;
+
+ while (retries++ <= MMC_READ_SINGLE_RETRIES) {
+ mmc_blk_rw_rq_prep(mqrq, card, 1, mq);
+
+ mmc_wait_for_req(host, mrq);
+
+ err = mmc_send_status(card, &status);
+ if (err)
+ goto error_exit;
+
+ if (!mmc_host_is_spi(host) &&
+ !mmc_ready_for_data(status)) {
+ err = mmc_blk_fix_state(card, req);
+ if (err)
+ goto error_exit;
+ }
+
+ if (!mrq->cmd->error)
+ break;
+ }
+
+ if (mrq->cmd->error ||
+ mrq->data->error ||
+ (!mmc_host_is_spi(host) &&
+ (mrq->cmd->resp[0] & CMD_ERRORS || status & CMD_ERRORS)))
+ error = BLK_STS_IOERR;
+ else
+ error = BLK_STS_OK;
+
+ } while (blk_update_request(req, error, bytes_per_read));
+
+ return;
+
+error_exit:
+ mrq->data->bytes_xfered = 0;
+ blk_update_request(req, BLK_STS_IOERR, bytes_per_read);
+ /* Let it try the remaining request again */
+ if (mqrq->retries > MMC_MAX_RETRIES - 1)
+ mqrq->retries = MMC_MAX_RETRIES - 1;
+}
+
+static inline bool mmc_blk_oor_valid(struct mmc_blk_request *brq)
+{
+ return !!brq->mrq.sbc;
+}
+
+static inline u32 mmc_blk_stop_err_bits(struct mmc_blk_request *brq)
+{
+ return mmc_blk_oor_valid(brq) ? CMD_ERRORS : CMD_ERRORS_EXCL_OOR;
+}
+
+/*
+ * Check for errors the host controller driver might not have seen such as
+ * response mode errors or invalid card state.
+ */
+static bool mmc_blk_status_error(struct request *req, u32 status)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_blk_request *brq = &mqrq->brq;
+ struct mmc_queue *mq = req->q->queuedata;
+ u32 stop_err_bits;
+
+ if (mmc_host_is_spi(mq->card->host))
+ return false;
+
+ stop_err_bits = mmc_blk_stop_err_bits(brq);
+
+ return brq->cmd.resp[0] & CMD_ERRORS ||
+ brq->stop.resp[0] & stop_err_bits ||
+ status & stop_err_bits ||
+ (rq_data_dir(req) == WRITE && !mmc_ready_for_data(status));
+}
+
+static inline bool mmc_blk_cmd_started(struct mmc_blk_request *brq)
+{
+ return !brq->sbc.error && !brq->cmd.error &&
+ !(brq->cmd.resp[0] & CMD_ERRORS);
+}
+
+/*
+ * Requests are completed by mmc_blk_mq_complete_rq() which sets simple
+ * policy:
+ * 1. A request that has transferred at least some data is considered
+ * successful and will be requeued if there is remaining data to
+ * transfer.
+ * 2. Otherwise the number of retries is incremented and the request
+ * will be requeued if there are remaining retries.
+ * 3. Otherwise the request will be errored out.
+ * That means mmc_blk_mq_complete_rq() is controlled by bytes_xfered and
+ * mqrq->retries. So there are only 4 possible actions here:
+ * 1. do not accept the bytes_xfered value i.e. set it to zero
+ * 2. change mqrq->retries to determine the number of retries
+ * 3. try to reset the card
+ * 4. read one sector at a time
+ */
+static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req)
+{
+ int type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_blk_request *brq = &mqrq->brq;
+ struct mmc_blk_data *md = mq->blkdata;
+ struct mmc_card *card = mq->card;
+ u32 status;
+ u32 blocks;
+ int err;
/*
- * If this is an SD card and we're writing, we can first
- * mark the known good sectors as ok.
- *
- * If the card is not SD, we can still ok written sectors
- * as reported by the controller (which might be less than
- * the real number of written sectors, but never more).
+ * Some errors the host driver might not have seen. Set the number of
+ * bytes transferred to zero in that case.
*/
- if (mmc_card_sd(card)) {
- u32 blocks;
- int err;
+ err = __mmc_send_status(card, &status, 0);
+ if (err || mmc_blk_status_error(req, status))
+ brq->data.bytes_xfered = 0;
- err = mmc_sd_num_wr_blocks(card, &blocks);
+ mmc_retune_release(card->host);
+
+ /*
+ * Try again to get the status. This also provides an opportunity for
+ * re-tuning.
+ */
+ if (err)
+ err = __mmc_send_status(card, &status, 0);
+
+ /*
+ * Nothing more to do after the number of bytes transferred has been
+ * updated and there is no card.
+ */
+ if (err && mmc_detect_card_removed(card->host))
+ return;
+
+ /* Try to get back to "tran" state */
+ if (!mmc_host_is_spi(mq->card->host) &&
+ (err || !mmc_ready_for_data(status)))
+ err = mmc_blk_fix_state(mq->card, req);
+
+ /*
+ * Special case for SD cards where the card might record the number of
+ * blocks written.
+ */
+ if (!err && mmc_blk_cmd_started(brq) && mmc_card_sd(card) &&
+ rq_data_dir(req) == WRITE) {
+ if (mmc_sd_num_wr_blocks(card, &blocks))
+ brq->data.bytes_xfered = 0;
+ else
+ brq->data.bytes_xfered = blocks << 9;
+ }
+
+ /* Reset if the card is in a bad state */
+ if (!mmc_host_is_spi(mq->card->host) &&
+ err && mmc_blk_reset(md, card->host, type)) {
+ pr_err("%s: recovery failed!\n", req->q->disk->disk_name);
+ mqrq->retries = MMC_NO_RETRIES;
+ return;
+ }
+
+ /*
+ * If anything was done, just return and if there is anything remaining
+ * on the request it will get requeued.
+ */
+ if (brq->data.bytes_xfered)
+ return;
+
+ /* Reset before last retry */
+ if (mqrq->retries + 1 == MMC_MAX_RETRIES &&
+ mmc_blk_reset(md, card->host, type))
+ return;
+
+ /* Command errors fail fast, so use all MMC_MAX_RETRIES */
+ if (brq->sbc.error || brq->cmd.error)
+ return;
+
+ /* Reduce the remaining retries for data errors */
+ if (mqrq->retries < MMC_MAX_RETRIES - MMC_DATA_RETRIES) {
+ mqrq->retries = MMC_MAX_RETRIES - MMC_DATA_RETRIES;
+ return;
+ }
+
+ if (rq_data_dir(req) == READ && brq->data.blocks >
+ queue_physical_block_size(mq->queue) >> 9) {
+ /* Read one (native) sector at a time */
+ mmc_blk_read_single(mq, req);
+ return;
+ }
+}
+
+static inline bool mmc_blk_rq_error(struct mmc_blk_request *brq)
+{
+ mmc_blk_eval_resp_error(brq);
+
+ return brq->sbc.error || brq->cmd.error || brq->stop.error ||
+ brq->data.error || brq->cmd.resp[0] & CMD_ERRORS;
+}
+
+static int mmc_spi_err_check(struct mmc_card *card)
+{
+ u32 status = 0;
+ int err;
+
+ /*
+ * SPI does not have a TRAN state we have to wait on, instead the
+ * card is ready again when it no longer holds the line LOW.
+ * We still have to ensure two things here before we know the write
+ * was successful:
+ * 1. The card has not disconnected during busy and we actually read our
+ * own pull-up, thinking it was still connected, so ensure it
+ * still responds.
+ * 2. Check for any error bits, in particular R1_SPI_IDLE to catch a
+ * just reconnected card after being disconnected during busy.
+ */
+ err = __mmc_send_status(card, &status, 0);
+ if (err)
+ return err;
+ /* All R1 and R2 bits of SPI are errors in our case */
+ if (status)
+ return -EIO;
+ return 0;
+}
+
+static int mmc_blk_busy_cb(void *cb_data, bool *busy)
+{
+ struct mmc_blk_busy_data *data = cb_data;
+ u32 status = 0;
+ int err;
+
+ err = mmc_send_status(data->card, &status);
+ if (err)
+ return err;
+
+ /* Accumulate response error bits. */
+ data->status |= status;
+
+ *busy = !mmc_ready_for_data(status);
+ return 0;
+}
+
+static int mmc_blk_card_busy(struct mmc_card *card, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_blk_busy_data cb_data;
+ int err;
+
+ if (rq_data_dir(req) == READ)
+ return 0;
+
+ if (mmc_host_is_spi(card->host)) {
+ err = mmc_spi_err_check(card);
if (err)
- req_pending = old_req_pending;
+ mqrq->brq.data.bytes_xfered = 0;
+ return err;
+ }
+
+ cb_data.card = card;
+ cb_data.status = 0;
+ err = __mmc_poll_for_busy(card->host, 0, MMC_BLK_TIMEOUT_MS,
+ &mmc_blk_busy_cb, &cb_data);
+
+ /*
+ * Do not assume data transferred correctly if there are any error bits
+ * set.
+ */
+ if (cb_data.status & mmc_blk_stop_err_bits(&mqrq->brq)) {
+ mqrq->brq.data.bytes_xfered = 0;
+ err = err ? err : -EIO;
+ }
+
+ /* Copy the exception bit so it will be seen later on */
+ if (mmc_card_mmc(card) && cb_data.status & R1_EXCEPTION_EVENT)
+ mqrq->brq.cmd.resp[0] |= R1_EXCEPTION_EVENT;
+
+ return err;
+}
+
+static inline void mmc_blk_rw_reset_success(struct mmc_queue *mq,
+ struct request *req)
+{
+ int type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
+
+ mmc_blk_reset_success(mq->blkdata, type);
+}
+
+static void mmc_blk_mq_complete_rq(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ unsigned int nr_bytes = mqrq->brq.data.bytes_xfered;
+
+ if (nr_bytes) {
+ if (blk_update_request(req, BLK_STS_OK, nr_bytes))
+ blk_mq_requeue_request(req, true);
else
- req_pending = blk_end_request(req, 0, blocks << 9);
+ __blk_mq_end_request(req, BLK_STS_OK);
+ } else if (!blk_rq_bytes(req)) {
+ __blk_mq_end_request(req, BLK_STS_IOERR);
+ } else if (mqrq->retries++ < MMC_MAX_RETRIES) {
+ blk_mq_requeue_request(req, true);
} else {
- req_pending = blk_end_request(req, 0, brq->data.bytes_xfered);
+ if (mmc_card_removed(mq->card))
+ req->rq_flags |= RQF_QUIET;
+ blk_mq_end_request(req, BLK_STS_IOERR);
}
- return req_pending;
}
-static void mmc_blk_rw_cmd_abort(struct mmc_queue *mq, struct mmc_card *card,
- struct request *req,
+static bool mmc_blk_urgent_bkops_needed(struct mmc_queue *mq,
+ struct mmc_queue_req *mqrq)
+{
+ return mmc_card_mmc(mq->card) && !mmc_host_is_spi(mq->card->host) &&
+ (mqrq->brq.cmd.resp[0] & R1_EXCEPTION_EVENT ||
+ mqrq->brq.stop.resp[0] & R1_EXCEPTION_EVENT);
+}
+
+static void mmc_blk_urgent_bkops(struct mmc_queue *mq,
struct mmc_queue_req *mqrq)
{
- if (mmc_card_removed(card))
- req->rq_flags |= RQF_QUIET;
- while (blk_end_request(req, BLK_STS_IOERR, blk_rq_cur_bytes(req)));
- mq->qcnt--;
+ if (mmc_blk_urgent_bkops_needed(mq, mqrq))
+ mmc_run_bkops(mq->card);
}
-/**
- * mmc_blk_rw_try_restart() - tries to restart the current async request
- * @mq: the queue with the card and host to restart
- * @req: a new request that want to be started after the current one
- */
-static void mmc_blk_rw_try_restart(struct mmc_queue *mq, struct request *req,
- struct mmc_queue_req *mqrq)
+static void mmc_blk_hsq_req_done(struct mmc_request *mrq)
{
- if (!req)
+ struct mmc_queue_req *mqrq =
+ container_of(mrq, struct mmc_queue_req, brq.mrq);
+ struct request *req = mmc_queue_req_to_req(mqrq);
+ struct request_queue *q = req->q;
+ struct mmc_queue *mq = q->queuedata;
+ struct mmc_host *host = mq->card->host;
+ unsigned long flags;
+
+ if (mmc_blk_rq_error(&mqrq->brq) ||
+ mmc_blk_urgent_bkops_needed(mq, mqrq)) {
+ spin_lock_irqsave(&mq->lock, flags);
+ mq->recovery_needed = true;
+ mq->recovery_req = req;
+ spin_unlock_irqrestore(&mq->lock, flags);
+
+ host->cqe_ops->cqe_recovery_start(host);
+
+ schedule_work(&mq->recovery_work);
return;
+ }
+
+ mmc_blk_rw_reset_success(mq, req);
/*
- * If the card was removed, just cancel everything and return.
+ * Block layer timeouts race with completions which means the normal
+ * completion path cannot be used during recovery.
*/
- if (mmc_card_removed(mq->card)) {
- req->rq_flags |= RQF_QUIET;
- blk_end_request_all(req, BLK_STS_IOERR);
- mq->qcnt--; /* FIXME: just set to 0? */
- return;
+ if (mq->in_recovery)
+ mmc_blk_cqe_complete_rq(mq, req);
+ else if (likely(!blk_should_fake_timeout(req->q)))
+ blk_mq_complete_request(req);
+}
+
+void mmc_blk_mq_complete(struct request *req)
+{
+ struct mmc_queue *mq = req->q->queuedata;
+ struct mmc_host *host = mq->card->host;
+
+ if (host->cqe_enabled)
+ mmc_blk_cqe_complete_rq(mq, req);
+ else if (likely(!blk_should_fake_timeout(req->q)))
+ mmc_blk_mq_complete_rq(mq, req);
+}
+
+static void mmc_blk_mq_poll_completion(struct mmc_queue *mq,
+ struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_host *host = mq->card->host;
+
+ if (mmc_blk_rq_error(&mqrq->brq) ||
+ mmc_blk_card_busy(mq->card, req)) {
+ mmc_blk_mq_rw_recovery(mq, req);
+ } else {
+ mmc_blk_rw_reset_success(mq, req);
+ mmc_retune_release(host);
}
- /* Else proceed and try to restart the current async request */
- mmc_blk_rw_rq_prep(mqrq, mq->card, 0, mq);
- mmc_start_areq(mq->card->host, &mqrq->areq, NULL);
+
+ mmc_blk_urgent_bkops(mq, mqrq);
}
-static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req)
+static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, enum mmc_issue_type issue_type)
{
- struct mmc_blk_data *md = mq->blkdata;
- struct mmc_card *card = md->queue.card;
- struct mmc_blk_request *brq;
- int disable_multi = 0, retry = 0, type, retune_retry_done = 0;
- enum mmc_blk_status status;
- struct mmc_queue_req *mqrq_cur = NULL;
- struct mmc_queue_req *mq_rq;
- struct request *old_req;
- struct mmc_async_req *new_areq;
- struct mmc_async_req *old_areq;
- bool req_pending = true;
+ unsigned long flags;
+ bool put_card;
+
+ spin_lock_irqsave(&mq->lock, flags);
+
+ mq->in_flight[issue_type] -= 1;
+
+ put_card = (mmc_tot_in_flight(mq) == 0);
+
+ spin_unlock_irqrestore(&mq->lock, flags);
+
+ if (put_card)
+ mmc_put_card(mq->card, &mq->ctx);
+}
+
+static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req,
+ bool can_sleep)
+{
+ enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_request *mrq = &mqrq->brq.mrq;
+ struct mmc_host *host = mq->card->host;
+
+ mmc_post_req(host, mrq, 0);
- if (new_req) {
- mqrq_cur = req_to_mmc_queue_req(new_req);
- mq->qcnt++;
+ /*
+ * Block layer timeouts race with completions which means the normal
+ * completion path cannot be used during recovery.
+ */
+ if (mq->in_recovery) {
+ mmc_blk_mq_complete_rq(mq, req);
+ } else if (likely(!blk_should_fake_timeout(req->q))) {
+ if (can_sleep)
+ blk_mq_complete_request_direct(req, mmc_blk_mq_complete);
+ else
+ blk_mq_complete_request(req);
}
- if (!mq->qcnt)
+ mmc_blk_mq_dec_in_flight(mq, issue_type);
+}
+
+void mmc_blk_mq_recovery(struct mmc_queue *mq)
+{
+ struct request *req = mq->recovery_req;
+ struct mmc_host *host = mq->card->host;
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+
+ mq->recovery_req = NULL;
+ mq->rw_wait = false;
+
+ if (mmc_blk_rq_error(&mqrq->brq)) {
+ mmc_retune_hold_now(host);
+ mmc_blk_mq_rw_recovery(mq, req);
+ }
+
+ mmc_blk_urgent_bkops(mq, mqrq);
+
+ mmc_blk_mq_post_req(mq, req, true);
+}
+
+static void mmc_blk_mq_complete_prev_req(struct mmc_queue *mq,
+ struct request **prev_req)
+{
+ if (mmc_host_can_done_complete(mq->card->host))
return;
- do {
- if (new_req) {
- /*
- * When 4KB native sector is enabled, only 8 blocks
- * multiple read or write is allowed
- */
- if (mmc_large_sector(card) &&
- !IS_ALIGNED(blk_rq_sectors(new_req), 8)) {
- pr_err("%s: Transfer size is not 4KB sector size aligned\n",
- new_req->rq_disk->disk_name);
- mmc_blk_rw_cmd_abort(mq, card, new_req, mqrq_cur);
- return;
- }
+ mutex_lock(&mq->complete_lock);
- mmc_blk_rw_rq_prep(mqrq_cur, card, 0, mq);
- new_areq = &mqrq_cur->areq;
- } else
- new_areq = NULL;
+ if (!mq->complete_req)
+ goto out_unlock;
- old_areq = mmc_start_areq(card->host, new_areq, &status);
- if (!old_areq) {
- /*
- * We have just put the first request into the pipeline
- * and there is nothing more to do until it is
- * complete.
- */
- return;
- }
+ mmc_blk_mq_poll_completion(mq, mq->complete_req);
+
+ if (prev_req)
+ *prev_req = mq->complete_req;
+ else
+ mmc_blk_mq_post_req(mq, mq->complete_req, true);
+
+ mq->complete_req = NULL;
+
+out_unlock:
+ mutex_unlock(&mq->complete_lock);
+}
+
+void mmc_blk_mq_complete_work(struct work_struct *work)
+{
+ struct mmc_queue *mq = container_of(work, struct mmc_queue,
+ complete_work);
+
+ mmc_blk_mq_complete_prev_req(mq, NULL);
+}
+
+static void mmc_blk_mq_req_done(struct mmc_request *mrq)
+{
+ struct mmc_queue_req *mqrq = container_of(mrq, struct mmc_queue_req,
+ brq.mrq);
+ struct request *req = mmc_queue_req_to_req(mqrq);
+ struct request_queue *q = req->q;
+ struct mmc_queue *mq = q->queuedata;
+ struct mmc_host *host = mq->card->host;
+ unsigned long flags;
+
+ if (!mmc_host_can_done_complete(host)) {
+ bool waiting;
/*
- * An asynchronous request has been completed and we proceed
- * to handle the result of it.
+ * We cannot complete the request in this context, so record
+ * that there is a request to complete, and that a following
+ * request does not need to wait (although it does need to
+ * complete complete_req first).
*/
- mq_rq = container_of(old_areq, struct mmc_queue_req, areq);
- brq = &mq_rq->brq;
- old_req = mmc_queue_req_to_req(mq_rq);
- type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
- mmc_queue_bounce_post(mq_rq);
-
- switch (status) {
- case MMC_BLK_SUCCESS:
- case MMC_BLK_PARTIAL:
- /*
- * A block was successfully transferred.
- */
- mmc_blk_reset_success(md, type);
+ spin_lock_irqsave(&mq->lock, flags);
+ mq->complete_req = req;
+ mq->rw_wait = false;
+ waiting = mq->waiting;
+ spin_unlock_irqrestore(&mq->lock, flags);
- req_pending = blk_end_request(old_req, BLK_STS_OK,
- brq->data.bytes_xfered);
- /*
- * If the blk_end_request function returns non-zero even
- * though all data has been transferred and no errors
- * were returned by the host controller, it's a bug.
- */
- if (status == MMC_BLK_SUCCESS && req_pending) {
- pr_err("%s BUG rq_tot %d d_xfer %d\n",
- __func__, blk_rq_bytes(old_req),
- brq->data.bytes_xfered);
- mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
- return;
- }
- break;
- case MMC_BLK_CMD_ERR:
- req_pending = mmc_blk_rw_cmd_err(md, card, brq, old_req, req_pending);
- if (mmc_blk_reset(md, card->host, type)) {
- if (req_pending)
- mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
- else
- mq->qcnt--;
- mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
- return;
- }
- if (!req_pending) {
- mq->qcnt--;
- mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
- return;
- }
- break;
- case MMC_BLK_RETRY:
- retune_retry_done = brq->retune_retry_done;
- if (retry++ < 5)
- break;
- /* Fall through */
- case MMC_BLK_ABORT:
- if (!mmc_blk_reset(md, card->host, type))
- break;
- mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
- mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
- return;
- case MMC_BLK_DATA_ERR: {
- int err;
-
- err = mmc_blk_reset(md, card->host, type);
- if (!err)
- break;
- if (err == -ENODEV) {
- mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
- mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
- return;
- }
- /* Fall through */
- }
- case MMC_BLK_ECC_ERR:
- if (brq->data.blocks > 1) {
- /* Redo read one sector at a time */
- pr_warn("%s: retrying using single block read\n",
- old_req->rq_disk->disk_name);
- disable_multi = 1;
- break;
- }
- /*
- * After an error, we redo I/O one sector at a
- * time, so we only reach here after trying to
- * read a single sector.
- */
- req_pending = blk_end_request(old_req, BLK_STS_IOERR,
- brq->data.blksz);
- if (!req_pending) {
- mq->qcnt--;
- mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
- return;
- }
- break;
- case MMC_BLK_NOMEDIUM:
- mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
- mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
- return;
- default:
- pr_err("%s: Unhandled return value (%d)",
- old_req->rq_disk->disk_name, status);
- mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
- mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
- return;
- }
+ /*
+ * If 'waiting' then the waiting task will complete this
+ * request, otherwise queue a work to do it. Note that
+ * complete_work may still race with the dispatch of a following
+ * request.
+ */
+ if (waiting)
+ wake_up(&mq->wait);
+ else
+ queue_work(mq->card->complete_wq, &mq->complete_work);
- if (req_pending) {
- /*
- * In case of a incomplete request
- * prepare it again and resend.
- */
- mmc_blk_rw_rq_prep(mq_rq, card,
- disable_multi, mq);
- mmc_start_areq(card->host,
- &mq_rq->areq, NULL);
- mq_rq->brq.retune_retry_done = retune_retry_done;
- }
- } while (req_pending);
+ return;
+ }
+
+ /* Take the recovery path for errors or urgent background operations */
+ if (mmc_blk_rq_error(&mqrq->brq) ||
+ mmc_blk_urgent_bkops_needed(mq, mqrq)) {
+ spin_lock_irqsave(&mq->lock, flags);
+ mq->recovery_needed = true;
+ mq->recovery_req = req;
+ spin_unlock_irqrestore(&mq->lock, flags);
+ wake_up(&mq->wait);
+ schedule_work(&mq->recovery_work);
+ return;
+ }
- mq->qcnt--;
+ mmc_blk_rw_reset_success(mq, req);
+
+ mq->rw_wait = false;
+ wake_up(&mq->wait);
+
+ /* context unknown */
+ mmc_blk_mq_post_req(mq, req, false);
}
-void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+static bool mmc_blk_rw_wait_cond(struct mmc_queue *mq, int *err)
+{
+ unsigned long flags;
+ bool done;
+
+ /*
+ * Wait while there is another request in progress, but not if recovery
+ * is needed. Also indicate whether there is a request waiting to start.
+ */
+ spin_lock_irqsave(&mq->lock, flags);
+ if (mq->recovery_needed) {
+ *err = -EBUSY;
+ done = true;
+ } else {
+ done = !mq->rw_wait;
+ }
+ mq->waiting = !done;
+ spin_unlock_irqrestore(&mq->lock, flags);
+
+ return done;
+}
+
+static int mmc_blk_rw_wait(struct mmc_queue *mq, struct request **prev_req)
+{
+ int err = 0;
+
+ wait_event(mq->wait, mmc_blk_rw_wait_cond(mq, &err));
+
+ /* Always complete the previous request if there is one */
+ mmc_blk_mq_complete_prev_req(mq, prev_req);
+
+ return err;
+}
+
+static int mmc_blk_mq_issue_rw_rq(struct mmc_queue *mq,
+ struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_host *host = mq->card->host;
+ struct request *prev_req = NULL;
+ int err = 0;
+
+ mmc_blk_rw_rq_prep(mqrq, mq->card, 0, mq);
+
+ mqrq->brq.mrq.done = mmc_blk_mq_req_done;
+
+ mmc_pre_req(host, &mqrq->brq.mrq);
+
+ err = mmc_blk_rw_wait(mq, &prev_req);
+ if (err)
+ goto out_post_req;
+
+ mq->rw_wait = true;
+
+ err = mmc_start_request(host, &mqrq->brq.mrq);
+
+ if (prev_req)
+ mmc_blk_mq_post_req(mq, prev_req, true);
+
+ if (err)
+ mq->rw_wait = false;
+
+ /* Release re-tuning here where there is no synchronization required */
+ if (err || mmc_host_can_done_complete(host))
+ mmc_retune_release(host);
+
+out_post_req:
+ if (err)
+ mmc_post_req(host, &mqrq->brq.mrq, err);
+
+ return err;
+}
+
+static int mmc_blk_wait_for_idle(struct mmc_queue *mq, struct mmc_host *host)
+{
+ if (host->cqe_enabled)
+ return host->cqe_ops->cqe_wait_for_idle(host);
+
+ return mmc_blk_rw_wait(mq, NULL);
+}
+
+enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req)
{
- int ret;
struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card;
+ struct mmc_host *host = card->host;
+ int ret;
- if (req && !mq->qcnt)
- /* claim host only for the first request */
- mmc_get_card(card);
-
- ret = mmc_blk_part_switch(card, md);
- if (ret) {
- if (req) {
- blk_end_request_all(req, BLK_STS_IOERR);
- }
- goto out;
- }
+ ret = mmc_blk_part_switch(card, md->part_type);
+ if (ret)
+ return MMC_REQ_FAILED_TO_START;
- if (req) {
+ switch (mmc_issue_type(mq, req)) {
+ case MMC_ISSUE_SYNC:
+ ret = mmc_blk_wait_for_idle(mq, host);
+ if (ret)
+ return MMC_REQ_BUSY;
switch (req_op(req)) {
case REQ_OP_DRV_IN:
case REQ_OP_DRV_OUT:
- /*
- * Complete ongoing async transfer before issuing
- * ioctl()s
- */
- if (mq->qcnt)
- mmc_blk_issue_rw_rq(mq, NULL);
mmc_blk_issue_drv_op(mq, req);
break;
case REQ_OP_DISCARD:
- /*
- * Complete ongoing async transfer before issuing
- * discard.
- */
- if (mq->qcnt)
- mmc_blk_issue_rw_rq(mq, NULL);
mmc_blk_issue_discard_rq(mq, req);
break;
case REQ_OP_SECURE_ERASE:
- /*
- * Complete ongoing async transfer before issuing
- * secure erase.
- */
- if (mq->qcnt)
- mmc_blk_issue_rw_rq(mq, NULL);
mmc_blk_issue_secdiscard_rq(mq, req);
break;
+ case REQ_OP_WRITE_ZEROES:
+ mmc_blk_issue_trim_rq(mq, req);
+ break;
case REQ_OP_FLUSH:
- /*
- * Complete ongoing async transfer before issuing
- * flush.
- */
- if (mq->qcnt)
- mmc_blk_issue_rw_rq(mq, NULL);
mmc_blk_issue_flush(mq, req);
break;
default:
- /* Normal request, just issue it */
- mmc_blk_issue_rw_rq(mq, req);
- card->host->context_info.is_waiting_last_req = false;
+ WARN_ON_ONCE(1);
+ return MMC_REQ_FAILED_TO_START;
+ }
+ return MMC_REQ_FINISHED;
+ case MMC_ISSUE_DCMD:
+ case MMC_ISSUE_ASYNC:
+ switch (req_op(req)) {
+ case REQ_OP_FLUSH:
+ if (!mmc_cache_enabled(host)) {
+ blk_mq_end_request(req, BLK_STS_OK);
+ return MMC_REQ_FINISHED;
+ }
+ ret = mmc_blk_cqe_issue_flush(mq, req);
break;
+ case REQ_OP_WRITE:
+ card->written_flag = true;
+ fallthrough;
+ case REQ_OP_READ:
+ if (host->cqe_enabled)
+ ret = mmc_blk_cqe_issue_rw_rq(mq, req);
+ else
+ ret = mmc_blk_mq_issue_rw_rq(mq, req);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ ret = -EINVAL;
}
- } else {
- /* No request, flushing the pipeline with NULL */
- mmc_blk_issue_rw_rq(mq, NULL);
- card->host->context_info.is_waiting_last_req = false;
+ if (!ret)
+ return MMC_REQ_STARTED;
+ return ret == -EBUSY ? MMC_REQ_BUSY : MMC_REQ_FAILED_TO_START;
+ default:
+ WARN_ON_ONCE(1);
+ return MMC_REQ_FAILED_TO_START;
}
-
-out:
- if (!mq->qcnt)
- mmc_put_card(card);
}
static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -1976,21 +2482,87 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
!(card->csd.cmdclass & CCC_BLOCK_WRITE);
}
+/*
+ * Search for a declared partitions node for the disk in mmc-card related node.
+ *
+ * This is to permit support for partition table defined in DT in special case
+ * where a partition table is not written in the disk and is expected to be
+ * passed from the running system.
+ *
+ * For the user disk, "partitions" node is searched.
+ * For the special HW disk, "partitions-" node with the appended name is used
+ * following this conversion table (to adhere to JEDEC naming)
+ * - boot0 -> partitions-boot1
+ * - boot1 -> partitions-boot2
+ * - gp0 -> partitions-gp1
+ * - gp1 -> partitions-gp2
+ * - gp2 -> partitions-gp3
+ * - gp3 -> partitions-gp4
+ */
+static struct fwnode_handle *mmc_blk_get_partitions_node(struct device *mmc_dev,
+ const char *subname)
+{
+ const char *node_name = "partitions";
+
+ if (subname) {
+ mmc_dev = mmc_dev->parent;
+
+ /*
+ * Check if we are allocating a BOOT disk boot0/1 disk.
+ * In DT we use the JEDEC naming boot1/2.
+ */
+ if (!strcmp(subname, "boot0"))
+ node_name = "partitions-boot1";
+ if (!strcmp(subname, "boot1"))
+ node_name = "partitions-boot2";
+ /*
+ * Check if we are allocating a GP disk gp0/1/2/3 disk.
+ * In DT we use the JEDEC naming gp1/2/3/4.
+ */
+ if (!strcmp(subname, "gp0"))
+ node_name = "partitions-gp1";
+ if (!strcmp(subname, "gp1"))
+ node_name = "partitions-gp2";
+ if (!strcmp(subname, "gp2"))
+ node_name = "partitions-gp3";
+ if (!strcmp(subname, "gp3"))
+ node_name = "partitions-gp4";
+ }
+
+ return device_get_named_child_node(mmc_dev, node_name);
+}
+
static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
struct device *parent,
sector_t size,
bool default_ro,
const char *subname,
- int area_type)
+ int area_type,
+ unsigned int part_type)
{
+ struct fwnode_handle *disk_fwnode;
struct mmc_blk_data *md;
int devidx, ret;
+ char cap_str[10];
+ unsigned int features = 0;
+
+ devidx = ida_alloc_max(&mmc_blk_ida, max_devices - 1, GFP_KERNEL);
+ if (devidx < 0) {
+ /*
+ * We get -ENOSPC because there are no more any available
+ * devidx. The reason may be that, either userspace haven't yet
+ * unmounted the partitions, which postpones mmc_blk_release()
+ * from being called, or the device has more partitions than
+ * what we support.
+ */
+ if (devidx == -ENOSPC)
+ dev_err(mmc_dev(card->host),
+ "no more device IDs available\n");
- devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL);
- if (devidx < 0)
return ERR_PTR(devidx);
+ }
- md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
+ md = kzalloc(sizeof(*md), GFP_KERNEL);
if (!md) {
ret = -ENOMEM;
goto out;
@@ -2004,32 +2576,40 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
*/
md->read_only = mmc_blk_readonly(card);
- md->disk = alloc_disk(perdev_minors);
- if (md->disk == NULL) {
- ret = -ENOMEM;
+ if (mmc_host_can_cmd23(card->host) && mmc_card_can_cmd23(card))
+ md->flags |= MMC_BLK_CMD23;
+
+ if (md->flags & MMC_BLK_CMD23 &&
+ ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||
+ card->ext_csd.rel_sectors)) {
+ md->flags |= MMC_BLK_REL_WR;
+ features |= (BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA);
+ } else if (mmc_cache_enabled(card->host)) {
+ features |= BLK_FEAT_WRITE_CACHE;
+ }
+
+ md->disk = mmc_init_queue(&md->queue, card, features);
+ if (IS_ERR(md->disk)) {
+ ret = PTR_ERR(md->disk);
goto err_kfree;
}
- spin_lock_init(&md->lock);
INIT_LIST_HEAD(&md->part);
- md->usage = 1;
-
- ret = mmc_init_queue(&md->queue, card, &md->lock, subname);
- if (ret)
- goto err_putdisk;
+ INIT_LIST_HEAD(&md->rpmbs);
+ kref_init(&md->kref);
md->queue.blkdata = md;
+ md->part_type = part_type;
md->disk->major = MMC_BLOCK_MAJOR;
+ md->disk->minors = perdev_minors;
md->disk->first_minor = devidx * perdev_minors;
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
- md->disk->queue = md->queue.queue;
md->parent = parent;
set_disk_ro(md->disk, md->read_only || default_ro);
- md->disk->flags = GENHD_FL_EXT_DEVT;
- if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
- md->disk->flags |= GENHD_FL_NO_PART_SCAN;
+ if (area_type & MMC_BLK_DATA_AREA_RPMB)
+ md->disk->flags |= GENHD_FL_NO_PART;
/*
* As discussed on lkml, GENHD_FL_REMOVABLE should:
@@ -2046,38 +2626,31 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
"mmcblk%u%s", card->host->index, subname ? subname : "");
- if (mmc_card_mmc(card))
- blk_queue_logical_block_size(md->queue.queue,
- card->ext_csd.data_sector_size);
- else
- blk_queue_logical_block_size(md->queue.queue, 512);
-
set_capacity(md->disk, size);
- if (mmc_host_cmd23(card->host)) {
- if ((mmc_card_mmc(card) &&
- card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
- (mmc_card_sd(card) &&
- card->scr.cmds & SD_SCR_CMD23_SUPPORT))
- md->flags |= MMC_BLK_CMD23;
- }
-
- if (mmc_card_mmc(card) &&
- md->flags & MMC_BLK_CMD23 &&
- ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||
- card->ext_csd.rel_sectors)) {
- md->flags |= MMC_BLK_REL_WR;
- blk_queue_write_cache(md->queue.queue, true, true);
- }
-
+ string_get_size((u64)size, 512, STRING_UNITS_2,
+ cap_str, sizeof(cap_str));
+ pr_info("%s: %s %s %s%s\n",
+ md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
+ cap_str, md->read_only ? " (ro)" : "");
+
+ /* used in ->open, must be set before add_disk: */
+ if (area_type == MMC_BLK_DATA_AREA_MAIN)
+ dev_set_drvdata(&card->dev, md);
+ disk_fwnode = mmc_blk_get_partitions_node(parent, subname);
+ ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups,
+ disk_fwnode);
+ if (ret)
+ goto err_put_disk;
return md;
- err_putdisk:
+ err_put_disk:
put_disk(md->disk);
+ blk_mq_free_tag_set(&md->queue.tag_set);
err_kfree:
kfree(md);
out:
- ida_simple_remove(&mmc_blk_ida, devidx);
+ ida_free(&mmc_blk_ida, devidx);
return ERR_PTR(ret);
}
@@ -2101,7 +2674,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
}
return mmc_blk_alloc_req(card, &card->dev, size, false, NULL,
- MMC_BLK_DATA_AREA_MAIN);
+ MMC_BLK_DATA_AREA_MAIN, 0);
}
static int mmc_blk_alloc_part(struct mmc_card *card,
@@ -2112,22 +2685,313 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
const char *subname,
int area_type)
{
- char cap_str[10];
struct mmc_blk_data *part_md;
part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
- subname, area_type);
+ subname, area_type, part_type);
if (IS_ERR(part_md))
return PTR_ERR(part_md);
- part_md->part_type = part_type;
list_add(&part_md->part, &md->part);
- string_get_size((u64)get_capacity(part_md->disk), 512, STRING_UNITS_2,
+ return 0;
+}
+
+/**
+ * mmc_rpmb_ioctl() - ioctl handler for the RPMB chardev
+ * @filp: the character device file
+ * @cmd: the ioctl() command
+ * @arg: the argument from userspace
+ *
+ * This will essentially just redirect the ioctl()s coming in over to
+ * the main block device spawning the RPMB character device.
+ */
+static long mmc_rpmb_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mmc_rpmb_data *rpmb = filp->private_data;
+ int ret;
+
+ switch (cmd) {
+ case MMC_IOC_CMD:
+ ret = mmc_blk_ioctl_cmd(rpmb->md,
+ (struct mmc_ioc_cmd __user *)arg,
+ rpmb);
+ break;
+ case MMC_IOC_MULTI_CMD:
+ ret = mmc_blk_ioctl_multi_cmd(rpmb->md,
+ (struct mmc_ioc_multi_cmd __user *)arg,
+ rpmb);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long mmc_rpmb_ioctl_compat(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ return mmc_rpmb_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static int mmc_rpmb_chrdev_open(struct inode *inode, struct file *filp)
+{
+ struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
+ struct mmc_rpmb_data, chrdev);
+
+ get_device(&rpmb->dev);
+ filp->private_data = rpmb;
+
+ return nonseekable_open(inode, filp);
+}
+
+static int mmc_rpmb_chrdev_release(struct inode *inode, struct file *filp)
+{
+ struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
+ struct mmc_rpmb_data, chrdev);
+
+ put_device(&rpmb->dev);
+
+ return 0;
+}
+
+static const struct file_operations mmc_rpmb_fileops = {
+ .release = mmc_rpmb_chrdev_release,
+ .open = mmc_rpmb_chrdev_open,
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = mmc_rpmb_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = mmc_rpmb_ioctl_compat,
+#endif
+};
+
+static void mmc_blk_rpmb_device_release(struct device *dev)
+{
+ struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev);
+
+ rpmb_dev_unregister(rpmb->rdev);
+ mmc_blk_put(rpmb->md);
+ ida_free(&mmc_rpmb_ida, rpmb->id);
+ kfree(rpmb);
+}
+
+static void free_idata(struct mmc_blk_ioc_data **idata, unsigned int cmd_count)
+{
+ unsigned int n;
+
+ for (n = 0; n < cmd_count; n++)
+ kfree(idata[n]);
+ kfree(idata);
+}
+
+static struct mmc_blk_ioc_data **alloc_idata(struct mmc_rpmb_data *rpmb,
+ unsigned int cmd_count)
+{
+ struct mmc_blk_ioc_data **idata;
+ unsigned int n;
+
+ idata = kcalloc(cmd_count, sizeof(*idata), GFP_KERNEL);
+ if (!idata)
+ return NULL;
+
+ for (n = 0; n < cmd_count; n++) {
+ idata[n] = kcalloc(1, sizeof(**idata), GFP_KERNEL);
+ if (!idata[n]) {
+ free_idata(idata, n);
+ return NULL;
+ }
+ idata[n]->rpmb = rpmb;
+ }
+
+ return idata;
+}
+
+static void set_idata(struct mmc_blk_ioc_data *idata, u32 opcode,
+ int write_flag, u8 *buf, unsigned int buf_bytes)
+{
+ /*
+ * The size of an RPMB frame must match what's expected by the
+ * hardware.
+ */
+ static_assert(!CHECK_SIZE_NEQ(512), "RPMB frame size must be 512 bytes");
+
+ idata->ic.opcode = opcode;
+ idata->ic.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ idata->ic.write_flag = write_flag;
+ idata->ic.blksz = RPMB_FRAME_SIZE;
+ idata->ic.blocks = buf_bytes / idata->ic.blksz;
+ idata->buf = buf;
+ idata->buf_bytes = buf_bytes;
+}
+
+static int mmc_route_rpmb_frames(struct device *dev, u8 *req,
+ unsigned int req_len, u8 *resp,
+ unsigned int resp_len)
+{
+ struct rpmb_frame *frm = (struct rpmb_frame *)req;
+ struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev);
+ struct mmc_blk_data *md = rpmb->md;
+ struct mmc_blk_ioc_data **idata;
+ struct mmc_queue_req *mq_rq;
+ unsigned int cmd_count;
+ struct request *rq;
+ u16 req_type;
+ bool write;
+ int ret;
+
+ if (IS_ERR(md->queue.card))
+ return PTR_ERR(md->queue.card);
+
+ if (req_len < RPMB_FRAME_SIZE)
+ return -EINVAL;
+
+ req_type = be16_to_cpu(frm->req_resp);
+ switch (req_type) {
+ case RPMB_PROGRAM_KEY:
+ if (CHECK_SIZE_NEQ(req_len) || CHECK_SIZE_NEQ(resp_len))
+ return -EINVAL;
+ write = true;
+ break;
+ case RPMB_GET_WRITE_COUNTER:
+ if (CHECK_SIZE_NEQ(req_len) || CHECK_SIZE_NEQ(resp_len))
+ return -EINVAL;
+ write = false;
+ break;
+ case RPMB_WRITE_DATA:
+ if (!CHECK_SIZE_ALIGNED(req_len) || CHECK_SIZE_NEQ(resp_len))
+ return -EINVAL;
+ write = true;
+ break;
+ case RPMB_READ_DATA:
+ if (CHECK_SIZE_NEQ(req_len) || !CHECK_SIZE_ALIGNED(resp_len))
+ return -EINVAL;
+ write = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Write operations require 3 commands, read operations require 2 */
+ cmd_count = write ? 3 : 2;
+
+ idata = alloc_idata(rpmb, cmd_count);
+ if (!idata)
+ return -ENOMEM;
+
+ if (write) {
+ struct rpmb_frame *resp_frm = (struct rpmb_frame *)resp;
+
+ /* Send write request frame(s) */
+ set_idata(idata[0], MMC_WRITE_MULTIPLE_BLOCK,
+ 1 | MMC_CMD23_ARG_REL_WR, req, req_len);
+
+ /* Send result request frame */
+ memset(resp_frm, 0, RPMB_FRAME_SIZE);
+ resp_frm->req_resp = cpu_to_be16(RPMB_RESULT_READ);
+ set_idata(idata[1], MMC_WRITE_MULTIPLE_BLOCK, 1, resp,
+ resp_len);
+
+ /* Read response frame */
+ set_idata(idata[2], MMC_READ_MULTIPLE_BLOCK, 0, resp, resp_len);
+ } else {
+ /* Send write request frame(s) */
+ set_idata(idata[0], MMC_WRITE_MULTIPLE_BLOCK, 1, req, req_len);
+
+ /* Read response frame */
+ set_idata(idata[1], MMC_READ_MULTIPLE_BLOCK, 0, resp, resp_len);
+ }
+
+ rq = blk_mq_alloc_request(md->queue.queue, REQ_OP_DRV_OUT, 0);
+ if (IS_ERR(rq)) {
+ ret = PTR_ERR(rq);
+ goto out;
+ }
+
+ mq_rq = req_to_mmc_queue_req(rq);
+ mq_rq->drv_op = MMC_DRV_OP_IOCTL_RPMB;
+ mq_rq->drv_op_result = -EIO;
+ mq_rq->drv_op_data = idata;
+ mq_rq->ioc_count = cmd_count;
+ blk_execute_rq(rq, false);
+ ret = req_to_mmc_queue_req(rq)->drv_op_result;
+
+ blk_mq_free_request(rq);
+
+out:
+ free_idata(idata, cmd_count);
+ return ret;
+}
+
+static int mmc_blk_alloc_rpmb_part(struct mmc_card *card,
+ struct mmc_blk_data *md,
+ unsigned int part_index,
+ sector_t size,
+ const char *subname)
+{
+ int devidx, ret;
+ char rpmb_name[DISK_NAME_LEN];
+ char cap_str[10];
+ struct mmc_rpmb_data *rpmb;
+
+ /* This creates the minor number for the RPMB char device */
+ devidx = ida_alloc_max(&mmc_rpmb_ida, max_devices - 1, GFP_KERNEL);
+ if (devidx < 0)
+ return devidx;
+
+ rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL);
+ if (!rpmb) {
+ ida_free(&mmc_rpmb_ida, devidx);
+ return -ENOMEM;
+ }
+
+ snprintf(rpmb_name, sizeof(rpmb_name),
+ "mmcblk%u%s", card->host->index, subname ? subname : "");
+
+ rpmb->id = devidx;
+ rpmb->part_index = part_index;
+ rpmb->dev.init_name = rpmb_name;
+ rpmb->dev.bus = &mmc_rpmb_bus_type;
+ rpmb->dev.devt = MKDEV(MAJOR(mmc_rpmb_devt), rpmb->id);
+ rpmb->dev.parent = &card->dev;
+ rpmb->dev.release = mmc_blk_rpmb_device_release;
+ device_initialize(&rpmb->dev);
+ dev_set_drvdata(&rpmb->dev, rpmb);
+ mmc_blk_get(md->disk);
+ rpmb->md = md;
+
+ cdev_init(&rpmb->chrdev, &mmc_rpmb_fileops);
+ rpmb->chrdev.owner = THIS_MODULE;
+ ret = cdev_device_add(&rpmb->chrdev, &rpmb->dev);
+ if (ret) {
+ pr_err("%s: could not add character device\n", rpmb_name);
+ goto out_put_device;
+ }
+
+ list_add(&rpmb->node, &md->rpmbs);
+
+ string_get_size((u64)size, 512, STRING_UNITS_2,
cap_str, sizeof(cap_str));
- pr_info("%s: %s %s partition %u %s\n",
- part_md->disk->disk_name, mmc_card_id(card),
- mmc_card_name(card), part_md->part_type, cap_str);
+
+ pr_info("%s: %s %s %s, chardev (%d:%d)\n",
+ rpmb_name, mmc_card_id(card), mmc_card_name(card), cap_str,
+ MAJOR(mmc_rpmb_devt), rpmb->id);
+
return 0;
+
+out_put_device:
+ put_device(&rpmb->dev);
+ return ret;
+}
+
+static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb)
+
+{
+ cdev_device_del(&rpmb->chrdev, &rpmb->dev);
+ put_device(&rpmb->dev);
}
/* MMC Physical partitions consist of two boot partitions and
@@ -2138,13 +3002,26 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
{
- int idx, ret = 0;
+ int idx, ret;
if (!mmc_card_mmc(card))
return 0;
for (idx = 0; idx < card->nr_parts; idx++) {
- if (card->part[idx].size) {
+ if (card->part[idx].area_type & MMC_BLK_DATA_AREA_RPMB) {
+ /*
+ * RPMB partitions does not provide block access, they
+ * are only accessed using ioctl():s. Thus create
+ * special RPMB block devices that do not have a
+ * backing block queue for these.
+ */
+ ret = mmc_blk_alloc_rpmb_part(card, md,
+ card->part[idx].part_cfg,
+ card->part[idx].size >> 9,
+ card->part[idx].name);
+ if (ret)
+ return ret;
+ } else if (card->part[idx].size) {
ret = mmc_blk_alloc_part(card, md,
card->part[idx].part_cfg,
card->part[idx].size >> 9,
@@ -2156,34 +3033,18 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
}
}
- return ret;
+ return 0;
}
static void mmc_blk_remove_req(struct mmc_blk_data *md)
{
- struct mmc_card *card;
-
- if (md) {
- /*
- * Flush remaining requests and free queues. It
- * is freeing the queue that stops new requests
- * from being accepted.
- */
- card = md->queue.card;
- queue_flag_set(QUEUE_FLAG_BYPASS, md->queue.queue);
- blk_set_queue_dying(md->queue.queue);
- mmc_cleanup_queue(&md->queue);
- if (md->disk->flags & GENHD_FL_UP) {
- device_remove_file(disk_to_dev(md->disk), &md->force_ro);
- if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
- card->ext_csd.boot_ro_lockable)
- device_remove_file(disk_to_dev(md->disk),
- &md->power_ro_lock);
-
- del_gendisk(md->disk);
- }
- mmc_blk_put(md);
- }
+ /*
+ * Flush remaining requests and free queues. It is freeing the queue
+ * that stops new requests from being accepted.
+ */
+ del_gendisk(md->disk);
+ mmc_cleanup_queue(&md->queue);
+ mmc_blk_put(md);
}
static void mmc_blk_remove_parts(struct mmc_card *card,
@@ -2191,7 +3052,15 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
{
struct list_head *pos, *q;
struct mmc_blk_data *part_md;
+ struct mmc_rpmb_data *rpmb;
+ /* Remove RPMB partitions */
+ list_for_each_safe(pos, q, &md->rpmbs) {
+ rpmb = list_entry(pos, struct mmc_rpmb_data, node);
+ list_del(pos);
+ mmc_blk_remove_rpmb_part(rpmb);
+ }
+ /* Remove block partitions */
list_for_each_safe(pos, q, &md->part) {
part_md = list_entry(pos, struct mmc_blk_data, part);
list_del(pos);
@@ -2199,55 +3068,200 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
}
}
-static int mmc_add_disk(struct mmc_blk_data *md)
+#ifdef CONFIG_DEBUG_FS
+
+static int mmc_dbg_card_status_get(void *data, u64 *val)
{
+ struct mmc_card *card = data;
+ struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
+ struct mmc_queue *mq = &md->queue;
+ struct request *req;
int ret;
- struct mmc_card *card = md->queue.card;
- device_add_disk(md->parent, md->disk);
- md->force_ro.show = force_ro_show;
- md->force_ro.store = force_ro_store;
- sysfs_attr_init(&md->force_ro.attr);
- md->force_ro.attr.name = "force_ro";
- md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
- ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
- if (ret)
- goto force_ro_fail;
+ /* Ask the block layer about the card status */
+ req = blk_mq_alloc_request(mq->queue, REQ_OP_DRV_IN, 0);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS;
+ req_to_mmc_queue_req(req)->drv_op_result = -EIO;
+ blk_execute_rq(req, false);
+ ret = req_to_mmc_queue_req(req)->drv_op_result;
+ if (ret >= 0) {
+ *val = ret;
+ ret = 0;
+ }
+ blk_mq_free_request(req);
- if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
- card->ext_csd.boot_ro_lockable) {
- umode_t mode;
+ return ret;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
+ NULL, "%08llx\n");
- if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
- mode = S_IRUGO;
- else
- mode = S_IRUGO | S_IWUSR;
-
- md->power_ro_lock.show = power_ro_lock_show;
- md->power_ro_lock.store = power_ro_lock_store;
- sysfs_attr_init(&md->power_ro_lock.attr);
- md->power_ro_lock.attr.mode = mode;
- md->power_ro_lock.attr.name =
- "ro_lock_until_next_power_on";
- ret = device_create_file(disk_to_dev(md->disk),
- &md->power_ro_lock);
- if (ret)
- goto power_ro_lock_fail;
+/* That is two digits * 512 + 1 for newline */
+#define EXT_CSD_STR_LEN 1025
+
+static int mmc_ext_csd_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;
+ ssize_t n = 0;
+ u8 *ext_csd;
+ int err, i;
+
+ buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* Ask the block layer for the EXT CSD */
+ req = blk_mq_alloc_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_EXT_CSD;
+ req_to_mmc_queue_req(req)->drv_op_result = -EIO;
+ req_to_mmc_queue_req(req)->drv_op_data = &ext_csd;
+ blk_execute_rq(req, false);
+ err = req_to_mmc_queue_req(req)->drv_op_result;
+ blk_mq_free_request(req);
+ if (err) {
+ pr_err("FAILED %d\n", err);
+ goto out_free;
}
- return ret;
-power_ro_lock_fail:
- device_remove_file(disk_to_dev(md->disk), &md->force_ro);
-force_ro_fail:
- del_gendisk(md->disk);
+ for (i = 0; i < 512; i++)
+ n += sprintf(buf + n, "%02x", ext_csd[i]);
+ n += sprintf(buf + n, "\n");
- return ret;
+ if (n != EXT_CSD_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_ext_csd_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ char *buf = filp->private_data;
+
+ return simple_read_from_buffer(ubuf, cnt, ppos,
+ buf, EXT_CSD_STR_LEN);
+}
+
+static int mmc_ext_csd_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations mmc_dbg_ext_csd_fops = {
+ .open = mmc_ext_csd_open,
+ .read = mmc_ext_csd_read,
+ .release = mmc_ext_csd_release,
+ .llseek = default_llseek,
+};
+
+static void mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md)
+{
+ struct dentry *root;
+
+ if (!card->debugfs_root)
+ return;
+
+ root = card->debugfs_root;
+
+ if (mmc_card_mmc(card) || mmc_card_sd(card)) {
+ md->status_dentry =
+ debugfs_create_file_unsafe("status", 0400, root,
+ card,
+ &mmc_dbg_card_status_fops);
+ }
+
+ if (mmc_card_mmc(card)) {
+ md->ext_csd_dentry =
+ debugfs_create_file("ext_csd", 0400, root, card,
+ &mmc_dbg_ext_csd_fops);
+ }
+}
+
+static void mmc_blk_remove_debugfs(struct mmc_card *card,
+ struct mmc_blk_data *md)
+{
+ if (!card->debugfs_root)
+ return;
+
+ debugfs_remove(md->status_dentry);
+ md->status_dentry = NULL;
+
+ debugfs_remove(md->ext_csd_dentry);
+ md->ext_csd_dentry = NULL;
+}
+
+#else
+
+static void mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md)
+{
+}
+
+static void mmc_blk_remove_debugfs(struct mmc_card *card,
+ struct mmc_blk_data *md)
+{
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
+static void mmc_blk_rpmb_add(struct mmc_card *card)
+{
+ struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
+ struct mmc_rpmb_data *rpmb;
+ struct rpmb_dev *rdev;
+ unsigned int n;
+ u32 cid[4];
+ struct rpmb_descr descr = {
+ .type = RPMB_TYPE_EMMC,
+ .route_frames = mmc_route_rpmb_frames,
+ .reliable_wr_count = card->ext_csd.enhanced_rpmb_supported ?
+ 2 : 32,
+ .capacity = card->ext_csd.raw_rpmb_size_mult,
+ .dev_id = (void *)cid,
+ .dev_id_len = sizeof(cid),
+ };
+
+ /*
+ * Provice CID as an octet array. The CID needs to be interpreted
+ * when used as input to derive the RPMB key since some fields
+ * will change due to firmware updates.
+ */
+ for (n = 0; n < 4; n++)
+ cid[n] = be32_to_cpu((__force __be32)card->raw_cid[n]);
+
+ list_for_each_entry(rpmb, &md->rpmbs, node) {
+ rdev = rpmb_dev_register(&rpmb->dev, &descr);
+ if (IS_ERR(rdev)) {
+ pr_warn("%s: could not register RPMB device\n",
+ dev_name(&rpmb->dev));
+ continue;
+ }
+ rpmb->rdev = rdev;
+ }
}
static int mmc_blk_probe(struct mmc_card *card)
{
- struct mmc_blk_data *md, *part_md;
- char cap_str[10];
+ struct mmc_blk_data *md;
+ int ret = 0;
/*
* Check that the card supports the command class(es) we need.
@@ -2257,28 +3271,26 @@ static int mmc_blk_probe(struct mmc_card *card)
mmc_fixup_device(card, mmc_blk_fixups);
- md = mmc_blk_alloc(card);
- if (IS_ERR(md))
- return PTR_ERR(md);
-
- string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2,
- cap_str, sizeof(cap_str));
- pr_info("%s: %s %s %s %s\n",
- md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
- cap_str, md->read_only ? "(ro)" : "");
-
- if (mmc_blk_alloc_parts(card, md))
- goto out;
+ card->complete_wq = alloc_workqueue("mmc_complete",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU,
+ 0);
+ if (!card->complete_wq) {
+ pr_err("Failed to create mmc completion workqueue");
+ return -ENOMEM;
+ }
- dev_set_drvdata(&card->dev, md);
+ md = mmc_blk_alloc(card);
+ if (IS_ERR(md)) {
+ ret = PTR_ERR(md);
+ goto out_free;
+ }
- if (mmc_add_disk(md))
+ ret = mmc_blk_alloc_parts(card, md);
+ if (ret)
goto out;
- list_for_each_entry(part_md, &md->part, part) {
- if (mmc_add_disk(part_md))
- goto out;
- }
+ /* Add two debugfs entries */
+ mmc_blk_add_debugfs(card, md);
pm_runtime_set_autosuspend_delay(&card->dev, 3000);
pm_runtime_use_autosuspend(&card->dev);
@@ -2287,33 +3299,40 @@ static int mmc_blk_probe(struct mmc_card *card)
* Don't enable runtime PM for SD-combo cards here. Leave that
* decision to be taken during the SDIO init sequence instead.
*/
- if (card->type != MMC_TYPE_SD_COMBO) {
+ if (!mmc_card_sd_combo(card)) {
pm_runtime_set_active(&card->dev);
pm_runtime_enable(&card->dev);
}
+ mmc_blk_rpmb_add(card);
+
return 0;
- out:
+out:
mmc_blk_remove_parts(card, md);
mmc_blk_remove_req(md);
- return 0;
+out_free:
+ destroy_workqueue(card->complete_wq);
+ return ret;
}
static void mmc_blk_remove(struct mmc_card *card)
{
struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
+ mmc_blk_remove_debugfs(card, md);
mmc_blk_remove_parts(card, md);
pm_runtime_get_sync(&card->dev);
- mmc_claim_host(card->host);
- mmc_blk_part_switch(card, md);
- mmc_release_host(card->host);
- if (card->type != MMC_TYPE_SD_COMBO)
+ if (md->part_curr != md->part_type) {
+ mmc_claim_host(card->host);
+ mmc_blk_part_switch(card, md->part_type);
+ mmc_release_host(card->host);
+ }
+ if (!mmc_card_sd_combo(card))
pm_runtime_disable(&card->dev);
pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);
- dev_set_drvdata(&card->dev, NULL);
+ destroy_workqueue(card->complete_wq);
}
static int _mmc_blk_suspend(struct mmc_card *card)
@@ -2379,6 +3398,17 @@ static int __init mmc_blk_init(void)
{
int res;
+ res = bus_register(&mmc_rpmb_bus_type);
+ if (res < 0) {
+ pr_err("mmcblk: could not register RPMB bus type\n");
+ return res;
+ }
+ res = alloc_chrdev_region(&mmc_rpmb_devt, 0, MAX_DEVICES, "rpmb");
+ if (res < 0) {
+ pr_err("mmcblk: failed to allocate rpmb chrdev region\n");
+ goto out_bus_unreg;
+ }
+
if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
pr_info("mmcblk: using %d minors per device\n", perdev_minors);
@@ -2386,16 +3416,20 @@ static int __init mmc_blk_init(void)
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
if (res)
- goto out;
+ goto out_chrdev_unreg;
res = mmc_register_driver(&mmc_driver);
if (res)
- goto out2;
+ goto out_blkdev_unreg;
return 0;
- out2:
+
+out_blkdev_unreg:
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
- out:
+out_chrdev_unreg:
+ unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES);
+out_bus_unreg:
+ bus_unregister(&mmc_rpmb_bus_type);
return res;
}
@@ -2403,6 +3437,8 @@ static void __exit mmc_blk_exit(void)
{
mmc_unregister_driver(&mmc_driver);
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
+ unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES);
+ bus_unregister(&mmc_rpmb_bus_type);
}
module_init(mmc_blk_init);
@@ -2410,4 +3446,3 @@ module_exit(mmc_blk_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
-
diff --git a/drivers/mmc/core/block.h b/drivers/mmc/core/block.h
index 860ca7c8df86..31153f656f41 100644
--- a/drivers/mmc/core/block.h
+++ b/drivers/mmc/core/block.h
@@ -1,9 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _MMC_CORE_BLOCK_H
#define _MMC_CORE_BLOCK_H
struct mmc_queue;
struct request;
-void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req);
+void mmc_blk_cqe_recovery(struct mmc_queue *mq);
+
+enum mmc_issued;
+
+enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req);
+void mmc_blk_mq_complete(struct request *req);
+void mmc_blk_mq_recovery(struct mmc_queue *mq);
+
+struct work_struct;
+
+void mmc_blk_mq_complete_work(struct work_struct *work);
#endif
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 301246513a37..ec4f3462bf80 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/bus.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright (C) 2007 Pierre Ossman
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* MMC card bus driver model
*/
@@ -18,9 +15,11 @@
#include <linux/stat.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
+#include <linux/sysfs.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
#include "core.h"
#include "card.h"
@@ -37,13 +36,13 @@ static ssize_t type_show(struct device *dev,
switch (card->type) {
case MMC_TYPE_MMC:
- return sprintf(buf, "MMC\n");
+ return sysfs_emit(buf, "MMC\n");
case MMC_TYPE_SD:
- return sprintf(buf, "SD\n");
+ return sysfs_emit(buf, "SD\n");
case MMC_TYPE_SDIO:
- return sprintf(buf, "SDIO\n");
+ return sysfs_emit(buf, "SDIO\n");
case MMC_TYPE_SD_COMBO:
- return sprintf(buf, "SDcombo\n");
+ return sysfs_emit(buf, "SDcombo\n");
default:
return -EFAULT;
}
@@ -56,21 +55,12 @@ static struct attribute *mmc_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(mmc_dev);
-/*
- * This currently matches any MMC driver to any MMC card - drivers
- * themselves make the decision whether to drive this card in their
- * probe method.
- */
-static int mmc_bus_match(struct device *dev, struct device_driver *drv)
-{
- return 1;
-}
-
static int
-mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+mmc_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct mmc_card *card = mmc_dev_to_card(dev);
+ const struct mmc_card *card = mmc_dev_to_card(dev);
const char *type;
+ unsigned int i;
int retval = 0;
switch (card->type) {
@@ -96,6 +86,31 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
return retval;
}
+ if (mmc_card_sdio(card) || mmc_card_sd_combo(card)) {
+ retval = add_uevent_var(env, "SDIO_ID=%04X:%04X",
+ card->cis.vendor, card->cis.device);
+ if (retval)
+ return retval;
+
+ retval = add_uevent_var(env, "SDIO_REVISION=%u.%u",
+ card->major_rev, card->minor_rev);
+ if (retval)
+ return retval;
+
+ for (i = 0; i < card->num_info; i++) {
+ retval = add_uevent_var(env, "SDIO_INFO%u=%s", i+1, card->info[i]);
+ if (retval)
+ return retval;
+ }
+ }
+
+ /*
+ * SDIO (non-combo) cards are not handled by mmc_block driver and do not
+ * have accessible CID register which used by mmc_card_name() function.
+ */
+ if (mmc_card_sdio(card))
+ return 0;
+
retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
if (retval)
return retval;
@@ -117,14 +132,12 @@ static int mmc_bus_probe(struct device *dev)
return drv->probe(card);
}
-static int mmc_bus_remove(struct device *dev)
+static void mmc_bus_remove(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
drv->remove(card);
-
- return 0;
}
static void mmc_bus_shutdown(struct device *dev)
@@ -137,6 +150,8 @@ static void mmc_bus_shutdown(struct device *dev)
if (dev->driver && drv->shutdown)
drv->shutdown(card);
+ __mmc_stop_host(host);
+
if (host->bus_ops->shutdown) {
ret = host->bus_ops->shutdown(host);
if (ret)
@@ -157,6 +172,9 @@ static int mmc_bus_suspend(struct device *dev)
return ret;
ret = host->bus_ops->suspend(host);
+ if (ret)
+ pm_generic_resume(dev);
+
return ret;
}
@@ -199,10 +217,9 @@ static const struct dev_pm_ops mmc_bus_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume)
};
-static struct bus_type mmc_bus_type = {
+static const struct bus_type mmc_bus_type = {
.name = "mmc",
.dev_groups = mmc_dev_groups,
- .match = mmc_bus_match,
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
@@ -258,7 +275,7 @@ static void mmc_release_card(struct device *dev)
/*
* Allocate and initialise a new MMC card structure.
*/
-struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
+struct mmc_card *mmc_alloc_card(struct mmc_host *host, const struct device_type *type)
{
struct mmc_card *card;
@@ -285,6 +302,7 @@ int mmc_add_card(struct mmc_card *card)
{
int ret;
const char *type;
+ const char *speed_mode = "";
const char *uhs_bus_speed_mode = "";
static const char *const uhs_speeds[] = {
[UHS_SDR12_BUS_SPEED] = "SDR12 ",
@@ -296,6 +314,9 @@ int mmc_add_card(struct mmc_card *card)
dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);
+ dev_set_removable(&card->dev,
+ mmc_card_is_removable(card->host) ?
+ DEVICE_REMOVABLE : DEVICE_FIXED);
switch (card->type) {
case MMC_TYPE_MMC:
@@ -304,7 +325,9 @@ int mmc_add_card(struct mmc_card *card)
case MMC_TYPE_SD:
type = "SD";
if (mmc_card_blockaddr(card)) {
- if (mmc_card_ext_capacity(card))
+ if (mmc_card_ult_capacity(card))
+ type = "SDUC";
+ else if (mmc_card_ext_capacity(card))
type = "SDXC";
else
type = "SDHC";
@@ -323,33 +346,34 @@ int mmc_add_card(struct mmc_card *card)
break;
}
+ if (mmc_card_hs(card))
+ speed_mode = "high speed ";
+ else if (mmc_card_uhs(card))
+ speed_mode = "UHS-I speed ";
+ else if (mmc_card_uhs2(card->host))
+ speed_mode = "UHS-II speed ";
+ else if (mmc_card_ddr52(card))
+ speed_mode = "high speed DDR ";
+ else if (mmc_card_hs200(card))
+ speed_mode = "HS200 ";
+ else if (mmc_card_hs400es(card))
+ speed_mode = "HS400 Enhanced strobe ";
+ else if (mmc_card_hs400(card))
+ speed_mode = "HS400 ";
+
if (mmc_card_uhs(card) &&
(card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
- if (mmc_host_is_spi(card->host)) {
- pr_info("%s: new %s%s%s card on SPI\n",
- mmc_hostname(card->host),
- mmc_card_hs(card) ? "high speed " : "",
- mmc_card_ddr52(card) ? "DDR " : "",
- type);
- } else {
- pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
- mmc_hostname(card->host),
- mmc_card_uhs(card) ? "ultra high speed " :
- (mmc_card_hs(card) ? "high speed " : ""),
- mmc_card_hs400(card) ? "HS400 " :
- (mmc_card_hs200(card) ? "HS200 " : ""),
- mmc_card_hs400es(card) ? "Enhanced strobe " : "",
- mmc_card_ddr52(card) ? "DDR " : "",
+ if (mmc_host_is_spi(card->host))
+ pr_info("%s: new %s%s card on SPI\n",
+ mmc_hostname(card->host), speed_mode, type);
+ else
+ pr_info("%s: new %s%s%s card at address %04x\n",
+ mmc_hostname(card->host), speed_mode,
uhs_bus_speed_mode, type, card->rca);
- }
-#ifdef CONFIG_DEBUG_FS
mmc_add_card_debugfs(card);
-#endif
- mmc_init_context_info(card->host);
-
card->dev.of_node = mmc_of_find_child_device(card->host, 0);
device_enable_async_suspend(&card->dev);
@@ -360,6 +384,14 @@ int mmc_add_card(struct mmc_card *card)
mmc_card_set_present(card);
+ /*
+ * Register for undervoltage notification if the card supports
+ * power-off notification, enabling emergency shutdowns.
+ */
+ if (mmc_card_mmc(card) &&
+ card->ext_csd.power_off_notification == EXT_CSD_POWER_ON)
+ mmc_regulator_register_undervoltage_notifier(card->host);
+
return 0;
}
@@ -369,9 +401,12 @@ int mmc_add_card(struct mmc_card *card)
*/
void mmc_remove_card(struct mmc_card *card)
{
-#ifdef CONFIG_DEBUG_FS
+ struct mmc_host *host = card->host;
+
+ if (mmc_card_present(card))
+ mmc_regulator_unregister_undervoltage_notifier(host);
+
mmc_remove_card_debugfs(card);
-#endif
if (mmc_card_present(card)) {
if (mmc_host_is_spi(card->host)) {
@@ -385,6 +420,10 @@ void mmc_remove_card(struct mmc_card *card)
of_node_put(card->dev.of_node);
}
+ if (host->cqe_enabled) {
+ host->cqe_ops->cqe_disable(host);
+ host->cqe_enabled = false;
+ }
+
put_device(&card->dev);
}
-
diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h
index 72b0ef03f10a..8b69624fa46e 100644
--- a/drivers/mmc/core/bus.h
+++ b/drivers/mmc/core/bus.h
@@ -1,17 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/mmc/core/bus.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _MMC_CORE_BUS_H
#define _MMC_CORE_BUS_H
#include <linux/device.h>
+#include <linux/sysfs.h>
struct mmc_host;
struct mmc_card;
@@ -20,12 +18,12 @@ struct mmc_card;
static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct mmc_card *card = mmc_dev_to_card(dev); \
- return sprintf(buf, fmt, args); \
+ return sysfs_emit(buf, fmt, args); \
} \
-static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
+static DEVICE_ATTR(name, 0444, mmc_##name##_show, NULL)
struct mmc_card *mmc_alloc_card(struct mmc_host *host,
- struct device_type *type);
+ const struct device_type *type);
int mmc_add_card(struct mmc_card *card);
void mmc_remove_card(struct mmc_card *card);
diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
index f06cd91964ce..1200951bab08 100644
--- a/drivers/mmc/core/card.h
+++ b/drivers/mmc/core/card.h
@@ -1,11 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Private header for the mmc subsystem
*
* Copyright (C) 2016 Linaro Ltd
*
* Author: Ulf Hansson <ulf.hansson@linaro.org>
- *
- * License terms: GNU General Public License (GPL) version 2
*/
#ifndef _MMC_CORE_CARD_H
@@ -23,24 +22,23 @@
#define MMC_STATE_BLOCKADDR (1<<2) /* card uses block-addressing */
#define MMC_CARD_SDXC (1<<3) /* card is SDXC */
#define MMC_CARD_REMOVED (1<<4) /* card has been removed */
-#define MMC_STATE_DOING_BKOPS (1<<5) /* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED (1<<6) /* card is suspended */
+#define MMC_STATE_SUSPENDED (1<<5) /* card is suspended */
+#define MMC_CARD_SDUC (1<<6) /* card is SDUC */
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
-#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED)
+#define mmc_card_ult_capacity(c) ((c)->state & MMC_CARD_SDUC)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_ult_capacity(c) ((c)->state |= MMC_CARD_SDUC)
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
-#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS)
-#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS)
#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
@@ -58,38 +56,57 @@ struct mmc_fixup {
unsigned int manfid;
unsigned short oemid;
+ /* Manufacturing date */
+ unsigned short year;
+ unsigned char month;
+
/* SDIO-specific fields. You can use SDIO_ANY_ID here of course */
u16 cis_vendor, cis_device;
/* for MMC cards */
unsigned int ext_csd_rev;
+ /* Match against functions declared in device tree */
+ const char *of_compatible;
+
void (*vendor_fixup)(struct mmc_card *card, int data);
int data;
};
#define CID_MANFID_ANY (-1u)
#define CID_OEMID_ANY ((unsigned short) -1)
+#define CID_YEAR_ANY ((unsigned short) -1)
+#define CID_MONTH_ANY ((unsigned char) -1)
#define CID_NAME_ANY (NULL)
#define EXT_CSD_REV_ANY (-1u)
#define CID_MANFID_SANDISK 0x2
+#define CID_MANFID_SANDISK_SD 0x3
+#define CID_MANFID_ATP 0x9
#define CID_MANFID_TOSHIBA 0x11
+#define CID_MANFID_GIGASTONE 0x12
#define CID_MANFID_MICRON 0x13
#define CID_MANFID_SAMSUNG 0x15
+#define CID_MANFID_APACER 0x27
+#define CID_MANFID_SWISSBIT 0x5D
#define CID_MANFID_KINGSTON 0x70
#define CID_MANFID_HYNIX 0x90
+#define CID_MANFID_KINGSTON_SD 0x9F
+#define CID_MANFID_NUMONYX 0xFE
#define END_FIXUP { NULL }
-#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \
- _cis_vendor, _cis_device, \
- _fixup, _data, _ext_csd_rev) \
+#define _FIXUP_EXT(_name, _manfid, _oemid, _year, _month, \
+ _rev_start, _rev_end, \
+ _cis_vendor, _cis_device, \
+ _fixup, _data, _ext_csd_rev) \
{ \
.name = (_name), \
.manfid = (_manfid), \
.oemid = (_oemid), \
+ .year = (_year), \
+ .month = (_month), \
.rev_start = (_rev_start), \
.rev_end = (_rev_end), \
.cis_vendor = (_cis_vendor), \
@@ -101,8 +118,8 @@ struct mmc_fixup {
#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end, \
_fixup, _data, _ext_csd_rev) \
- _FIXUP_EXT(_name, _manfid, \
- _oemid, _rev_start, _rev_end, \
+ _FIXUP_EXT(_name, _manfid, _oemid, CID_YEAR_ANY, CID_MONTH_ANY, \
+ _rev_start, _rev_end, \
SDIO_ANY_ID, SDIO_ANY_ID, \
_fixup, _data, _ext_csd_rev) \
@@ -116,11 +133,27 @@ struct mmc_fixup {
_ext_csd_rev)
#define SDIO_FIXUP(_vendor, _device, _fixup, _data) \
- _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY, \
- CID_OEMID_ANY, 0, -1ull, \
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY, CID_OEMID_ANY, \
+ CID_YEAR_ANY, CID_MONTH_ANY, \
+ 0, -1ull, \
_vendor, _device, \
_fixup, _data, EXT_CSD_REV_ANY) \
+#define SDIO_FIXUP_COMPATIBLE(_compatible, _fixup, _data) \
+ { \
+ .name = CID_NAME_ANY, \
+ .manfid = CID_MANFID_ANY, \
+ .oemid = CID_OEMID_ANY, \
+ .rev_start = 0, \
+ .rev_end = -1ull, \
+ .cis_vendor = SDIO_ANY_ID, \
+ .cis_device = SDIO_ANY_ID, \
+ .vendor_fixup = (_fixup), \
+ .data = (_data), \
+ .ext_csd_rev = EXT_CSD_REV_ANY, \
+ .of_compatible = _compatible, \
+ }
+
#define cid_rev(hwrev, fwrev, year, month) \
(((u64) hwrev) << 40 | \
((u64) fwrev) << 32 | \
@@ -146,6 +179,30 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
card->quirks &= ~data;
}
+static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card,
+ int data)
+{
+ card->quirk_max_rate = data;
+}
+
+static inline void __maybe_unused wl1251_quirk(struct mmc_card *card,
+ int data)
+{
+ /*
+ * We have TI wl1251 attached to this mmc. Pass this
+ * information to the SDIO core because it can't be
+ * probed by normal methods.
+ */
+
+ dev_info(card->host->parent, "found wl1251\n");
+ card->quirks |= MMC_QUIRK_NONSTD_SDIO;
+ card->cccr.wide_bus = 1;
+ card->cis.vendor = 0x104c;
+ card->cis.device = 0x9066;
+ card->cis.blksize = 512;
+ card->cis.max_dtr = 24000000;
+}
+
/*
* Quirk add/remove for MMC products.
*/
@@ -188,14 +245,19 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
}
+static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
+}
+
static inline int mmc_card_disable_cd(const struct mmc_card *c)
{
return c->quirks & MMC_QUIRK_DISABLE_CD;
}
-static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
+static inline int mmc_card_blk_no_cmd23(const struct mmc_card *c)
{
- return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
+ return c->quirks & MMC_QUIRK_BLK_NO_CMD23;
}
static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c)
@@ -218,4 +280,29 @@ static inline int mmc_card_broken_hpi(const struct mmc_card *c)
return c->quirks & MMC_QUIRK_BROKEN_HPI;
}
+static inline int mmc_card_broken_sd_discard(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_BROKEN_SD_DISCARD;
+}
+
+static inline int mmc_card_broken_sd_cache(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
+}
+
+static inline int mmc_card_broken_cache_flush(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
+}
+
+static inline int mmc_card_broken_sd_poweroff_notify(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY;
+}
+
+static inline int mmc_card_no_uhs_ddr50_tuning(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_NO_UHS_DDR50_TUNING;
+}
+
#endif
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 26431267a3e2..860378bea557 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/core.c
*
@@ -5,10 +6,6 @@
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
* Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
* MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
@@ -21,9 +18,7 @@
#include <linux/leds.h>
#include <linux/scatterlist.h>
#include <linux/log2.h>
-#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
-#include <linux/pm_wakeup.h>
#include <linux/suspend.h>
#include <linux/fault-inject.h>
#include <linux/random.h>
@@ -41,6 +36,7 @@
#include "core.h"
#include "card.h"
+#include "crypto.h"
#include "bus.h"
#include "host.h"
#include "sdio_bus.h"
@@ -50,18 +46,16 @@
#include "sd_ops.h"
#include "sdio_ops.h"
-/* If the device is not responding */
-#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
-
/* The max erase timeout, used when host->max_busy_timeout isn't specified */
#define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */
+#define SD_DISCARD_TIMEOUT_MS (250)
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
/*
* Enabling software CRCs on the data blocks can be a significant (30%)
* performance cost, and for other reasons may not always be desired.
- * So we allow it it to be disabled.
+ * So we allow it to be disabled.
*/
bool use_spi_crc = 1;
module_param(use_spi_crc, bool, 0);
@@ -98,12 +92,12 @@ static void mmc_should_fail_request(struct mmc_host *host,
if (!data)
return;
- if (cmd->error || data->error ||
+ if ((cmd && cmd->error) || data->error ||
!should_fail(&host->fail_mmc_request, data->blksz * data->blocks))
return;
- data->error = data_errors[prandom_u32() % ARRAY_SIZE(data_errors)];
- data->bytes_xfered = (prandom_u32() % (data->bytes_xfered >> 9)) << 9;
+ data->error = data_errors[get_random_u32_below(ARRAY_SIZE(data_errors))];
+ data->bytes_xfered = get_random_u32_below(data->bytes_xfered >> 9) << 9;
}
#else /* CONFIG_FAIL_MMC_REQUEST */
@@ -147,8 +141,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
int err = cmd->error;
/* Flag re-tuning needed on CRC errors */
- if ((cmd->opcode != MMC_SEND_TUNING_BLOCK &&
- cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
+ if (!mmc_op_tuning(cmd->opcode) &&
+ !host->retune_crc_disable &&
(err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) ||
(mrq->data && mrq->data->error == -EILSEQ) ||
(mrq->stop && mrq->stop->error == -EILSEQ)))
@@ -260,10 +254,14 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
trace_mmc_request_start(host, mrq);
+ if (host->cqe_on)
+ host->cqe_ops->cqe_off(host);
+
host->ops->request(host, mrq);
}
-static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
+static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq,
+ bool cqe)
{
if (mrq->sbc) {
pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
@@ -272,9 +270,12 @@ static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
}
if (mrq->cmd) {
- pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
- mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg,
- mrq->cmd->flags);
+ pr_debug("%s: starting %sCMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), cqe ? "CQE direct " : "",
+ mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
+ } else if (cqe) {
+ pr_debug("%s: starting CQE transfer for tag %d blkaddr %u\n",
+ mmc_hostname(host), mrq->tag, mrq->data->blk_addr);
}
if (mrq->data) {
@@ -295,10 +296,8 @@ static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
{
-#ifdef CONFIG_MMC_DEBUG
- unsigned int i, sz;
+ unsigned int i, sz = 0;
struct scatterlist *sg;
-#endif
if (mrq->cmd) {
mrq->cmd->error = 0;
@@ -314,13 +313,12 @@ static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
mrq->data->blocks > host->max_blk_count ||
mrq->data->blocks * mrq->data->blksz > host->max_req_size)
return -EINVAL;
-#ifdef CONFIG_MMC_DEBUG
- sz = 0;
+
for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
sz += sg->length;
if (sz != mrq->data->blocks * mrq->data->blksz)
return -EINVAL;
-#endif
+
mrq->data->error = 0;
mrq->data->mrq = mrq;
if (mrq->stop) {
@@ -333,16 +331,21 @@ static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
return 0;
}
-static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
int err;
+ if (mrq->cmd->has_ext_addr)
+ mmc_send_ext_addr(host, mrq->cmd->ext_addr);
+
+ init_completion(&mrq->cmd_completion);
+
mmc_retune_hold(host);
if (mmc_card_removed(host->card))
return -ENOMEDIUM;
- mmc_mrq_pr_debug(host, mrq);
+ mmc_mrq_pr_debug(host, mrq, false);
WARN_ON(!host->claimed);
@@ -350,25 +353,15 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
if (err)
return err;
+ if (host->uhs2_sd_tran)
+ mmc_uhs2_prepare_cmd(host, mrq);
+
led_trigger_event(host->led, LED_FULL);
__mmc_start_request(host, mrq);
return 0;
}
-
-/*
- * mmc_wait_data_done() - done callback for data request
- * @mrq: done data request
- *
- * Wakes up mmc context, passed as a callback to host controller driver
- */
-static void mmc_wait_data_done(struct mmc_request *mrq)
-{
- struct mmc_context_info *context_info = &mrq->host->context_info;
-
- context_info->is_done_rcv = true;
- wake_up_interruptible(&context_info->wait);
-}
+EXPORT_SYMBOL(mmc_start_request);
static void mmc_wait_done(struct mmc_request *mrq)
{
@@ -387,37 +380,6 @@ static inline void mmc_wait_ongoing_tfr_cmd(struct mmc_host *host)
wait_for_completion(&ongoing_mrq->cmd_completion);
}
-/*
- *__mmc_start_data_req() - starts data request
- * @host: MMC host to start the request
- * @mrq: data request to start
- *
- * Sets the done callback to be called when request is completed by the card.
- * Starts data mmc request execution
- * If an ongoing transfer is already in progress, wait for the command line
- * to become available before sending another command.
- */
-static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
-{
- int err;
-
- mmc_wait_ongoing_tfr_cmd(host);
-
- mrq->done = mmc_wait_data_done;
- mrq->host = host;
-
- init_completion(&mrq->cmd_completion);
-
- err = mmc_start_request(host, mrq);
- if (err) {
- mrq->cmd->error = err;
- mmc_complete_cmd(mrq);
- mmc_wait_data_done(mrq);
- }
-
- return err;
-}
-
static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
int err;
@@ -427,8 +389,6 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
init_completion(&mrq->completion);
mrq->done = mmc_wait_done;
- init_completion(&mrq->cmd_completion);
-
err = mmc_start_request(host, mrq);
if (err) {
mrq->cmd->error = err;
@@ -448,23 +408,6 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
cmd = mrq->cmd;
- /*
- * If host has timed out waiting for the sanitize
- * to complete, card might be still in programming state
- * so let's try to bring the card out of programming
- * state.
- */
- if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {
- if (!mmc_interrupt_hpi(host->card)) {
- pr_warn("%s: %s: Interrupted sanitize\n",
- mmc_hostname(host), __func__);
- cmd->error = 0;
- break;
- } else {
- pr_err("%s: %s: Failed to interrupt sanitize\n",
- mmc_hostname(host), __func__);
- }
- }
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card))
break;
@@ -482,176 +425,178 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
}
EXPORT_SYMBOL(mmc_wait_for_req_done);
-/**
- * mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
- * @host: MMC host
- * @mrq: MMC request
+/*
+ * mmc_cqe_start_req - Start a CQE request.
+ * @host: MMC host to start the request
+ * @mrq: request to start
*
- * mmc_is_req_done() is used with requests that have
- * mrq->cap_cmd_during_tfr = true. mmc_is_req_done() must be called after
- * starting a request and before waiting for it to complete. That is,
- * either in between calls to mmc_start_req(), or after mmc_wait_for_req()
- * and before mmc_wait_for_req_done(). If it is called at other times the
- * result is not meaningful.
+ * Start the request, re-tuning if needed and it is possible. Returns an error
+ * code if the request fails to start or -EBUSY if CQE is busy.
*/
-bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq)
+int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
- if (host->areq)
- return host->context_info.is_done_rcv;
- else
- return completion_done(&mrq->completion);
-}
-EXPORT_SYMBOL(mmc_is_req_done);
+ int err;
-/**
- * mmc_pre_req - Prepare for a new request
- * @host: MMC host to prepare command
- * @mrq: MMC request to prepare for
- *
- * mmc_pre_req() is called in prior to mmc_start_req() to let
- * host prepare for the new request. Preparation of a request may be
- * performed while another request is running on the host.
- */
-static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq)
-{
- if (host->ops->pre_req)
- host->ops->pre_req(host, mrq);
-}
+ /*
+ * CQE cannot process re-tuning commands. Caller must hold retuning
+ * while CQE is in use. Re-tuning can happen here only when CQE has no
+ * active requests i.e. this is the first. Note, re-tuning will call
+ * ->cqe_off().
+ */
+ err = mmc_retune(host);
+ if (err)
+ goto out_err;
-/**
- * mmc_post_req - Post process a completed request
- * @host: MMC host to post process command
- * @mrq: MMC request to post process for
- * @err: Error, if non zero, clean up any resources made in pre_req
- *
- * Let the host post process a completed request. Post processing of
- * a request may be performed while another reuqest is running.
- */
-static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
- int err)
-{
- if (host->ops->post_req)
- host->ops->post_req(host, mrq, err);
+ mrq->host = host;
+
+ mmc_mrq_pr_debug(host, mrq, true);
+
+ err = mmc_mrq_prep(host, mrq);
+ if (err)
+ goto out_err;
+
+ if (host->uhs2_sd_tran)
+ mmc_uhs2_prepare_cmd(host, mrq);
+
+ err = host->cqe_ops->cqe_request(host, mrq);
+ if (err)
+ goto out_err;
+
+ trace_mmc_request_start(host, mrq);
+
+ return 0;
+
+out_err:
+ if (mrq->cmd) {
+ pr_debug("%s: failed to start CQE direct CMD%u, error %d\n",
+ mmc_hostname(host), mrq->cmd->opcode, err);
+ } else {
+ pr_debug("%s: failed to start CQE transfer for tag %d, error %d\n",
+ mmc_hostname(host), mrq->tag, err);
+ }
+ return err;
}
+EXPORT_SYMBOL(mmc_cqe_start_req);
/**
- * mmc_finalize_areq() - finalize an asynchronous request
- * @host: MMC host to finalize any ongoing request on
+ * mmc_cqe_request_done - CQE has finished processing an MMC request
+ * @host: MMC host which completed request
+ * @mrq: MMC request which completed
*
- * Returns the status of the ongoing asynchronous request, but
- * MMC_BLK_SUCCESS if no request was going on.
+ * CQE drivers should call this function when they have completed
+ * their processing of a request.
*/
-static enum mmc_blk_status mmc_finalize_areq(struct mmc_host *host)
+void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq)
{
- struct mmc_context_info *context_info = &host->context_info;
- enum mmc_blk_status status;
+ mmc_should_fail_request(host, mrq);
- if (!host->areq)
- return MMC_BLK_SUCCESS;
+ /* Flag re-tuning needed on CRC errors */
+ if ((mrq->cmd && mrq->cmd->error == -EILSEQ) ||
+ (mrq->data && mrq->data->error == -EILSEQ))
+ mmc_retune_needed(host);
- while (1) {
- wait_event_interruptible(context_info->wait,
- (context_info->is_done_rcv ||
- context_info->is_new_req));
-
- if (context_info->is_done_rcv) {
- struct mmc_command *cmd;
-
- context_info->is_done_rcv = false;
- cmd = host->areq->mrq->cmd;
-
- if (!cmd->error || !cmd->retries ||
- mmc_card_removed(host->card)) {
- status = host->areq->err_check(host->card,
- host->areq);
- break; /* return status */
- } else {
- mmc_retune_recheck(host);
- pr_info("%s: req failed (CMD%u): %d, retrying...\n",
- mmc_hostname(host),
- cmd->opcode, cmd->error);
- cmd->retries--;
- cmd->error = 0;
- __mmc_start_request(host, host->areq->mrq);
- continue; /* wait for done/new event again */
- }
- }
+ trace_mmc_request_done(host, mrq);
- return MMC_BLK_NEW_REQUEST;
+ if (mrq->cmd) {
+ pr_debug("%s: CQE req done (direct CMD%u): %d\n",
+ mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->error);
+ } else {
+ pr_debug("%s: CQE transfer done tag %d\n",
+ mmc_hostname(host), mrq->tag);
}
- mmc_retune_release(host);
-
- /*
- * Check BKOPS urgency for each R1 response
- */
- if (host->card && mmc_card_mmc(host->card) &&
- ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
- (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
- (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) {
- mmc_start_bkops(host->card, true);
+ if (mrq->data) {
+ pr_debug("%s: %d bytes transferred: %d\n",
+ mmc_hostname(host),
+ mrq->data->bytes_xfered, mrq->data->error);
}
- return status;
+ mrq->done(mrq);
}
+EXPORT_SYMBOL(mmc_cqe_request_done);
/**
- * mmc_start_areq - start an asynchronous request
- * @host: MMC host to start command
- * @areq: asynchronous request to start
- * @ret_stat: out parameter for status
- *
- * Start a new MMC custom command request for a host.
- * If there is on ongoing async request wait for completion
- * of that request and start the new one and return.
- * Does not wait for the new request to complete.
+ * mmc_cqe_post_req - CQE post process of a completed MMC request
+ * @host: MMC host
+ * @mrq: MMC request to be processed
+ */
+void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ if (host->cqe_ops->cqe_post_req)
+ host->cqe_ops->cqe_post_req(host, mrq);
+}
+EXPORT_SYMBOL(mmc_cqe_post_req);
+
+/* Arbitrary 1 second timeout */
+#define MMC_CQE_RECOVERY_TIMEOUT 1000
+
+/*
+ * mmc_cqe_recovery - Recover from CQE errors.
+ * @host: MMC host to recover
*
- * Returns the completed request, NULL in case of none completed.
- * Wait for the an ongoing request (previoulsy started) to complete and
- * return the completed request. If there is no ongoing request, NULL
- * is returned without waiting. NULL is not an error condition.
+ * Recovery consists of stopping CQE, stopping eMMC, discarding the queue
+ * in eMMC, and discarding the queue in CQE. CQE must call
+ * mmc_cqe_request_done() on all requests. An error is returned if the eMMC
+ * fails to discard its queue.
*/
-struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
- struct mmc_async_req *areq,
- enum mmc_blk_status *ret_stat)
+int mmc_cqe_recovery(struct mmc_host *host)
{
- enum mmc_blk_status status;
- int start_err = 0;
- struct mmc_async_req *previous = host->areq;
+ struct mmc_command cmd;
+ int err;
- /* Prepare a new request */
- if (areq)
- mmc_pre_req(host, areq->mrq);
+ mmc_retune_hold_now(host);
- /* Finalize previous request */
- status = mmc_finalize_areq(host);
- if (ret_stat)
- *ret_stat = status;
+ /*
+ * Recovery is expected seldom, if at all, but it reduces performance,
+ * so make sure it is not completely silent.
+ */
+ pr_warn("%s: running CQE recovery\n", mmc_hostname(host));
- /* The previous request is still going on... */
- if (status == MMC_BLK_NEW_REQUEST)
- return NULL;
+ host->cqe_ops->cqe_recovery_start(host);
- /* Fine so far, start the new request! */
- if (status == MMC_BLK_SUCCESS && areq)
- start_err = __mmc_start_data_req(host, areq->mrq);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = MMC_STOP_TRANSMISSION;
+ cmd.flags = MMC_RSP_R1B_NO_CRC | MMC_CMD_AC; /* Ignore CRC */
+ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
+ mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- /* Postprocess the old request at this point */
- if (host->areq)
- mmc_post_req(host, host->areq->mrq, 0);
+ mmc_poll_for_busy(host->card, MMC_CQE_RECOVERY_TIMEOUT, true, MMC_BUSY_IO);
- /* Cancel a prepared request if it was not started. */
- if ((status != MMC_BLK_SUCCESS || start_err) && areq)
- mmc_post_req(host, areq->mrq, -EINVAL);
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = MMC_CMDQ_TASK_MGMT;
+ cmd.arg = 1; /* Discard entire queue */
+ cmd.flags = MMC_RSP_R1B_NO_CRC | MMC_CMD_AC; /* Ignore CRC */
+ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT;
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (status != MMC_BLK_SUCCESS)
- host->areq = NULL;
- else
- host->areq = areq;
+ host->cqe_ops->cqe_recovery_finish(host);
+
+ if (err)
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+
+ mmc_retune_release(host);
- return previous;
+ return err;
+}
+EXPORT_SYMBOL(mmc_cqe_recovery);
+
+/**
+ * mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
+ * @host: MMC host
+ * @mrq: MMC request
+ *
+ * mmc_is_req_done() is used with requests that have
+ * mrq->cap_cmd_during_tfr = true. mmc_is_req_done() must be called after
+ * starting a request and before waiting for it to complete. That is,
+ * either in between calls to mmc_start_req(), or after mmc_wait_for_req()
+ * and before mmc_wait_for_req_done(). If it is called at other times the
+ * result is not meaningful.
+ */
+bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq)
+{
+ return completion_done(&mrq->completion);
}
-EXPORT_SYMBOL(mmc_start_areq);
+EXPORT_SYMBOL(mmc_is_req_done);
/**
* mmc_wait_for_req - start a request and wait for completion
@@ -736,8 +681,8 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
if (data->flags & MMC_DATA_WRITE)
mult <<= card->csd.r2w_factor;
- data->timeout_ns = card->csd.tacc_ns * mult;
- data->timeout_clks = card->csd.tacc_clks * mult;
+ data->timeout_ns = card->csd.taac_ns * mult;
+ data->timeout_clks = card->csd.taac_clks * mult;
/*
* SD cards also have an upper limit on the timeout.
@@ -766,7 +711,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
/*
* SDHC cards always use these fixed values.
*/
- if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
+ if (timeout_us > limit_us) {
data->timeout_ns = limit_us * 1000;
data->timeout_clks = 0;
}
@@ -805,36 +750,36 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
}
EXPORT_SYMBOL(mmc_set_data_timeout);
-/**
- * mmc_align_data_size - pads a transfer size to a more optimal value
- * @card: the MMC card associated with the data transfer
- * @sz: original transfer size
- *
- * Pads the original data size with a number of extra bytes in
- * order to avoid controller bugs and/or performance hits
- * (e.g. some controllers revert to PIO for certain sizes).
- *
- * Returns the improved size, which might be unmodified.
- *
- * Note that this function is only relevant when issuing a
- * single scatter gather entry.
+/*
+ * Allow claiming an already claimed host if the context is the same or there is
+ * no context but the task is the same.
*/
-unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
+static inline bool mmc_ctx_matches(struct mmc_host *host, struct mmc_ctx *ctx,
+ struct task_struct *task)
{
- /*
- * FIXME: We don't have a system for the controller to tell
- * the core about its problems yet, so for now we just 32-bit
- * align the size.
- */
- sz = ((sz + 3) / 4) * 4;
+ return host->claimer == ctx ||
+ (!ctx && task && host->claimer->task == task);
+}
- return sz;
+static inline void mmc_ctx_set_claimer(struct mmc_host *host,
+ struct mmc_ctx *ctx,
+ struct task_struct *task)
+{
+ if (!host->claimer) {
+ if (ctx)
+ host->claimer = ctx;
+ else
+ host->claimer = &host->default_ctx;
+ }
+ if (task)
+ host->claimer->task = task;
}
-EXPORT_SYMBOL(mmc_align_data_size);
/**
* __mmc_claim_host - exclusively claim a host
* @host: mmc host to claim
+ * @ctx: context that claims the host or NULL in which case the default
+ * context will be used
* @abort: whether or not the operation should be aborted
*
* Claim a host for a set of operations. If @abort is non null and
@@ -842,8 +787,10 @@ EXPORT_SYMBOL(mmc_align_data_size);
* that non-zero value without acquiring the lock. Returns zero
* with the lock held otherwise.
*/
-int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
+int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
+ atomic_t *abort)
{
+ struct task_struct *task = ctx ? NULL : current;
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
int stop;
@@ -856,7 +803,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
stop = abort ? atomic_read(abort) : 0;
- if (stop || !host->claimed || host->claimer == current)
+ if (stop || !host->claimed || mmc_ctx_matches(host, ctx, task))
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
@@ -865,7 +812,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
set_current_state(TASK_RUNNING);
if (!stop) {
host->claimed = 1;
- host->claimer = current;
+ mmc_ctx_set_claimer(host, ctx, task);
host->claim_cnt += 1;
if (host->claim_cnt == 1)
pm = true;
@@ -900,11 +847,15 @@ void mmc_release_host(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
} else {
host->claimed = 0;
+ host->claimer->task = NULL;
host->claimer = NULL;
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq);
pm_runtime_mark_last_busy(mmc_dev(host));
- pm_runtime_put_autosuspend(mmc_dev(host));
+ if (host->caps & MMC_CAP_SYNC_RUNTIME_PM)
+ pm_runtime_put_sync_suspend(mmc_dev(host));
+ else
+ pm_runtime_put_autosuspend(mmc_dev(host));
}
}
EXPORT_SYMBOL(mmc_release_host);
@@ -913,10 +864,10 @@ EXPORT_SYMBOL(mmc_release_host);
* This is a helper function, which fetches a runtime pm reference for the
* card device and also claims the host.
*/
-void mmc_get_card(struct mmc_card *card)
+void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx)
{
pm_runtime_get_sync(&card->dev);
- mmc_claim_host(card->host);
+ __mmc_claim_host(card->host, ctx, NULL);
}
EXPORT_SYMBOL(mmc_get_card);
@@ -924,10 +875,13 @@ EXPORT_SYMBOL(mmc_get_card);
* This is a helper function, which releases the host and drops the runtime
* pm reference for the card device.
*/
-void mmc_put_card(struct mmc_card *card)
+void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx)
{
- mmc_release_host(card->host);
- pm_runtime_mark_last_busy(&card->dev);
+ struct mmc_host *host = card->host;
+
+ WARN_ON(ctx && host->claimer != ctx);
+
+ mmc_release_host(host);
pm_runtime_put_autosuspend(&card->dev);
}
EXPORT_SYMBOL(mmc_put_card);
@@ -982,18 +936,27 @@ int mmc_execute_tuning(struct mmc_card *card)
if (!host->ops->execute_tuning)
return 0;
+ if (host->cqe_on)
+ host->cqe_ops->cqe_off(host);
+
if (mmc_card_mmc(card))
opcode = MMC_SEND_TUNING_BLOCK_HS200;
else
opcode = MMC_SEND_TUNING_BLOCK;
err = host->ops->execute_tuning(host, opcode);
+ if (!err) {
+ mmc_retune_clear(host);
+ mmc_retune_enable(host);
+ return 0;
+ }
- if (err)
+ /* Only print error when we don't check for card removal */
+ if (!host->detect_change) {
pr_err("%s: tuning execution failed: %d\n",
mmc_hostname(host), err);
- else
- mmc_retune_enable(host);
+ mmc_debugfs_err_stats_inc(host, MMC_ERR_TUNING);
+ }
return err;
}
@@ -1021,6 +984,9 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
*/
void mmc_set_initial_state(struct mmc_host *host)
{
+ if (host->cqe_on)
+ host->cqe_ops->cqe_off(host);
+
mmc_retune_disable(host);
if (mmc_host_is_spi(host))
@@ -1042,6 +1008,8 @@ void mmc_set_initial_state(struct mmc_host *host)
host->ops->hs400_enhanced_strobe(host, &host->ios);
mmc_set_ios(host);
+
+ mmc_crypto_set_initial_state(host);
}
/**
@@ -1116,55 +1084,6 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max)
return mask;
}
-EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
-
-#ifdef CONFIG_OF
-
-/**
- * mmc_of_parse_voltage - return mask of supported voltages
- * @np: The device node need to be parsed.
- * @mask: mask of voltages available for MMC/SD/SDIO
- *
- * Parse the "voltage-ranges" DT property, returning zero if it is not
- * found, negative errno if the voltage-range specification is invalid,
- * or one if the voltage-range is specified and successfully parsed.
- */
-int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
-{
- const u32 *voltage_ranges;
- int num_ranges, i;
-
- voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
- num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
- if (!voltage_ranges) {
- pr_debug("%s: voltage-ranges unspecified\n", np->full_name);
- return 0;
- }
- if (!num_ranges) {
- pr_err("%s: voltage-ranges empty\n", np->full_name);
- return -EINVAL;
- }
-
- for (i = 0; i < num_ranges; i++) {
- const int j = i * 2;
- u32 ocr_mask;
-
- ocr_mask = mmc_vddrange_to_ocrmask(
- be32_to_cpu(voltage_ranges[j]),
- be32_to_cpu(voltage_ranges[j + 1]));
- if (!ocr_mask) {
- pr_err("%s: voltage-range #%d is invalid\n",
- np->full_name, i);
- return -EINVAL;
- }
- *mask |= ocr_mask;
- }
-
- return 1;
-}
-EXPORT_SYMBOL(mmc_of_parse_voltage);
-
-#endif /* CONFIG_OF */
static int mmc_of_get_func_num(struct device_node *node)
{
@@ -1194,236 +1113,6 @@ struct device_node *mmc_of_find_child_device(struct mmc_host *host,
return NULL;
}
-#ifdef CONFIG_REGULATOR
-
-/**
- * mmc_ocrbitnum_to_vdd - Convert a OCR bit number to its voltage
- * @vdd_bit: OCR bit number
- * @min_uV: minimum voltage value (mV)
- * @max_uV: maximum voltage value (mV)
- *
- * This function returns the voltage range according to the provided OCR
- * bit number. If conversion is not possible a negative errno value returned.
- */
-static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV)
-{
- int tmp;
-
- if (!vdd_bit)
- return -EINVAL;
-
- /*
- * REVISIT mmc_vddrange_to_ocrmask() may have set some
- * bits this regulator doesn't quite support ... don't
- * be too picky, most cards and regulators are OK with
- * a 0.1V range goof (it's a small error percentage).
- */
- tmp = vdd_bit - ilog2(MMC_VDD_165_195);
- if (tmp == 0) {
- *min_uV = 1650 * 1000;
- *max_uV = 1950 * 1000;
- } else {
- *min_uV = 1900 * 1000 + tmp * 100 * 1000;
- *max_uV = *min_uV + 100 * 1000;
- }
-
- return 0;
-}
-
-/**
- * mmc_regulator_get_ocrmask - return mask of supported voltages
- * @supply: regulator to use
- *
- * This returns either a negative errno, or a mask of voltages that
- * can be provided to MMC/SD/SDIO devices using the specified voltage
- * regulator. This would normally be called before registering the
- * MMC host adapter.
- */
-int mmc_regulator_get_ocrmask(struct regulator *supply)
-{
- int result = 0;
- int count;
- int i;
- int vdd_uV;
- int vdd_mV;
-
- count = regulator_count_voltages(supply);
- if (count < 0)
- return count;
-
- for (i = 0; i < count; i++) {
- vdd_uV = regulator_list_voltage(supply, i);
- if (vdd_uV <= 0)
- continue;
-
- vdd_mV = vdd_uV / 1000;
- result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
- }
-
- if (!result) {
- vdd_uV = regulator_get_voltage(supply);
- if (vdd_uV <= 0)
- return vdd_uV;
-
- vdd_mV = vdd_uV / 1000;
- result = mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
- }
-
- return result;
-}
-EXPORT_SYMBOL_GPL(mmc_regulator_get_ocrmask);
-
-/**
- * mmc_regulator_set_ocr - set regulator to match host->ios voltage
- * @mmc: the host to regulate
- * @supply: regulator to use
- * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
- *
- * Returns zero on success, else negative errno.
- *
- * MMC host drivers may use this to enable or disable a regulator using
- * a particular supply voltage. This would normally be called from the
- * set_ios() method.
- */
-int mmc_regulator_set_ocr(struct mmc_host *mmc,
- struct regulator *supply,
- unsigned short vdd_bit)
-{
- int result = 0;
- int min_uV, max_uV;
-
- if (vdd_bit) {
- mmc_ocrbitnum_to_vdd(vdd_bit, &min_uV, &max_uV);
-
- result = regulator_set_voltage(supply, min_uV, max_uV);
- if (result == 0 && !mmc->regulator_enabled) {
- result = regulator_enable(supply);
- if (!result)
- mmc->regulator_enabled = true;
- }
- } else if (mmc->regulator_enabled) {
- result = regulator_disable(supply);
- if (result == 0)
- mmc->regulator_enabled = false;
- }
-
- if (result)
- dev_err(mmc_dev(mmc),
- "could not set regulator OCR (%d)\n", result);
- return result;
-}
-EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr);
-
-static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator,
- int min_uV, int target_uV,
- int max_uV)
-{
- /*
- * Check if supported first to avoid errors since we may try several
- * signal levels during power up and don't want to show errors.
- */
- if (!regulator_is_supported_voltage(regulator, min_uV, max_uV))
- return -EINVAL;
-
- return regulator_set_voltage_triplet(regulator, min_uV, target_uV,
- max_uV);
-}
-
-/**
- * mmc_regulator_set_vqmmc - Set VQMMC as per the ios
- *
- * For 3.3V signaling, we try to match VQMMC to VMMC as closely as possible.
- * That will match the behavior of old boards where VQMMC and VMMC were supplied
- * by the same supply. The Bus Operating conditions for 3.3V signaling in the
- * SD card spec also define VQMMC in terms of VMMC.
- * If this is not possible we'll try the full 2.7-3.6V of the spec.
- *
- * For 1.2V and 1.8V signaling we'll try to get as close as possible to the
- * requested voltage. This is definitely a good idea for UHS where there's a
- * separate regulator on the card that's trying to make 1.8V and it's best if
- * we match.
- *
- * This function is expected to be used by a controller's
- * start_signal_voltage_switch() function.
- */
-int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct device *dev = mmc_dev(mmc);
- int ret, volt, min_uV, max_uV;
-
- /* If no vqmmc supply then we can't change the voltage */
- if (IS_ERR(mmc->supply.vqmmc))
- return -EINVAL;
-
- switch (ios->signal_voltage) {
- case MMC_SIGNAL_VOLTAGE_120:
- return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
- 1100000, 1200000, 1300000);
- case MMC_SIGNAL_VOLTAGE_180:
- return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
- 1700000, 1800000, 1950000);
- case MMC_SIGNAL_VOLTAGE_330:
- ret = mmc_ocrbitnum_to_vdd(mmc->ios.vdd, &volt, &max_uV);
- if (ret < 0)
- return ret;
-
- dev_dbg(dev, "%s: found vmmc voltage range of %d-%duV\n",
- __func__, volt, max_uV);
-
- min_uV = max(volt - 300000, 2700000);
- max_uV = min(max_uV + 200000, 3600000);
-
- /*
- * Due to a limitation in the current implementation of
- * regulator_set_voltage_triplet() which is taking the lowest
- * voltage possible if below the target, search for a suitable
- * voltage in two steps and try to stay close to vmmc
- * with a 0.3V tolerance at first.
- */
- if (!mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
- min_uV, volt, max_uV))
- return 0;
-
- return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
- 2700000, volt, 3600000);
- default:
- return -EINVAL;
- }
-}
-EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc);
-
-#endif /* CONFIG_REGULATOR */
-
-int mmc_regulator_get_supply(struct mmc_host *mmc)
-{
- struct device *dev = mmc_dev(mmc);
- int ret;
-
- mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
- mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
-
- if (IS_ERR(mmc->supply.vmmc)) {
- if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- dev_dbg(dev, "No vmmc regulator found\n");
- } else {
- ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
- if (ret > 0)
- mmc->ocr_avail = ret;
- else
- dev_warn(dev, "Failed getting OCR mask: %d\n", ret);
- }
-
- if (IS_ERR(mmc->supply.vqmmc)) {
- if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- dev_dbg(dev, "No vqmmc regulator found\n");
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
-
/*
* Mask off any voltages we don't support and select
* the lowest voltage
@@ -1448,13 +1137,19 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
return 0;
}
- if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
+ if (!mmc_card_uhs2(host) && host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
bit = ffs(ocr) - 1;
ocr &= 3 << bit;
mmc_power_cycle(host, ocr);
} else {
bit = fls(ocr) - 1;
- ocr &= 3 << bit;
+ /*
+ * The bit variable represents the highest voltage bit set in
+ * the OCR register.
+ * To keep a range of 2 values (e.g. 3.2V/3.3V and 3.3V/3.4V),
+ * we must shift the mask '3' with (bit - 1).
+ */
+ ocr &= 3 << (bit - 1);
if (bit != host->ios.vdd)
dev_warn(mmc_dev(host), "exceeding card's volts\n");
}
@@ -1478,11 +1173,44 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
}
+void mmc_set_initial_signal_voltage(struct mmc_host *host)
+{
+ /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
+ if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
+ dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
+ dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
+ dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
+}
+
+int mmc_host_set_uhs_voltage(struct mmc_host *host)
+{
+ u32 clock;
+
+ /*
+ * During a signal voltage level switch, the clock must be gated
+ * for 5 ms according to the SD spec
+ */
+ clock = host->ios.clock;
+ host->ios.clock = 0;
+ mmc_set_ios(host);
+
+ if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
+ return -EAGAIN;
+
+ /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
+ mmc_delay(10);
+ host->ios.clock = clock;
+ mmc_set_ios(host);
+
+ return 0;
+}
+
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
{
struct mmc_command cmd = {};
int err = 0;
- u32 clock;
/*
* If we cannot switch voltages, return failure so the caller
@@ -1500,7 +1228,7 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
- return err;
+ goto power_cycle;
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
return -EIO;
@@ -1514,15 +1242,8 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
err = -EAGAIN;
goto power_cycle;
}
- /*
- * During a signal voltage level switch, the clock must be gated
- * for 5 ms according to the SD spec
- */
- clock = host->ios.clock;
- host->ios.clock = 0;
- mmc_set_ios(host);
- if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
+ if (mmc_host_set_uhs_voltage(host)) {
/*
* Voltages may not have been switched, but we've already
* sent CMD11, so a power cycle is required anyway
@@ -1531,11 +1252,6 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
goto power_cycle;
}
- /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
- mmc_delay(10);
- host->ios.clock = clock;
- mmc_set_ios(host);
-
/* Wait for at least 1 ms according to spec */
mmc_delay(1);
@@ -1630,19 +1346,13 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
/* Set initial state and call mmc_set_ios */
mmc_set_initial_state(host);
- /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
- if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
- dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
- else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
- dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
- else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
- dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
+ mmc_set_initial_signal_voltage(host);
/*
* This delay should be sufficient to allow the power supply
* to reach the minimum voltage.
*/
- mmc_delay(10);
+ mmc_delay(host->ios.power_delay_ms);
mmc_pwrseq_post_power_on(host);
@@ -1655,7 +1365,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
* This delay must be at least 74 clock sizes, or 1 ms, or the
* time required to reach a stable voltage.
*/
- mmc_delay(10);
+ mmc_delay(host->ios.power_delay_ms);
}
void mmc_power_off(struct mmc_host *host)
@@ -1688,41 +1398,27 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr)
mmc_power_up(host, ocr);
}
-/*
- * Cleanup when the last reference to the bus operator is dropped.
- */
-static void __mmc_release_bus(struct mmc_host *host)
-{
- WARN_ON(!host->bus_dead);
-
- host->bus_ops = NULL;
-}
-
-/*
- * Increase reference count of bus operator
+/**
+ * mmc_handle_undervoltage - Handle an undervoltage event on the MMC bus
+ * @host: The MMC host that detected the undervoltage condition
+ *
+ * This function is called when an undervoltage event is detected on one of
+ * the MMC regulators.
+ *
+ * Returns: 0 on success or a negative error code on failure.
*/
-static inline void mmc_bus_get(struct mmc_host *host)
+int mmc_handle_undervoltage(struct mmc_host *host)
{
- unsigned long flags;
+ /* Stop the host to prevent races with card removal */
+ __mmc_stop_host(host);
- spin_lock_irqsave(&host->lock, flags);
- host->bus_refs++;
- spin_unlock_irqrestore(&host->lock, flags);
-}
+ if (!host->bus_ops || !host->bus_ops->handle_undervoltage)
+ return 0;
-/*
- * Decrease reference count of bus operator and free it if
- * it is the last reference.
- */
-static inline void mmc_bus_put(struct mmc_host *host)
-{
- unsigned long flags;
+ dev_warn(mmc_dev(host), "%s: Undervoltage detected, initiating emergency stop\n",
+ mmc_hostname(host));
- spin_lock_irqsave(&host->lock, flags);
- host->bus_refs--;
- if ((host->bus_refs == 0) && host->bus_ops)
- __mmc_release_bus(host);
- spin_unlock_irqrestore(&host->lock, flags);
+ return host->bus_ops->handle_undervoltage(host);
}
/*
@@ -1731,20 +1427,7 @@ static inline void mmc_bus_put(struct mmc_host *host)
*/
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
- unsigned long flags;
-
- WARN_ON(!host->claimed);
-
- spin_lock_irqsave(&host->lock, flags);
-
- WARN_ON(host->bus_ops);
- WARN_ON(host->bus_refs);
-
host->bus_ops = ops;
- host->bus_refs = 1;
- host->bus_dead = 0;
-
- spin_unlock_irqrestore(&host->lock, flags);
}
/*
@@ -1752,37 +1435,18 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
*/
void mmc_detach_bus(struct mmc_host *host)
{
- unsigned long flags;
-
- WARN_ON(!host->claimed);
- WARN_ON(!host->bus_ops);
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->bus_dead = 1;
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- mmc_bus_put(host);
+ host->bus_ops = NULL;
}
-static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
- bool cd_irq)
+void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq)
{
-#ifdef CONFIG_MMC_DEBUG
- unsigned long flags;
- spin_lock_irqsave(&host->lock, flags);
- WARN_ON(host->removed);
- spin_unlock_irqrestore(&host->lock, flags);
-#endif
-
/*
- * If the device is configured as wakeup, we prevent a new sleep for
- * 5 s to give provision for user space to consume the event.
+ * Prevent system sleep for 5s to allow user space to consume the
+ * corresponding uevent. This is especially useful, when CD irq is used
+ * as a system wakeup, but doesn't hurt in other cases.
*/
- if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
- device_can_wakeup(mmc_dev(host)))
- pm_wakeup_event(mmc_dev(host), 5000);
+ if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL))
+ __pm_wakeup_event(host->ws, 5000);
host->detect_change = 1;
mmc_schedule_delayed_work(&host->detect, delay);
@@ -1852,6 +1516,11 @@ void mmc_init_erase(struct mmc_card *card)
card->pref_erase = 0;
}
+static bool is_trim_arg(unsigned int arg)
+{
+ return (arg & MMC_TRIM_OR_DISCARD_ARGS) && arg != MMC_DISCARD_ARG;
+}
+
static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
unsigned int arg, unsigned int qty)
{
@@ -1869,14 +1538,14 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
} else {
/* CSD Erase Group Size uses write timeout */
unsigned int mult = (10 << card->csd.r2w_factor);
- unsigned int timeout_clks = card->csd.tacc_clks * mult;
+ unsigned int timeout_clks = card->csd.taac_clks * mult;
unsigned int timeout_us;
- /* Avoid overflow: e.g. tacc_ns=80000000 mult=1280 */
- if (card->csd.tacc_ns < 1000000)
- timeout_us = (card->csd.tacc_ns * mult) / 1000;
+ /* Avoid overflow: e.g. taac_ns=80000000 mult=1280 */
+ if (card->csd.taac_ns < 1000000)
+ timeout_us = (card->csd.taac_ns * mult) / 1000;
else
- timeout_us = (card->csd.tacc_ns / 1000) * mult;
+ timeout_us = (card->csd.taac_ns / 1000) * mult;
/*
* ios.clock is only a target. The real clock rate might be
@@ -1922,6 +1591,12 @@ static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
{
unsigned int erase_timeout;
+ /* for DISCARD none of the below calculation applies.
+ * the busy timeout is 250msec per discard command.
+ */
+ if (arg == SD_DISCARD_ARG)
+ return SD_DISCARD_TIMEOUT_MS;
+
if (card->ssr.erase_timeout) {
/* Erase timeout specified in SD Status Register (SSR) */
erase_timeout = card->ssr.erase_timeout * qty +
@@ -1951,13 +1626,12 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card,
return mmc_mmc_erase_timeout(card, arg, qty);
}
-static int mmc_do_erase(struct mmc_card *card, unsigned int from,
- unsigned int to, unsigned int arg)
+static int mmc_do_erase(struct mmc_card *card, sector_t from,
+ sector_t to, unsigned int arg)
{
struct mmc_command cmd = {};
unsigned int qty = 0, busy_timeout = 0;
- bool use_r1b_resp = false;
- unsigned long timeout;
+ bool use_r1b_resp;
int err;
mmc_retune_hold(card->host);
@@ -1984,8 +1658,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
else if (mmc_card_sd(card))
qty += to - from + 1;
else
- qty += ((to / card->erase_size) -
- (from / card->erase_size)) + 1;
+ qty += (mmc_sector_div(to, card->erase_size) -
+ mmc_sector_div(from, card->erase_size)) + 1;
if (!mmc_card_blockaddr(card)) {
from <<= 9;
@@ -1998,6 +1672,12 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
cmd.opcode = MMC_ERASE_GROUP_START;
cmd.arg = from;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+
+ if (mmc_card_ult_capacity(card)) {
+ cmd.ext_addr = from >> 32;
+ cmd.has_ext_addr = true;
+ }
+
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
pr_err("mmc_erase: group start error %d, "
@@ -2013,6 +1693,12 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
cmd.opcode = MMC_ERASE_GROUP_END;
cmd.arg = to;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+
+ if (mmc_card_ult_capacity(card)) {
+ cmd.ext_addr = to >> 32;
+ cmd.has_ext_addr = true;
+ }
+
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
pr_err("mmc_erase: group end error %d, status %#x\n",
@@ -2025,20 +1711,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
cmd.opcode = MMC_ERASE;
cmd.arg = arg;
busy_timeout = mmc_erase_timeout(card, arg, qty);
- /*
- * If the host controller supports busy signalling and the timeout for
- * the erase operation does not exceed the max_busy_timeout, we should
- * use R1B response. Or we need to prevent the host from doing hw busy
- * detection, which is done by converting to a R1 response instead.
- */
- if (card->host->max_busy_timeout &&
- busy_timeout > card->host->max_busy_timeout) {
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- } else {
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- cmd.busy_timeout = busy_timeout;
- use_r1b_resp = true;
- }
+ use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd, busy_timeout);
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
@@ -2058,51 +1731,28 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
goto out;
- timeout = jiffies + msecs_to_jiffies(busy_timeout);
- do {
- memset(&cmd, 0, sizeof(struct mmc_command));
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- /* Do not retry else we can't see errors */
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err || (cmd.resp[0] & 0xFDF92000)) {
- pr_err("error %d requesting status %#x\n",
- err, cmd.resp[0]);
- err = -EIO;
- goto out;
- }
-
- /* Timeout if the device never becomes ready for data and
- * never leaves the program state.
- */
- if (time_after(jiffies, timeout)) {
- pr_err("%s: Card stuck in programming state! %s\n",
- mmc_hostname(card->host), __func__);
- err = -EIO;
- goto out;
- }
+ /* Let's poll to find out when the erase operation completes. */
+ err = mmc_poll_for_busy(card, busy_timeout, false, MMC_BUSY_ERASE);
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
out:
mmc_retune_release(card->host);
return err;
}
static unsigned int mmc_align_erase_size(struct mmc_card *card,
- unsigned int *from,
- unsigned int *to,
+ sector_t *from,
+ sector_t *to,
unsigned int nr)
{
- unsigned int from_new = *from, nr_new = nr, rem;
+ sector_t from_new = *from;
+ unsigned int nr_new = nr, rem;
/*
* When the 'card->erase_size' is power of 2, we can use round_up/down()
* to align the erase size efficiently.
*/
if (is_power_of_2(card->erase_size)) {
- unsigned int temp = from_new;
+ sector_t temp = from_new;
from_new = round_up(temp, card->erase_size);
rem = from_new - temp;
@@ -2114,7 +1764,7 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card,
nr_new = round_down(nr_new, card->erase_size);
} else {
- rem = from_new % card->erase_size;
+ rem = mmc_sector_mod(from_new, card->erase_size);
if (rem) {
rem = card->erase_size - rem;
from_new += rem;
@@ -2143,36 +1793,37 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card,
* @card: card to erase
* @from: first sector to erase
* @nr: number of sectors to erase
- * @arg: erase command argument (SD supports only %MMC_ERASE_ARG)
+ * @arg: erase command argument
*
* Caller must claim host before calling this function.
*/
-int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
+int mmc_erase(struct mmc_card *card, sector_t from, unsigned int nr,
unsigned int arg)
{
- unsigned int rem, to = from + nr;
+ unsigned int rem;
+ sector_t to = from + nr;
+
int err;
- if (!(card->host->caps & MMC_CAP_ERASE) ||
- !(card->csd.cmdclass & CCC_ERASE))
+ if (!(card->csd.cmdclass & CCC_ERASE))
return -EOPNOTSUPP;
if (!card->erase_size)
return -EOPNOTSUPP;
- if (mmc_card_sd(card) && arg != MMC_ERASE_ARG)
+ if (mmc_card_sd(card) && arg != SD_ERASE_ARG && arg != SD_DISCARD_ARG)
return -EOPNOTSUPP;
- if ((arg & MMC_SECURE_ARGS) &&
+ if (mmc_card_mmc(card) && (arg & MMC_SECURE_ARGS) &&
!(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN))
return -EOPNOTSUPP;
- if ((arg & MMC_TRIM_ARGS) &&
+ if (mmc_card_mmc(card) && is_trim_arg(arg) &&
!(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN))
return -EOPNOTSUPP;
if (arg == MMC_SECURE_ERASE_ARG) {
- if (from % card->erase_size || nr % card->erase_size)
+ if (mmc_sector_mod(from, card->erase_size) || nr % card->erase_size)
return -EINVAL;
}
@@ -2196,8 +1847,8 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
* and call mmc_do_erase() twice if necessary. This special case is
* identified by the card->eg_boundary flag.
*/
- rem = card->erase_size - (from % card->erase_size);
- if ((arg & MMC_TRIM_ARGS) && (card->eg_boundary) && (nr > rem)) {
+ rem = card->erase_size - mmc_sector_mod(from, card->erase_size);
+ if ((arg & MMC_TRIM_OR_DISCARD_ARGS) && card->eg_boundary && nr > rem) {
err = mmc_do_erase(card, from, from + rem - 1, arg);
from += rem;
if ((err) || (to <= from))
@@ -2208,61 +1859,60 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
}
EXPORT_SYMBOL(mmc_erase);
-int mmc_can_erase(struct mmc_card *card)
+bool mmc_card_can_erase(struct mmc_card *card)
{
- if ((card->host->caps & MMC_CAP_ERASE) &&
- (card->csd.cmdclass & CCC_ERASE) && card->erase_size)
- return 1;
- return 0;
+ return (card->csd.cmdclass & CCC_ERASE && card->erase_size);
}
-EXPORT_SYMBOL(mmc_can_erase);
+EXPORT_SYMBOL(mmc_card_can_erase);
-int mmc_can_trim(struct mmc_card *card)
+bool mmc_card_can_trim(struct mmc_card *card)
{
- if ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) &&
- (!(card->quirks & MMC_QUIRK_TRIM_BROKEN)))
- return 1;
- return 0;
+ return ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) &&
+ (!(card->quirks & MMC_QUIRK_TRIM_BROKEN)));
}
-EXPORT_SYMBOL(mmc_can_trim);
+EXPORT_SYMBOL(mmc_card_can_trim);
-int mmc_can_discard(struct mmc_card *card)
+bool mmc_card_can_discard(struct mmc_card *card)
{
/*
* As there's no way to detect the discard support bit at v4.5
* use the s/w feature support filed.
*/
- if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE)
- return 1;
- return 0;
+ return (card->ext_csd.feature_support & MMC_DISCARD_FEATURE);
}
-EXPORT_SYMBOL(mmc_can_discard);
+EXPORT_SYMBOL(mmc_card_can_discard);
-int mmc_can_sanitize(struct mmc_card *card)
+bool mmc_card_can_sanitize(struct mmc_card *card)
{
- if (!mmc_can_trim(card) && !mmc_can_erase(card))
- return 0;
+ if (!mmc_card_can_trim(card) && !mmc_card_can_erase(card))
+ return false;
if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
- return 1;
- return 0;
+ return true;
+ return false;
}
-EXPORT_SYMBOL(mmc_can_sanitize);
-int mmc_can_secure_erase_trim(struct mmc_card *card)
+bool mmc_card_can_secure_erase_trim(struct mmc_card *card)
{
- if ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN) &&
- !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN))
- return 1;
- return 0;
+ return ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN) &&
+ !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN));
}
-EXPORT_SYMBOL(mmc_can_secure_erase_trim);
+EXPORT_SYMBOL(mmc_card_can_secure_erase_trim);
-int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
+bool mmc_card_can_cmd23(struct mmc_card *card)
+{
+ return ((mmc_card_mmc(card) &&
+ card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
+ (mmc_card_sd(card) && !mmc_card_ult_capacity(card) &&
+ card->scr.cmds & SD_SCR_CMD23_SUPPORT));
+}
+EXPORT_SYMBOL(mmc_card_can_cmd23);
+
+int mmc_erase_group_aligned(struct mmc_card *card, sector_t from,
unsigned int nr)
{
if (!card->erase_size)
return 0;
- if (from % card->erase_size || nr % card->erase_size)
+ if (mmc_sector_mod(from, card->erase_size) || nr % card->erase_size)
return 0;
return 1;
}
@@ -2360,9 +2010,9 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
return card->pref_erase;
max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
- if (mmc_can_trim(card)) {
+ if (mmc_card_can_trim(card)) {
max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
- if (max_trim < max_discard)
+ if (max_trim < max_discard || max_discard == 0)
max_discard = max_trim;
} else if (max_discard < card->erase_size) {
max_discard = 0;
@@ -2395,61 +2045,63 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
}
EXPORT_SYMBOL(mmc_set_blocklen);
-int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
- bool is_rel_write)
-{
- struct mmc_command cmd = {};
-
- cmd.opcode = MMC_SET_BLOCK_COUNT;
- cmd.arg = blockcount & 0x0000FFFF;
- if (is_rel_write)
- cmd.arg |= 1 << 31;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- return mmc_wait_for_cmd(card->host, &cmd, 5);
-}
-EXPORT_SYMBOL(mmc_set_blockcount);
-
static void mmc_hw_reset_for_init(struct mmc_host *host)
{
mmc_pwrseq_reset(host);
- if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+ if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->card_hw_reset)
return;
- host->ops->hw_reset(host);
+ host->ops->card_hw_reset(host);
}
-int mmc_hw_reset(struct mmc_host *host)
+/**
+ * mmc_hw_reset - reset the card in hardware
+ * @card: card to be reset
+ *
+ * Hard reset the card. This function is only for upper layers, like the
+ * block layer or card drivers. You cannot use it in host drivers (struct
+ * mmc_card might be gone then).
+ *
+ * Return: 0 on success, -errno on failure
+ */
+int mmc_hw_reset(struct mmc_card *card)
{
+ struct mmc_host *host = card->host;
int ret;
- if (!host->card)
- return -EINVAL;
+ ret = host->bus_ops->hw_reset(host);
+ if (ret < 0)
+ pr_warn("%s: tried to HW reset card, got error %d\n",
+ mmc_hostname(host), ret);
- mmc_bus_get(host);
- if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) {
- mmc_bus_put(host);
- return -EOPNOTSUPP;
- }
+ return ret;
+}
+EXPORT_SYMBOL(mmc_hw_reset);
- ret = host->bus_ops->reset(host);
- mmc_bus_put(host);
+int mmc_sw_reset(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ int ret;
+ if (!host->bus_ops->sw_reset)
+ return -EOPNOTSUPP;
+
+ ret = host->bus_ops->sw_reset(host);
if (ret)
- pr_warn("%s: tried to reset card, got error %d\n",
+ pr_warn("%s: tried to SW reset card, got error %d\n",
mmc_hostname(host), ret);
return ret;
}
-EXPORT_SYMBOL(mmc_hw_reset);
+EXPORT_SYMBOL(mmc_sw_reset);
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;
-#ifdef CONFIG_MMC_DEBUG
- pr_info("%s: %s: trying to init card at %u Hz\n",
+ pr_debug("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init);
-#endif
+
mmc_power_up(host, host->ocr_avail);
/*
@@ -2469,8 +2121,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
mmc_go_idle(host);
- if (!(host->caps2 & MMC_CAP2_NO_SD))
- mmc_send_if_cond(host, host->ocr_avail);
+ if (!(host->caps2 & MMC_CAP2_NO_SD)) {
+ if (mmc_send_if_cond_pcie(host, host->ocr_avail))
+ goto out;
+ if (mmc_card_sd_express(host))
+ return 0;
+ }
/* Order's important: probe SDIO, then SD, then MMC */
if (!(host->caps2 & MMC_CAP2_NO_SDIO))
@@ -2485,6 +2141,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
if (!mmc_attach_mmc(host))
return 0;
+out:
mmc_power_off(host);
return -EIO;
}
@@ -2556,6 +2213,41 @@ int mmc_detect_card_removed(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_detect_card_removed);
+int mmc_card_alternative_gpt_sector(struct mmc_card *card, sector_t *gpt_sector)
+{
+ unsigned int boot_sectors_num;
+
+ if ((!(card->host->caps2 & MMC_CAP2_ALT_GPT_TEGRA)))
+ return -EOPNOTSUPP;
+
+ /* filter out unrelated cards */
+ if (card->ext_csd.rev < 3 ||
+ !mmc_card_mmc(card) ||
+ !mmc_card_is_blockaddr(card) ||
+ mmc_card_is_removable(card->host))
+ return -ENOENT;
+
+ /*
+ * eMMC storage has two special boot partitions in addition to the
+ * main one. NVIDIA's bootloader linearizes eMMC boot0->boot1->main
+ * accesses, this means that the partition table addresses are shifted
+ * by the size of boot partitions. In accordance with the eMMC
+ * specification, the boot partition size is calculated as follows:
+ *
+ * boot partition size = 128K byte x BOOT_SIZE_MULT
+ *
+ * Calculate number of sectors occupied by the both boot partitions.
+ */
+ boot_sectors_num = card->ext_csd.raw_boot_mult * SZ_128K /
+ SZ_512 * MMC_NUM_BOOT_PARTITION;
+
+ /* Defined by NVIDIA and used by Android devices. */
+ *gpt_sector = card->ext_csd.sectors - boot_sectors_num - 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(mmc_card_alternative_gpt_sector);
+
void mmc_rescan(struct work_struct *work)
{
struct mmc_host *host =
@@ -2577,35 +2269,15 @@ void mmc_rescan(struct work_struct *work)
host->trigger_card_event = false;
}
- mmc_bus_get(host);
-
- /*
- * if there is a _removable_ card registered, check whether it is
- * still present
- */
- if (host->bus_ops && !host->bus_dead && mmc_card_is_removable(host))
+ /* Verify a registered card to be functional, else remove it. */
+ if (host->bus_ops)
host->bus_ops->detect(host);
host->detect_change = 0;
- /*
- * Let mmc_bus_put() free the bus/bus_ops if we've found that
- * the card is no longer present.
- */
- mmc_bus_put(host);
- mmc_bus_get(host);
-
/* if there still is a card present, stop here */
- if (host->bus_ops != NULL) {
- mmc_bus_put(host);
+ if (host->bus_ops != NULL)
goto out;
- }
-
- /*
- * Only we can add a new handler, so it's safe to
- * release the lock here.
- */
- mmc_bus_put(host);
mmc_claim_host(host);
if (mmc_card_is_removable(host) && host->ops->get_cd &&
@@ -2615,12 +2287,47 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
+ /* If an SD express card is present, then leave it as is. */
+ if (mmc_card_sd_express(host)) {
+ mmc_release_host(host);
+ goto out;
+ }
+
+ /*
+ * Ideally we should favor initialization of legacy SD cards and defer
+ * UHS-II enumeration. However, it seems like cards doesn't reliably
+ * announce their support for UHS-II in the response to the ACMD41,
+ * while initializing the legacy SD interface. Therefore, let's start
+ * with UHS-II for now.
+ */
+ if (!mmc_attach_sd_uhs2(host)) {
+ mmc_release_host(host);
+ goto out;
+ }
+
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
- if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
+ unsigned int freq = freqs[i];
+ if (freq > host->f_max) {
+ if (i + 1 < ARRAY_SIZE(freqs))
+ continue;
+ freq = host->f_max;
+ }
+ if (!mmc_rescan_try_freq(host, max(freq, host->f_min)))
break;
if (freqs[i] <= host->f_min)
break;
}
+
+ /* A non-removable card should have been detected by now. */
+ if (!mmc_card_is_removable(host) && !host->bus_ops)
+ pr_info("%s: Failed to initialize a non-removable card",
+ mmc_hostname(host));
+
+ /*
+ * Ignore the command timeout errors observed during
+ * the card init as those are excepted.
+ */
+ host->err_stats[MMC_ERR_CMD_TIMEOUT] = 0;
mmc_release_host(host);
out:
@@ -2630,11 +2337,13 @@ void mmc_rescan(struct work_struct *work)
void mmc_start_host(struct mmc_host *host)
{
- host->f_init = max(freqs[0], host->f_min);
+ bool power_up = !(host->caps2 &
+ (MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_SD_UHS2));
+
+ host->f_init = max(min(freqs[0], host->f_max), host->f_min);
host->rescan_disable = 0;
- host->ios.power_mode = MMC_POWER_UNDEFINED;
- if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
+ if (power_up) {
mmc_claim_host(host);
mmc_power_up(host, host->ocr_avail);
mmc_release_host(host);
@@ -2644,176 +2353,42 @@ void mmc_start_host(struct mmc_host *host)
_mmc_detect_change(host, 0, false);
}
-void mmc_stop_host(struct mmc_host *host)
+void __mmc_stop_host(struct mmc_host *host)
{
-#ifdef CONFIG_MMC_DEBUG
- unsigned long flags;
- spin_lock_irqsave(&host->lock, flags);
- host->removed = 1;
- spin_unlock_irqrestore(&host->lock, flags);
-#endif
+ if (host->rescan_disable)
+ return;
+
if (host->slot.cd_irq >= 0) {
- if (host->slot.cd_wake_enabled)
- disable_irq_wake(host->slot.cd_irq);
+ mmc_gpio_set_cd_wake(host, false);
disable_irq(host->slot.cd_irq);
}
host->rescan_disable = 1;
cancel_delayed_work_sync(&host->detect);
+}
+
+void mmc_stop_host(struct mmc_host *host)
+{
+ __mmc_stop_host(host);
/* clear pm flags now and let card drivers set them as needed */
host->pm_flags = 0;
- mmc_bus_get(host);
- if (host->bus_ops && !host->bus_dead) {
+ if (host->bus_ops) {
/* Calling bus_ops->remove() with a claimed host can deadlock */
host->bus_ops->remove(host);
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
mmc_release_host(host);
- mmc_bus_put(host);
return;
}
- mmc_bus_put(host);
mmc_claim_host(host);
mmc_power_off(host);
mmc_release_host(host);
}
-int mmc_power_save_host(struct mmc_host *host)
-{
- int ret = 0;
-
-#ifdef CONFIG_MMC_DEBUG
- pr_info("%s: %s: powering down\n", mmc_hostname(host), __func__);
-#endif
-
- mmc_bus_get(host);
-
- if (!host->bus_ops || host->bus_dead) {
- mmc_bus_put(host);
- return -EINVAL;
- }
-
- if (host->bus_ops->power_save)
- ret = host->bus_ops->power_save(host);
-
- mmc_bus_put(host);
-
- mmc_power_off(host);
-
- return ret;
-}
-EXPORT_SYMBOL(mmc_power_save_host);
-
-int mmc_power_restore_host(struct mmc_host *host)
-{
- int ret;
-
-#ifdef CONFIG_MMC_DEBUG
- pr_info("%s: %s: powering up\n", mmc_hostname(host), __func__);
-#endif
-
- mmc_bus_get(host);
-
- if (!host->bus_ops || host->bus_dead) {
- mmc_bus_put(host);
- return -EINVAL;
- }
-
- mmc_power_up(host, host->card->ocr);
- ret = host->bus_ops->power_restore(host);
-
- mmc_bus_put(host);
-
- return ret;
-}
-EXPORT_SYMBOL(mmc_power_restore_host);
-
-#ifdef CONFIG_PM_SLEEP
-/* Do the card removal on suspend if card is assumed removeable
- * Do that in pm notifier while userspace isn't yet frozen, so we will be able
- to sync the card.
-*/
-static int mmc_pm_notify(struct notifier_block *notify_block,
- unsigned long mode, void *unused)
-{
- struct mmc_host *host = container_of(
- notify_block, struct mmc_host, pm_notify);
- unsigned long flags;
- int err = 0;
-
- switch (mode) {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- case PM_RESTORE_PREPARE:
- spin_lock_irqsave(&host->lock, flags);
- host->rescan_disable = 1;
- spin_unlock_irqrestore(&host->lock, flags);
- cancel_delayed_work_sync(&host->detect);
-
- if (!host->bus_ops)
- break;
-
- /* Validate prerequisites for suspend */
- if (host->bus_ops->pre_suspend)
- err = host->bus_ops->pre_suspend(host);
- if (!err)
- break;
-
- /* Calling bus_ops->remove() with a claimed host can deadlock */
- host->bus_ops->remove(host);
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- host->pm_flags = 0;
- break;
-
- case PM_POST_SUSPEND:
- case PM_POST_HIBERNATION:
- case PM_POST_RESTORE:
-
- spin_lock_irqsave(&host->lock, flags);
- host->rescan_disable = 0;
- spin_unlock_irqrestore(&host->lock, flags);
- _mmc_detect_change(host, 0, false);
-
- }
-
- return 0;
-}
-
-void mmc_register_pm_notifier(struct mmc_host *host)
-{
- host->pm_notify.notifier_call = mmc_pm_notify;
- register_pm_notifier(&host->pm_notify);
-}
-
-void mmc_unregister_pm_notifier(struct mmc_host *host)
-{
- unregister_pm_notifier(&host->pm_notify);
-}
-#endif
-
-/**
- * mmc_init_context_info() - init synchronization context
- * @host: mmc host
- *
- * Init struct context_info needed to implement asynchronous
- * request mechanism, used by mmc core, host driver and mmc requests
- * supplier.
- */
-void mmc_init_context_info(struct mmc_host *host)
-{
- host->context_info.is_new_req = false;
- host->context_info.is_done_rcv = false;
- host->context_info.is_waiting_last_req = false;
- init_waitqueue_head(&host->context_info.wait);
-}
-
static int __init mmc_init(void)
{
int ret;
@@ -2849,4 +2424,5 @@ static void __exit mmc_exit(void)
subsys_initcall(mmc_init);
module_exit(mmc_exit);
+MODULE_DESCRIPTION("MMC core driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 55f543fd37c4..a028b48be164 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/mmc/core/core.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _MMC_CORE_CORE_H
#define _MMC_CORE_CORE_H
@@ -28,11 +25,13 @@ struct mmc_bus_ops {
int (*resume)(struct mmc_host *);
int (*runtime_suspend)(struct mmc_host *);
int (*runtime_resume)(struct mmc_host *);
- int (*power_save)(struct mmc_host *);
- int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *);
int (*shutdown)(struct mmc_host *);
- int (*reset)(struct mmc_host *);
+ int (*hw_reset)(struct mmc_host *);
+ int (*sw_reset)(struct mmc_host *);
+ bool (*cache_enabled)(struct mmc_host *);
+ int (*flush_cache)(struct mmc_host *);
+ int (*handle_undervoltage)(struct mmc_host *host);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -49,7 +48,9 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
+int mmc_host_set_uhs_voltage(struct mmc_host *host);
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
+void mmc_set_initial_signal_voltage(struct mmc_host *host);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
@@ -58,74 +59,88 @@ void mmc_power_up(struct mmc_host *host, u32 ocr);
void mmc_power_off(struct mmc_host *host);
void mmc_power_cycle(struct mmc_host *host, u32 ocr);
void mmc_set_initial_state(struct mmc_host *host);
+u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max);
+int mmc_handle_undervoltage(struct mmc_host *host);
+void mmc_regulator_register_undervoltage_notifier(struct mmc_host *host);
+void mmc_regulator_unregister_undervoltage_notifier(struct mmc_host *host);
+void mmc_undervoltage_workfn(struct work_struct *work);
static inline void mmc_delay(unsigned int ms)
{
- if (ms < 1000 / HZ) {
- cond_resched();
- mdelay(ms);
- } else {
+ if (ms <= 20)
+ usleep_range(ms * 1000, ms * 1250);
+ else
msleep(ms);
- }
}
void mmc_rescan(struct work_struct *work);
void mmc_start_host(struct mmc_host *host);
+void __mmc_stop_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host);
+void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
+ bool cd_irq);
int _mmc_detect_card_removed(struct mmc_host *host);
int mmc_detect_card_removed(struct mmc_host *host);
int mmc_attach_mmc(struct mmc_host *host);
int mmc_attach_sd(struct mmc_host *host);
int mmc_attach_sdio(struct mmc_host *host);
+int mmc_attach_sd_uhs2(struct mmc_host *host);
/* Module parameters */
extern bool use_spi_crc;
/* Debugfs information for hosts and cards */
+#ifdef CONFIG_DEBUG_FS
void mmc_add_host_debugfs(struct mmc_host *host);
void mmc_remove_host_debugfs(struct mmc_host *host);
void mmc_add_card_debugfs(struct mmc_card *card);
void mmc_remove_card_debugfs(struct mmc_card *card);
-
-void mmc_init_context_info(struct mmc_host *host);
+#else
+static inline void mmc_add_host_debugfs(struct mmc_host *host)
+{
+}
+static inline void mmc_remove_host_debugfs(struct mmc_host *host)
+{
+}
+static inline void mmc_add_card_debugfs(struct mmc_card *card)
+{
+}
+static inline void mmc_remove_card_debugfs(struct mmc_card *card)
+{
+}
+#endif
int mmc_execute_tuning(struct mmc_card *card);
int mmc_hs200_to_hs400(struct mmc_card *card);
int mmc_hs400_to_hs200(struct mmc_card *card);
-#ifdef CONFIG_PM_SLEEP
-void mmc_register_pm_notifier(struct mmc_host *host);
-void mmc_unregister_pm_notifier(struct mmc_host *host);
-#else
-static inline void mmc_register_pm_notifier(struct mmc_host *host) { }
-static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
-#endif
-
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq);
bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
-int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
- unsigned int arg);
-int mmc_can_erase(struct mmc_card *card);
-int mmc_can_trim(struct mmc_card *card);
-int mmc_can_discard(struct mmc_card *card);
-int mmc_can_sanitize(struct mmc_card *card);
-int mmc_can_secure_erase_trim(struct mmc_card *card);
-int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
- unsigned int nr);
+int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq);
+
+int mmc_erase(struct mmc_card *card, sector_t from, unsigned int nr, unsigned int arg);
+bool mmc_card_can_erase(struct mmc_card *card);
+bool mmc_card_can_trim(struct mmc_card *card);
+bool mmc_card_can_discard(struct mmc_card *card);
+bool mmc_card_can_sanitize(struct mmc_card *card);
+bool mmc_card_can_secure_erase_trim(struct mmc_card *card);
+bool mmc_card_can_cmd23(struct mmc_card *card);
+int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr);
unsigned int mmc_calc_max_discard(struct mmc_card *card);
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
-int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
- bool is_rel_write);
-int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
+int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
+ atomic_t *abort);
void mmc_release_host(struct mmc_host *host);
-void mmc_get_card(struct mmc_card *card);
-void mmc_put_card(struct mmc_card *card);
+void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx);
+void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx);
+
+int mmc_card_alternative_gpt_sector(struct mmc_card *card, sector_t *sector);
/**
* mmc_claim_host - exclusively claim a host
@@ -135,7 +150,68 @@ void mmc_put_card(struct mmc_card *card);
*/
static inline void mmc_claim_host(struct mmc_host *host)
{
- __mmc_claim_host(host, NULL);
+ __mmc_claim_host(host, NULL, NULL);
+}
+
+int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq);
+void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq);
+int mmc_cqe_recovery(struct mmc_host *host);
+
+/**
+ * mmc_pre_req - Prepare for a new request
+ * @host: MMC host to prepare command
+ * @mrq: MMC request to prepare for
+ *
+ * mmc_pre_req() is called in prior to mmc_start_req() to let
+ * host prepare for the new request. Preparation of a request may be
+ * performed while another request is running on the host.
+ */
+static inline void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ if (host->ops->pre_req)
+ host->ops->pre_req(host, mrq);
+}
+
+/**
+ * mmc_post_req - Post process a completed request
+ * @host: MMC host to post process command
+ * @mrq: MMC request to post process for
+ * @err: Error, if non zero, clean up any resources made in pre_req
+ *
+ * Let the host post process a completed request. Post processing of
+ * a request may be performed while another request is running.
+ */
+static inline void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
+ int err)
+{
+ if (host->ops->post_req)
+ host->ops->post_req(host, mrq, err);
+}
+
+static inline bool mmc_cache_enabled(struct mmc_host *host)
+{
+ if (host->bus_ops->cache_enabled)
+ return host->bus_ops->cache_enabled(host);
+
+ return false;
+}
+
+static inline int mmc_flush_cache(struct mmc_host *host)
+{
+ if (host->bus_ops->flush_cache)
+ return host->bus_ops->flush_cache(host);
+
+ return 0;
+}
+
+static inline unsigned int mmc_sector_div(sector_t dividend, u32 divisor)
+{
+ return div_u64(dividend, divisor);
+}
+
+static inline unsigned int mmc_sector_mod(sector_t dividend, u32 divisor)
+{
+ return sector_div(dividend, divisor);
}
#endif
diff --git a/drivers/mmc/core/crypto.c b/drivers/mmc/core/crypto.c
new file mode 100644
index 000000000000..fec4fbf16a5b
--- /dev/null
+++ b/drivers/mmc/core/crypto.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MMC crypto engine (inline encryption) support
+ *
+ * Copyright 2020 Google LLC
+ */
+
+#include <linux/blk-crypto.h>
+#include <linux/mmc/host.h>
+
+#include "core.h"
+#include "crypto.h"
+#include "queue.h"
+
+void mmc_crypto_set_initial_state(struct mmc_host *host)
+{
+ /* Reset might clear all keys, so reprogram all the keys. */
+ if (host->caps2 & MMC_CAP2_CRYPTO)
+ blk_crypto_reprogram_all_keys(&host->crypto_profile);
+}
+
+void mmc_crypto_setup_queue(struct request_queue *q, struct mmc_host *host)
+{
+ if (host->caps2 & MMC_CAP2_CRYPTO)
+ blk_crypto_register(&host->crypto_profile, q);
+}
+EXPORT_SYMBOL_GPL(mmc_crypto_setup_queue);
+
+void mmc_crypto_prepare_req(struct mmc_queue_req *mqrq)
+{
+ struct request *req = mmc_queue_req_to_req(mqrq);
+ struct mmc_request *mrq = &mqrq->brq.mrq;
+ struct blk_crypto_keyslot *keyslot;
+
+ if (!req->crypt_ctx)
+ return;
+
+ mrq->crypto_ctx = req->crypt_ctx;
+
+ keyslot = req->crypt_keyslot;
+ if (keyslot)
+ mrq->crypto_key_slot = blk_crypto_keyslot_index(keyslot);
+}
+EXPORT_SYMBOL_GPL(mmc_crypto_prepare_req);
diff --git a/drivers/mmc/core/crypto.h b/drivers/mmc/core/crypto.h
new file mode 100644
index 000000000000..fbe9a520bf90
--- /dev/null
+++ b/drivers/mmc/core/crypto.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * MMC crypto engine (inline encryption) support
+ *
+ * Copyright 2020 Google LLC
+ */
+
+#ifndef _MMC_CORE_CRYPTO_H
+#define _MMC_CORE_CRYPTO_H
+
+struct mmc_host;
+struct mmc_queue_req;
+struct request_queue;
+
+#ifdef CONFIG_MMC_CRYPTO
+
+void mmc_crypto_set_initial_state(struct mmc_host *host);
+
+void mmc_crypto_setup_queue(struct request_queue *q, struct mmc_host *host);
+
+void mmc_crypto_prepare_req(struct mmc_queue_req *mqrq);
+
+#else /* CONFIG_MMC_CRYPTO */
+
+static inline void mmc_crypto_set_initial_state(struct mmc_host *host)
+{
+}
+
+static inline void mmc_crypto_setup_queue(struct request_queue *q,
+ struct mmc_host *host)
+{
+}
+
+static inline void mmc_crypto_prepare_req(struct mmc_queue_req *mqrq)
+{
+}
+
+#endif /* !CONFIG_MMC_CRYPTO */
+
+#endif /* _MMC_CORE_CRYPTO_H */
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index a1fba5732d66..91ea00a0f61d 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Debugfs support for hosts and cards
*
* Copyright (C) 2008 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/moduleparam.h>
#include <linux/export.h>
@@ -15,9 +12,12 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/fault-inject.h>
+#include <linux/time.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
#include "core.h"
#include "card.h"
@@ -29,6 +29,7 @@
static DECLARE_FAULT_ATTR(fail_default_attr);
static char *fail_request;
module_param(fail_request, charp, 0);
+MODULE_PARM_DESC(fail_request, "default fault injection attributes");
#endif /* CONFIG_FAIL_MMC_REQUEST */
@@ -196,18 +197,7 @@ static int mmc_ios_show(struct seq_file *s, void *data)
return 0;
}
-
-static int mmc_ios_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mmc_ios_show, inode->i_private);
-}
-
-static const struct file_operations mmc_ios_fops = {
- .open = mmc_ios_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mmc_ios);
static int mmc_clock_opt_get(void *data, u64 *val)
{
@@ -233,132 +223,165 @@ static int mmc_clock_opt_set(void *data, u64 val)
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
+DEFINE_DEBUGFS_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
"%llu\n");
-void mmc_add_host_debugfs(struct mmc_host *host)
+static int mmc_err_state_get(void *data, u64 *val)
{
- struct dentry *root;
+ struct mmc_host *host = data;
+ int i;
- root = debugfs_create_dir(mmc_hostname(host), NULL);
- if (IS_ERR(root))
- /* Don't complain -- debugfs just isn't enabled */
- return;
- if (!root)
- /* Complain -- debugfs is enabled, but it failed to
- * create the directory. */
- goto err_root;
+ if (!host)
+ return -EINVAL;
- host->debugfs_root = root;
+ *val = 0;
+ for (i = 0; i < MMC_ERR_MAX; i++) {
+ if (host->err_stats[i]) {
+ *val = 1;
+ break;
+ }
+ }
- if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
- goto err_node;
+ return 0;
+}
- if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
- &mmc_clock_fops))
- goto err_node;
+DEFINE_DEBUGFS_ATTRIBUTE(mmc_err_state, mmc_err_state_get, NULL, "%llu\n");
-#ifdef CONFIG_FAIL_MMC_REQUEST
- if (fail_request)
- setup_fault_attr(&fail_default_attr, fail_request);
- host->fail_mmc_request = fail_default_attr;
- if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
- root,
- &host->fail_mmc_request)))
- goto err_node;
-#endif
- return;
+static int mmc_err_stats_show(struct seq_file *file, void *data)
+{
+ struct mmc_host *host = file->private;
+ const char *desc[MMC_ERR_MAX] = {
+ [MMC_ERR_CMD_TIMEOUT] = "Command Timeout Occurred",
+ [MMC_ERR_CMD_CRC] = "Command CRC Errors Occurred",
+ [MMC_ERR_DAT_TIMEOUT] = "Data Timeout Occurred",
+ [MMC_ERR_DAT_CRC] = "Data CRC Errors Occurred",
+ [MMC_ERR_AUTO_CMD] = "Auto-Cmd Error Occurred",
+ [MMC_ERR_ADMA] = "ADMA Error Occurred",
+ [MMC_ERR_TUNING] = "Tuning Error Occurred",
+ [MMC_ERR_CMDQ_RED] = "CMDQ RED Errors",
+ [MMC_ERR_CMDQ_GCE] = "CMDQ GCE Errors",
+ [MMC_ERR_CMDQ_ICCE] = "CMDQ ICCE Errors",
+ [MMC_ERR_REQ_TIMEOUT] = "Request Timedout",
+ [MMC_ERR_CMDQ_REQ_TIMEOUT] = "CMDQ Request Timedout",
+ [MMC_ERR_ICE_CFG] = "ICE Config Errors",
+ [MMC_ERR_CTRL_TIMEOUT] = "Controller Timedout errors",
+ [MMC_ERR_UNEXPECTED_IRQ] = "Unexpected IRQ errors",
+ };
+ int i;
+
+ for (i = 0; i < MMC_ERR_MAX; i++) {
+ if (desc[i])
+ seq_printf(file, "# %s:\t %d\n",
+ desc[i], host->err_stats[i]);
+ }
-err_node:
- debugfs_remove_recursive(root);
- host->debugfs_root = NULL;
-err_root:
- dev_err(&host->class_dev, "failed to initialize debugfs\n");
+ return 0;
}
-void mmc_remove_host_debugfs(struct mmc_host *host)
+static int mmc_err_stats_open(struct inode *inode, struct file *file)
{
- debugfs_remove_recursive(host->debugfs_root);
+ return single_open(file, mmc_err_stats_show, inode->i_private);
}
-static int mmc_dbg_card_status_get(void *data, u64 *val)
+static ssize_t mmc_err_stats_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
{
- struct mmc_card *card = data;
- u32 status;
- int ret;
+ struct mmc_host *host = filp->f_mapping->host->i_private;
- mmc_get_card(card);
+ pr_debug("%s: Resetting MMC error statistics\n", __func__);
+ memset(host->err_stats, 0, sizeof(host->err_stats));
- ret = mmc_send_status(data, &status);
- if (!ret)
- *val = status;
+ return cnt;
+}
- mmc_put_card(card);
+static const struct file_operations mmc_err_stats_fops = {
+ .open = mmc_err_stats_open,
+ .read = seq_read,
+ .write = mmc_err_stats_write,
+ .release = single_release,
+};
- return ret;
+static int mmc_caps_get(void *data, u64 *val)
+{
+ *val = *(u32 *)data;
+ return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
- NULL, "%08llx\n");
-#define EXT_CSD_STR_LEN 1025
-
-static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
+static int mmc_caps_set(void *data, u64 val)
{
- struct mmc_card *card = inode->i_private;
- char *buf;
- ssize_t n = 0;
- u8 *ext_csd;
- int err, i;
-
- buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- mmc_get_card(card);
- err = mmc_get_ext_csd(card, &ext_csd);
- mmc_put_card(card);
- if (err)
- goto out_free;
-
- for (i = 0; i < 512; i++)
- n += sprintf(buf + n, "%02x", ext_csd[i]);
- n += sprintf(buf + n, "\n");
-
- if (n != EXT_CSD_STR_LEN) {
- err = -EINVAL;
- goto out_free;
- }
+ u32 *caps = data;
+ u32 diff = *caps ^ val;
+ u32 allowed = MMC_CAP_AGGRESSIVE_PM |
+ MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_MMC_HIGHSPEED |
+ MMC_CAP_UHS |
+ MMC_CAP_DDR |
+ MMC_CAP_4_BIT_DATA |
+ MMC_CAP_8_BIT_DATA |
+ MMC_CAP_CMD23;
+
+ if (diff & ~allowed)
+ return -EINVAL;
- filp->private_data = buf;
- kfree(ext_csd);
- return 0;
+ *caps = val;
-out_free:
- kfree(buf);
- return err;
+ return 0;
}
-static ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
+static int mmc_caps2_set(void *data, u64 val)
{
- char *buf = filp->private_data;
+ u32 allowed = MMC_CAP2_HSX00_1_8V |
+ MMC_CAP2_HSX00_1_2V |
+ MMC_CAP2_CQE |
+ MMC_CAP2_CQE_DCMD;
+ u32 *caps = data;
+ u32 diff = *caps ^ val;
+
+ if (diff & ~allowed)
+ return -EINVAL;
+
+ *caps = val;
- return simple_read_from_buffer(ubuf, cnt, ppos,
- buf, EXT_CSD_STR_LEN);
+ return 0;
}
-static int mmc_ext_csd_release(struct inode *inode, struct file *file)
+DEFINE_DEBUGFS_ATTRIBUTE(mmc_caps_fops, mmc_caps_get, mmc_caps_set,
+ "0x%08llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(mmc_caps2_fops, mmc_caps_get, mmc_caps2_set,
+ "0x%08llx\n");
+
+void mmc_add_host_debugfs(struct mmc_host *host)
{
- kfree(file->private_data);
- return 0;
+ struct dentry *root;
+
+ root = debugfs_create_dir(mmc_hostname(host), NULL);
+ host->debugfs_root = root;
+
+ debugfs_create_file("ios", 0400, root, host, &mmc_ios_fops);
+ debugfs_create_file("caps", 0600, root, &host->caps, &mmc_caps_fops);
+ debugfs_create_file("caps2", 0600, root, &host->caps2,
+ &mmc_caps2_fops);
+ debugfs_create_file_unsafe("clock", 0600, root, host,
+ &mmc_clock_fops);
+
+ debugfs_create_file_unsafe("err_state", 0600, root, host,
+ &mmc_err_state);
+ debugfs_create_file("err_stats", 0600, root, host,
+ &mmc_err_stats_fops);
+
+#ifdef CONFIG_FAIL_MMC_REQUEST
+ if (fail_request)
+ setup_fault_attr(&fail_default_attr, fail_request);
+ host->fail_mmc_request = fail_default_attr;
+ fault_create_debugfs_attr("fail_mmc_request", root,
+ &host->fail_mmc_request);
+#endif
}
-static const struct file_operations mmc_dbg_ext_csd_fops = {
- .open = mmc_ext_csd_open,
- .read = mmc_ext_csd_read,
- .release = mmc_ext_csd_release,
- .llseek = default_llseek,
-};
+void mmc_remove_host_debugfs(struct mmc_host *host)
+{
+ debugfs_remove_recursive(host->debugfs_root);
+}
void mmc_add_card_debugfs(struct mmc_card *card)
{
@@ -369,38 +392,14 @@ void mmc_add_card_debugfs(struct mmc_card *card)
return;
root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
- if (IS_ERR(root))
- /* Don't complain -- debugfs just isn't enabled */
- return;
- if (!root)
- /* Complain -- debugfs is enabled, but it failed to
- * create the directory. */
- goto err;
-
card->debugfs_root = root;
- if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
- goto err;
-
- if (mmc_card_mmc(card) || mmc_card_sd(card))
- if (!debugfs_create_file("status", S_IRUSR, root, card,
- &mmc_dbg_card_status_fops))
- goto err;
-
- if (mmc_card_mmc(card))
- if (!debugfs_create_file("ext_csd", S_IRUSR, root, card,
- &mmc_dbg_ext_csd_fops))
- goto err;
-
- return;
-
-err:
- debugfs_remove_recursive(root);
- card->debugfs_root = NULL;
- dev_err(&card->dev, "failed to initialize debugfs\n");
+ debugfs_create_x32("state", 0400, root, &card->state);
+ debugfs_create_x32("quirks", 0400, root, &card->quirks);
}
void mmc_remove_card_debugfs(struct mmc_card *card)
{
debugfs_remove_recursive(card->debugfs_root);
+ card->debugfs_root = NULL;
}
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 1503412f826c..88c95dbfd9cf 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/host.c
*
@@ -5,10 +6,6 @@
* Copyright (C) 2007-2008 Pierre Ossman
* Copyright (C) 2010 Linus Walleij
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* MMC host class device management
*/
@@ -16,7 +13,6 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/pagemap.h>
#include <linux/export.h>
#include <linux/leds.h>
@@ -27,6 +23,7 @@
#include <linux/mmc/slot-gpio.h>
#include "core.h"
+#include "crypto.h"
#include "host.h"
#include "slot-gpio.h"
#include "pwrseq.h"
@@ -36,16 +33,64 @@
static DEFINE_IDA(mmc_host_ida);
+#ifdef CONFIG_PM_SLEEP
+static int mmc_host_class_prepare(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+ /*
+ * It's safe to access the bus_ops pointer, as both userspace and the
+ * workqueue for detecting cards are frozen at this point.
+ */
+ if (!host->bus_ops)
+ return 0;
+
+ /* Validate conditions for system suspend. */
+ if (host->bus_ops->pre_suspend)
+ return host->bus_ops->pre_suspend(host);
+
+ return 0;
+}
+
+static void mmc_host_class_complete(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+ _mmc_detect_change(host, 0, false);
+}
+
+static const struct dev_pm_ops mmc_host_class_dev_pm_ops = {
+ .prepare = mmc_host_class_prepare,
+ .complete = mmc_host_class_complete,
+};
+
+#define MMC_HOST_CLASS_DEV_PM_OPS (&mmc_host_class_dev_pm_ops)
+#else
+#define MMC_HOST_CLASS_DEV_PM_OPS NULL
+#endif
+
static void mmc_host_classdev_release(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
- ida_simple_remove(&mmc_host_ida, host->index);
+ wakeup_source_unregister(host->ws);
+ if (of_alias_get_id(host->parent->of_node, "mmc") < 0)
+ ida_free(&mmc_host_ida, host->index);
kfree(host);
}
-static struct class mmc_host_class = {
+static int mmc_host_classdev_shutdown(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+ __mmc_stop_host(host);
+ return 0;
+}
+
+static const struct class mmc_host_class = {
.name = "mmc_host",
.dev_release = mmc_host_classdev_release,
+ .shutdown_pre = mmc_host_classdev_shutdown,
+ .pm = MMC_HOST_CLASS_DEV_PM_OPS,
};
int mmc_register_host_class(void)
@@ -58,6 +103,10 @@ void mmc_unregister_host_class(void)
class_unregister(&mmc_host_class);
}
+/**
+ * mmc_retune_enable() - enter a transfer mode that requires retuning
+ * @host: host which should retune now
+ */
void mmc_retune_enable(struct mmc_host *host)
{
host->can_retune = 1;
@@ -68,13 +117,12 @@ void mmc_retune_enable(struct mmc_host *host)
/*
* Pause re-tuning for a small set of operations. The pause begins after the
- * next command and after first doing re-tuning.
+ * next command.
*/
void mmc_retune_pause(struct mmc_host *host)
{
if (!host->retune_paused) {
host->retune_paused = 1;
- mmc_retune_needed(host);
mmc_retune_hold(host);
}
}
@@ -89,18 +137,23 @@ void mmc_retune_unpause(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_retune_unpause);
+/**
+ * mmc_retune_disable() - exit a transfer mode that requires retuning
+ * @host: host which should not retune anymore
+ *
+ * It is not meant for temporarily preventing retuning!
+ */
void mmc_retune_disable(struct mmc_host *host)
{
mmc_retune_unpause(host);
host->can_retune = 0;
- del_timer_sync(&host->retune_timer);
- host->retune_now = 0;
- host->need_retune = 0;
+ timer_delete_sync(&host->retune_timer);
+ mmc_retune_clear(host);
}
void mmc_retune_timer_stop(struct mmc_host *host)
{
- del_timer_sync(&host->retune_timer);
+ timer_delete_sync(&host->retune_timer);
}
EXPORT_SYMBOL(mmc_retune_timer_stop);
@@ -118,6 +171,7 @@ void mmc_retune_release(struct mmc_host *host)
else
WARN_ON(1);
}
+EXPORT_SYMBOL(mmc_retune_release);
int mmc_retune(struct mmc_host *host)
{
@@ -142,9 +196,6 @@ int mmc_retune(struct mmc_host *host)
goto out;
return_to_hs400 = true;
-
- if (host->ops->prepare_hs400_tuning)
- host->ops->prepare_hs400_tuning(host, &host->ios);
}
err = mmc_execute_tuning(host->card);
@@ -159,29 +210,69 @@ out:
return err;
}
-static void mmc_retune_timer(unsigned long data)
+static void mmc_retune_timer(struct timer_list *t)
{
- struct mmc_host *host = (struct mmc_host *)data;
+ struct mmc_host *host = timer_container_of(host, t, retune_timer);
mmc_retune_needed(host);
}
+static void mmc_of_parse_timing_phase(struct device *dev, const char *prop,
+ struct mmc_clk_phase *phase)
+{
+ int degrees[2] = {0};
+ int rc;
+
+ rc = device_property_read_u32_array(dev, prop, degrees, 2);
+ phase->valid = !rc;
+ if (phase->valid) {
+ phase->in_deg = degrees[0];
+ phase->out_deg = degrees[1];
+ }
+}
+
+void
+mmc_of_parse_clk_phase(struct device *dev, struct mmc_clk_phase_map *map)
+{
+ mmc_of_parse_timing_phase(dev, "clk-phase-legacy",
+ &map->phase[MMC_TIMING_LEGACY]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-mmc-hs",
+ &map->phase[MMC_TIMING_MMC_HS]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-sd-hs",
+ &map->phase[MMC_TIMING_SD_HS]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-uhs-sdr12",
+ &map->phase[MMC_TIMING_UHS_SDR12]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-uhs-sdr25",
+ &map->phase[MMC_TIMING_UHS_SDR25]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-uhs-sdr50",
+ &map->phase[MMC_TIMING_UHS_SDR50]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-uhs-sdr104",
+ &map->phase[MMC_TIMING_UHS_SDR104]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-uhs-ddr50",
+ &map->phase[MMC_TIMING_UHS_DDR50]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-mmc-ddr52",
+ &map->phase[MMC_TIMING_MMC_DDR52]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-mmc-hs200",
+ &map->phase[MMC_TIMING_MMC_HS200]);
+ mmc_of_parse_timing_phase(dev, "clk-phase-mmc-hs400",
+ &map->phase[MMC_TIMING_MMC_HS400]);
+}
+EXPORT_SYMBOL(mmc_of_parse_clk_phase);
+
/**
- * mmc_of_parse() - parse host's device-tree node
- * @host: host whose node should be parsed.
+ * mmc_of_parse() - parse host's device properties
+ * @host: host whose properties should be parsed.
*
* To keep the rest of the MMC subsystem unaware of whether DT has been
- * used to to instantiate and configure this host instance or not, we
+ * used to instantiate and configure this host instance or not, we
* parse the properties and set respective generic mmc-host flags and
* parameters.
*/
int mmc_of_parse(struct mmc_host *host)
{
struct device *dev = host->parent;
- u32 bus_width;
+ u32 bus_width, drv_type, cd_debounce_delay_ms;
int ret;
- bool cd_cap_invert, cd_gpio_invert = false;
- bool ro_cap_invert, ro_gpio_invert = false;
if (!dev || !dev_fwnode(dev))
return 0;
@@ -196,7 +287,7 @@ int mmc_of_parse(struct mmc_host *host)
switch (bus_width) {
case 8:
host->caps |= MMC_CAP_8_BIT_DATA;
- /* Hosts capable of 8-bit transfers can also do 4 bits */
+ fallthrough; /* Hosts capable of 8-bit can also do 4 bits */
case 4:
host->caps |= MMC_CAP_4_BIT_DATA;
break;
@@ -211,6 +302,8 @@ int mmc_of_parse(struct mmc_host *host)
/* f_max is obtained from the optional "max-frequency" property */
device_property_read_u32(dev, "max-frequency", &host->f_max);
+ device_property_read_u32(dev, "max-sd-hs-hz", &host->max_sd_hs_hz);
+
/*
* Configure CD and WP pins. They are both by default active low to
* match the SDHCI spec. If GPIOs are provided for CD and / or WP, the
@@ -224,40 +317,34 @@ int mmc_of_parse(struct mmc_host *host)
*/
/* Parse Card Detection */
+
if (device_property_read_bool(dev, "non-removable")) {
host->caps |= MMC_CAP_NONREMOVABLE;
} else {
- cd_cap_invert = device_property_read_bool(dev, "cd-inverted");
+ if (device_property_read_bool(dev, "cd-inverted"))
+ host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
+
+ if (device_property_read_u32(dev, "cd-debounce-delay-ms",
+ &cd_debounce_delay_ms))
+ cd_debounce_delay_ms = 200;
if (device_property_read_bool(dev, "broken-cd"))
host->caps |= MMC_CAP_NEEDS_POLL;
- ret = mmc_gpiod_request_cd(host, "cd", 0, true,
- 0, &cd_gpio_invert);
+ ret = mmc_gpiod_request_cd(host, "cd", 0, false,
+ cd_debounce_delay_ms * 1000);
if (!ret)
dev_info(host->parent, "Got CD GPIO\n");
else if (ret != -ENOENT && ret != -ENOSYS)
return ret;
-
- /*
- * There are two ways to flag that the CD line is inverted:
- * through the cd-inverted flag and by the GPIO line itself
- * being inverted from the GPIO subsystem. This is a leftover
- * from the times when the GPIO subsystem did not make it
- * possible to flag a line as inverted.
- *
- * If the capability on the host AND the GPIO line are
- * both inverted, the end result is that the CD line is
- * not inverted.
- */
- if (cd_cap_invert ^ cd_gpio_invert)
- host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
}
/* Parse Write Protection */
- ro_cap_invert = device_property_read_bool(dev, "wp-inverted");
- ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert);
+ if (device_property_read_bool(dev, "wp-inverted"))
+ host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+
+ ret = mmc_gpiod_request_ro(host, "wp", 0, 0);
if (!ret)
dev_info(host->parent, "Got WP GPIO\n");
else if (ret != -ENOENT && ret != -ENOSYS)
@@ -266,10 +353,6 @@ int mmc_of_parse(struct mmc_host *host)
if (device_property_read_bool(dev, "disable-wp"))
host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
- /* See the comment on CD inversion above */
- if (ro_cap_invert ^ ro_gpio_invert)
- host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
-
if (device_property_read_bool(dev, "cap-sd-highspeed"))
host->caps |= MMC_CAP_SD_HIGHSPEED;
if (device_property_read_bool(dev, "cap-mmc-highspeed"))
@@ -292,6 +375,8 @@ int mmc_of_parse(struct mmc_host *host)
host->caps |= MMC_CAP_SDIO_IRQ;
if (device_property_read_bool(dev, "full-pwr-cycle"))
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
+ if (device_property_read_bool(dev, "full-pwr-cycle-in-suspend"))
+ host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND;
if (device_property_read_bool(dev, "keep-power-in-suspend"))
host->pm_caps |= MMC_PM_KEEP_POWER;
if (device_property_read_bool(dev, "wakeup-source") ||
@@ -319,6 +404,18 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 |= MMC_CAP2_NO_SD;
if (device_property_read_bool(dev, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC;
+ if (device_property_read_bool(dev, "no-mmc-hs400"))
+ host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
+ MMC_CAP2_HS400_ES);
+
+ /* Must be after "non-removable" check */
+ if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
+ if (host->caps & MMC_CAP_NONREMOVABLE)
+ host->fixed_drv_type = drv_type;
+ else
+ dev_err(host->parent,
+ "can't use fixed driver type, media is removable\n");
+ }
host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr);
if (host->dsr_req && (host->dsr & ~0xffff)) {
@@ -328,12 +425,91 @@ int mmc_of_parse(struct mmc_host *host)
host->dsr_req = 0;
}
+ device_property_read_u32(dev, "post-power-on-delay-ms",
+ &host->ios.power_delay_ms);
+
return mmc_pwrseq_alloc(host);
}
EXPORT_SYMBOL(mmc_of_parse);
/**
+ * mmc_of_parse_voltage - return mask of supported voltages
+ * @host: host whose properties should be parsed.
+ * @mask: mask of voltages available for MMC/SD/SDIO
+ *
+ * Parse the "voltage-ranges" property, returning zero if it is not
+ * found, negative errno if the voltage-range specification is invalid,
+ * or one if the voltage-range is specified and successfully parsed.
+ */
+int mmc_of_parse_voltage(struct mmc_host *host, u32 *mask)
+{
+ const char *prop = "voltage-ranges";
+ struct device *dev = host->parent;
+ u32 *voltage_ranges;
+ int num_ranges, i;
+ int ret;
+
+ if (!device_property_present(dev, prop)) {
+ dev_dbg(dev, "%s unspecified\n", prop);
+ return 0;
+ }
+
+ ret = device_property_count_u32(dev, prop);
+ if (ret < 0)
+ return ret;
+
+ num_ranges = ret / 2;
+ if (!num_ranges) {
+ dev_err(dev, "%s empty\n", prop);
+ return -EINVAL;
+ }
+
+ voltage_ranges = kcalloc(2 * num_ranges, sizeof(*voltage_ranges), GFP_KERNEL);
+ if (!voltage_ranges)
+ return -ENOMEM;
+
+ ret = device_property_read_u32_array(dev, prop, voltage_ranges, 2 * num_ranges);
+ if (ret) {
+ kfree(voltage_ranges);
+ return ret;
+ }
+
+ for (i = 0; i < num_ranges; i++) {
+ const int j = i * 2;
+ u32 ocr_mask;
+
+ ocr_mask = mmc_vddrange_to_ocrmask(voltage_ranges[j + 0],
+ voltage_ranges[j + 1]);
+ if (!ocr_mask) {
+ dev_err(dev, "range #%d in %s is invalid\n", i, prop);
+ kfree(voltage_ranges);
+ return -EINVAL;
+ }
+ *mask |= ocr_mask;
+ }
+
+ kfree(voltage_ranges);
+
+ return 1;
+}
+EXPORT_SYMBOL(mmc_of_parse_voltage);
+
+/**
+ * mmc_first_nonreserved_index() - get the first index that is not reserved
+ */
+static int mmc_first_nonreserved_index(void)
+{
+ int max;
+
+ max = of_alias_get_highest_id("mmc");
+ if (max < 0)
+ return 0;
+
+ return max + 1;
+}
+
+/**
* mmc_alloc_host - initialise the per-host structure.
* @extra: sizeof private data structure
* @dev: pointer to host device model structure
@@ -342,8 +518,9 @@ EXPORT_SYMBOL(mmc_of_parse);
*/
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
- int err;
+ int index;
struct mmc_host *host;
+ int alias_id, min_idx, max_idx;
host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
if (!host)
@@ -352,15 +529,25 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
/* scanning will be enabled when we're ready */
host->rescan_disable = 1;
- err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL);
- if (err < 0) {
- kfree(host);
- return NULL;
+ alias_id = of_alias_get_id(dev->of_node, "mmc");
+ if (alias_id >= 0) {
+ index = alias_id;
+ } else {
+ min_idx = mmc_first_nonreserved_index();
+ max_idx = 0;
+
+ index = ida_alloc_range(&mmc_host_ida, min_idx, max_idx - 1,
+ GFP_KERNEL);
+ if (index < 0) {
+ kfree(host);
+ return NULL;
+ }
}
- host->index = err;
+ host->index = index;
dev_set_name(&host->class_dev, "mmc%d", host->index);
+ host->ws = wakeup_source_register(NULL, dev_name(&host->class_dev));
host->parent = dev;
host->class_dev.parent = dev;
@@ -370,16 +557,16 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
if (mmc_gpio_alloc(host)) {
put_device(&host->class_dev);
- ida_simple_remove(&mmc_host_ida, host->index);
- kfree(host);
return NULL;
}
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
- INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work);
- setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);
+ INIT_WORK(&host->sdio_irq_work, sdio_irq_work);
+ timer_setup(&host->retune_timer, mmc_retune_timer, 0);
+
+ INIT_WORK(&host->supply.uv_work, mmc_undervoltage_workfn);
/*
* By default, hosts do not support SGIO or large requests.
@@ -392,11 +579,60 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->max_blk_size = 512;
host->max_blk_count = PAGE_SIZE / 512;
+ host->fixed_drv_type = -EINVAL;
+ host->ios.power_delay_ms = 10;
+ host->ios.power_mode = MMC_POWER_UNDEFINED;
+
return host;
}
EXPORT_SYMBOL(mmc_alloc_host);
+static void devm_mmc_host_release(struct device *dev, void *res)
+{
+ mmc_free_host(*(struct mmc_host **)res);
+}
+
+struct mmc_host *devm_mmc_alloc_host(struct device *dev, int extra)
+{
+ struct mmc_host **dr, *host;
+
+ dr = devres_alloc(devm_mmc_host_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return NULL;
+
+ host = mmc_alloc_host(extra, dev);
+ if (!host) {
+ devres_free(dr);
+ return NULL;
+ }
+
+ *dr = host;
+ devres_add(dev, dr);
+
+ return host;
+}
+EXPORT_SYMBOL(devm_mmc_alloc_host);
+
+static int mmc_validate_host_caps(struct mmc_host *host)
+{
+ struct device *dev = host->parent;
+ u32 caps = host->caps, caps2 = host->caps2;
+
+ if (caps & MMC_CAP_SDIO_IRQ && !host->ops->enable_sdio_irq) {
+ dev_warn(dev, "missing ->enable_sdio_irq() ops\n");
+ return -EINVAL;
+ }
+
+ if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) &&
+ !(caps & MMC_CAP_8_BIT_DATA) && !(caps2 & MMC_CAP2_NO_MMC)) {
+ dev_warn(dev, "drop HS400 support since no 8-bit bus\n");
+ host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400;
+ }
+
+ return 0;
+}
+
/**
* mmc_add_host - initialise host hardware
* @host: mmc host
@@ -409,8 +645,9 @@ int mmc_add_host(struct mmc_host *host)
{
int err;
- WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
- !host->ops->enable_sdio_irq);
+ err = mmc_validate_host_caps(host);
+ if (err)
+ return err;
err = device_add(&host->class_dev);
if (err)
@@ -418,13 +655,9 @@ int mmc_add_host(struct mmc_host *host)
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
-#ifdef CONFIG_DEBUG_FS
mmc_add_host_debugfs(host);
-#endif
mmc_start_host(host);
- mmc_register_pm_notifier(host);
-
return 0;
}
@@ -440,12 +673,9 @@ EXPORT_SYMBOL(mmc_add_host);
*/
void mmc_remove_host(struct mmc_host *host)
{
- mmc_unregister_pm_notifier(host);
mmc_stop_host(host);
-#ifdef CONFIG_DEBUG_FS
mmc_remove_host_debugfs(host);
-#endif
device_del(&host->class_dev);
@@ -462,6 +692,7 @@ EXPORT_SYMBOL(mmc_remove_host);
*/
void mmc_free_host(struct mmc_host *host)
{
+ cancel_delayed_work_sync(&host->detect);
mmc_pwrseq_free(host);
put_device(&host->class_dev);
}
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index fb6a76a03833..5941d68ff989 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/mmc/core/host.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _MMC_CORE_HOST_H
#define _MMC_CORE_HOST_H
@@ -24,28 +21,46 @@ int mmc_retune(struct mmc_host *host);
void mmc_retune_pause(struct mmc_host *host);
void mmc_retune_unpause(struct mmc_host *host);
+static inline void mmc_retune_clear(struct mmc_host *host)
+{
+ host->retune_now = 0;
+ host->need_retune = 0;
+}
+
+static inline void mmc_retune_hold_now(struct mmc_host *host)
+{
+ host->retune_now = 0;
+ host->hold_retune += 1;
+}
+
static inline void mmc_retune_recheck(struct mmc_host *host)
{
if (host->hold_retune <= 1)
host->retune_now = 1;
}
-static inline int mmc_host_cmd23(struct mmc_host *host)
+static inline int mmc_host_can_cmd23(struct mmc_host *host)
{
return host->caps & MMC_CAP_CMD23;
}
-static inline int mmc_boot_partition_access(struct mmc_host *host)
+static inline bool mmc_host_can_done_complete(struct mmc_host *host)
+{
+ return host->caps & MMC_CAP_DONE_COMPLETE;
+}
+
+static inline int mmc_host_can_access_boot(struct mmc_host *host)
{
return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
}
-static inline int mmc_host_uhs(struct mmc_host *host)
+static inline int mmc_host_can_uhs(struct mmc_host *host)
{
return host->caps &
(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50);
+ MMC_CAP_UHS_DDR50) &&
+ host->caps & MMC_CAP_4_BIT_DATA;
}
static inline bool mmc_card_hs200(struct mmc_card *card)
@@ -68,6 +83,11 @@ static inline bool mmc_card_hs400es(struct mmc_card *card)
return card->host->ios.enhanced_strobe;
}
+static inline bool mmc_card_sd_express(struct mmc_host *host)
+{
+ return host->ios.timing == MMC_TIMING_SD_EXP ||
+ host->ios.timing == MMC_TIMING_SD_EXP_1_2V;
+}
#endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 4ffea14b7eb6..7c86efb1044a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1,20 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/mmc.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
* MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/string.h>
#include <linux/pm_runtime.h>
+#include <linux/random.h>
+#include <linux/sysfs.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@@ -30,6 +30,15 @@
#include "pwrseq.h"
#define DEFAULT_CMD6_TIMEOUT_MS 500
+#define MIN_CACHE_EN_TIMEOUT_MS 1600
+#define CACHE_FLUSH_TIMEOUT_MS 30000 /* 30s */
+
+enum mmc_poweroff_type {
+ MMC_POWEROFF_SUSPEND,
+ MMC_POWEROFF_SHUTDOWN,
+ MMC_POWEROFF_UNDERVOLTAGE,
+ MMC_POWEROFF_UNBIND,
+};
static const unsigned int tran_exp[] = {
10000, 100000, 1000000, 10000000,
@@ -41,29 +50,15 @@ static const unsigned char tran_mant[] = {
35, 40, 45, 50, 55, 60, 70, 80,
};
-static const unsigned int tacc_exp[] = {
+static const unsigned int taac_exp[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
-static const unsigned int tacc_mant[] = {
+static const unsigned int taac_mant[] = {
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
-#define UNSTUFF_BITS(resp,start,size) \
- ({ \
- const int __size = size; \
- const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
- const int __off = 3 - ((start) / 32); \
- const int __shft = (start) & 31; \
- u32 __res; \
- \
- __res = resp[__off] >> __shft; \
- if (__size + __shft > 32) \
- __res |= resp[__off-1] << ((32 - __shft) % 32); \
- __res & __mask; \
- })
-
/*
* Given the decoded CSD structure, decode the raw CID to our CID structure.
*/
@@ -72,42 +67,48 @@ static int mmc_decode_cid(struct mmc_card *card)
u32 *resp = card->raw_cid;
/*
+ * Add the raw card ID (cid) data to the entropy pool. It doesn't
+ * matter that not all of it is unique, it's just bonus entropy.
+ */
+ add_device_randomness(&card->raw_cid, sizeof(card->raw_cid));
+
+ /*
* The selection of the format here is based upon published
- * specs from sandisk and from what people have reported.
+ * specs from SanDisk and from what people have reported.
*/
switch (card->csd.mmca_vsn) {
case 0: /* MMC v1.0 - v1.2 */
case 1: /* MMC v1.4 */
- card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
- card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4);
- card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
+ card->cid.manfid = unstuff_bits(resp, 104, 24);
+ card->cid.prod_name[0] = unstuff_bits(resp, 96, 8);
+ card->cid.prod_name[1] = unstuff_bits(resp, 88, 8);
+ card->cid.prod_name[2] = unstuff_bits(resp, 80, 8);
+ card->cid.prod_name[3] = unstuff_bits(resp, 72, 8);
+ card->cid.prod_name[4] = unstuff_bits(resp, 64, 8);
+ card->cid.prod_name[5] = unstuff_bits(resp, 56, 8);
+ card->cid.prod_name[6] = unstuff_bits(resp, 48, 8);
+ card->cid.hwrev = unstuff_bits(resp, 44, 4);
+ card->cid.fwrev = unstuff_bits(resp, 40, 4);
+ card->cid.serial = unstuff_bits(resp, 16, 24);
+ card->cid.month = unstuff_bits(resp, 12, 4);
+ card->cid.year = unstuff_bits(resp, 8, 4) + 1997;
break;
case 2: /* MMC v2.0 - v2.2 */
case 3: /* MMC v3.1 - v3.3 */
case 4: /* MMC v4 */
- card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
- card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.prv = UNSTUFF_BITS(resp, 48, 8);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
+ card->cid.manfid = unstuff_bits(resp, 120, 8);
+ card->cid.oemid = unstuff_bits(resp, 104, 16);
+ card->cid.prod_name[0] = unstuff_bits(resp, 96, 8);
+ card->cid.prod_name[1] = unstuff_bits(resp, 88, 8);
+ card->cid.prod_name[2] = unstuff_bits(resp, 80, 8);
+ card->cid.prod_name[3] = unstuff_bits(resp, 72, 8);
+ card->cid.prod_name[4] = unstuff_bits(resp, 64, 8);
+ card->cid.prod_name[5] = unstuff_bits(resp, 56, 8);
+ card->cid.prv = unstuff_bits(resp, 48, 8);
+ card->cid.serial = unstuff_bits(resp, 16, 32);
+ card->cid.month = unstuff_bits(resp, 12, 4);
+ card->cid.year = unstuff_bits(resp, 8, 4) + 1997;
break;
default:
@@ -116,6 +117,9 @@ static int mmc_decode_cid(struct mmc_card *card)
return -EINVAL;
}
+ /* some product names include trailing whitespace */
+ strim(card->cid.prod_name);
+
return 0;
}
@@ -129,6 +133,17 @@ static void mmc_set_erase_size(struct mmc_card *card)
mmc_init_erase(card);
}
+
+static void mmc_set_wp_grp_size(struct mmc_card *card)
+{
+ if (card->ext_csd.erase_group_def & 1)
+ card->wp_grp_size = card->ext_csd.hc_erase_size *
+ card->ext_csd.raw_hc_erase_gap_size;
+ else
+ card->wp_grp_size = card->csd.erase_size *
+ (card->csd.wp_grp_size + 1);
+}
+
/*
* Given a 128-bit response, decode to our card CSD structure.
*/
@@ -143,42 +158,43 @@ static int mmc_decode_csd(struct mmc_card *card)
* v1.2 has extra information in bits 15, 11 and 10.
* We also support eMMC v4.4 & v4.41.
*/
- csd->structure = UNSTUFF_BITS(resp, 126, 2);
+ csd->structure = unstuff_bits(resp, 126, 2);
if (csd->structure == 0) {
pr_err("%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd->structure);
return -EINVAL;
}
- csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+ csd->mmca_vsn = unstuff_bits(resp, 122, 4);
+ m = unstuff_bits(resp, 115, 4);
+ e = unstuff_bits(resp, 112, 3);
+ csd->taac_ns = (taac_exp[e] * taac_mant[m] + 9) / 10;
+ csd->taac_clks = unstuff_bits(resp, 104, 8) * 100;
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
+ m = unstuff_bits(resp, 99, 4);
+ e = unstuff_bits(resp, 96, 3);
csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+ csd->cmdclass = unstuff_bits(resp, 84, 12);
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
+ e = unstuff_bits(resp, 47, 3);
+ m = unstuff_bits(resp, 62, 12);
csd->capacity = (1 + m) << (e + 2);
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ csd->read_blkbits = unstuff_bits(resp, 80, 4);
+ csd->read_partial = unstuff_bits(resp, 79, 1);
+ csd->write_misalign = unstuff_bits(resp, 78, 1);
+ csd->read_misalign = unstuff_bits(resp, 77, 1);
+ csd->dsr_imp = unstuff_bits(resp, 76, 1);
+ csd->r2w_factor = unstuff_bits(resp, 26, 3);
+ csd->write_blkbits = unstuff_bits(resp, 22, 4);
+ csd->write_partial = unstuff_bits(resp, 21, 1);
if (csd->write_blkbits >= 9) {
- a = UNSTUFF_BITS(resp, 42, 5);
- b = UNSTUFF_BITS(resp, 37, 5);
+ a = unstuff_bits(resp, 42, 5);
+ b = unstuff_bits(resp, 37, 5);
csd->erase_size = (a + 1) * (b + 1);
csd->erase_size <<= csd->write_blkbits - 9;
+ csd->wp_grp_size = unstuff_bits(resp, 32, 5);
}
return 0;
@@ -299,7 +315,7 @@ static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd)
}
}
-static void mmc_part_add(struct mmc_card *card, unsigned int size,
+static void mmc_part_add(struct mmc_card *card, u64 size,
unsigned int part_cfg, char *name, int idx, bool ro,
int area_type)
{
@@ -315,7 +331,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
{
int idx;
u8 hc_erase_grp_sz, hc_wp_grp_sz;
- unsigned int part_size;
+ u64 part_size;
/*
* General purpose partition feature support --
@@ -345,8 +361,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
(ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1]
<< 8) +
ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3];
- part_size *= (size_t)(hc_erase_grp_sz *
- hc_wp_grp_sz);
+ part_size *= (hc_erase_grp_sz * hc_wp_grp_sz);
mmc_part_add(card, part_size << 19,
EXT_CSD_PART_CONFIG_ACC_GP0 + idx,
"gp%d", idx, false,
@@ -364,7 +379,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
{
int err = 0, idx;
- unsigned int part_size;
+ u64 part_size;
struct device_node *np;
bool broken_hpi = false;
@@ -413,23 +428,20 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
- mmc_select_card_type(card);
card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
card->ext_csd.raw_erase_timeout_mult =
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
card->ext_csd.raw_hc_erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ card->ext_csd.raw_boot_mult =
+ ext_csd[EXT_CSD_BOOT_MULT];
if (card->ext_csd.rev >= 3) {
u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
/* EXT_CSD value is in units of 10ms, but we store in ms */
card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
- /* Some eMMC set the value too low so set a minimum */
- if (card->ext_csd.part_time &&
- card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME)
- card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME;
/* Sleep / awake timeout in 100ns units */
if (sa_shift > 0 && sa_shift <= 0x17)
@@ -448,7 +460,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
* There are two boot regions of equal size, defined in
* multiples of 128K.
*/
- if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) {
+ if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_host_can_access_boot(card->host)) {
for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) {
part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
mmc_part_add(card, part_size,
@@ -526,8 +538,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->cid.year += 16;
/* check whether the eMMC card supports BKOPS */
- if (!mmc_card_broken_hpi(card) &&
- ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
+ if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
card->ext_csd.bkops = 1;
card->ext_csd.man_bkops_en =
(ext_csd[EXT_CSD_BKOPS_EN] &
@@ -568,7 +579,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
* RPMB regions are defined in multiples of 128K.
*/
card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
- if (ext_csd[EXT_CSD_RPMB_MULT] && mmc_host_cmd23(card->host)) {
+ if (ext_csd[EXT_CSD_RPMB_MULT] && mmc_host_can_cmd23(card->host)) {
mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
EXT_CSD_PART_CONFIG_ACC_RPMB,
"rpmb", 0, false,
@@ -611,15 +622,21 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
} else {
card->ext_csd.data_tag_unit_size = 0;
}
-
- card->ext_csd.max_packed_writes =
- ext_csd[EXT_CSD_MAX_PACKED_WRITES];
- card->ext_csd.max_packed_reads =
- ext_csd[EXT_CSD_MAX_PACKED_READS];
} else {
card->ext_csd.data_sector_size = 512;
}
+ /*
+ * GENERIC_CMD6_TIME is to be used "unless a specific timeout is defined
+ * when accessing a specific field", so use it here if there is no
+ * PARTITION_SWITCH_TIME.
+ */
+ if (!card->ext_csd.part_time)
+ card->ext_csd.part_time = card->ext_csd.generic_cmd6_time;
+ /* Some eMMC set the value too low so set a minimum */
+ if (card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME)
+ card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME;
+
/* eMMC v5 or later */
if (card->ext_csd.rev >= 7) {
memcpy(card->ext_csd.fwrev, &ext_csd[EXT_CSD_FIRMWARE_VERSION],
@@ -651,6 +668,9 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
mmc_hostname(card->host),
card->ext_csd.cmdq_depth);
}
+ card->ext_csd.enhanced_rpmb_supported =
+ (card->ext_csd.rel_param &
+ EXT_CSD_WR_REL_PARAM_EN_RPMB_REL_WR);
}
out:
return err;
@@ -661,7 +681,7 @@ static int mmc_read_ext_csd(struct mmc_card *card)
u8 *ext_csd;
int err;
- if (!mmc_can_ext_csd(card))
+ if (!mmc_card_can_ext_csd(card))
return 0;
err = mmc_get_ext_csd(card, &ext_csd);
@@ -774,13 +794,15 @@ MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
+MMC_DEV_ATTR(wp_grp_size, "%u\n", card->wp_grp_size << 9);
MMC_DEV_ATTR(ffu_capable, "%d\n", card->ext_csd.ffu_capable);
MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv);
-MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info);
+MMC_DEV_ATTR(rev, "0x%x\n", card->ext_csd.rev);
+MMC_DEV_ATTR(pre_eol_info, "0x%02x\n", card->ext_csd.pre_eol_info);
MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n",
card->ext_csd.device_life_time_est_typ_a,
card->ext_csd.device_life_time_est_typ_b);
@@ -789,8 +811,11 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
+MMC_DEV_ATTR(enhanced_rpmb_supported, "%#x\n",
+ card->ext_csd.enhanced_rpmb_supported);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
-MMC_DEV_ATTR(ocr, "%08x\n", card->ocr);
+MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
+MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en);
static ssize_t mmc_fwrev_show(struct device *dev,
@@ -799,15 +824,14 @@ static ssize_t mmc_fwrev_show(struct device *dev,
{
struct mmc_card *card = mmc_dev_to_card(dev);
- if (card->ext_csd.rev < 7) {
- return sprintf(buf, "0x%x\n", card->cid.fwrev);
- } else {
- return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN,
- card->ext_csd.fwrev);
- }
+ if (card->ext_csd.rev < 7)
+ return sysfs_emit(buf, "0x%x\n", card->cid.fwrev);
+ else
+ return sysfs_emit(buf, "0x%*phN\n", MMC_FIRMWARE_LEN,
+ card->ext_csd.fwrev);
}
-static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL);
+static DEVICE_ATTR(fwrev, 0444, mmc_fwrev_show, NULL);
static ssize_t mmc_dsr_show(struct device *dev,
struct device_attribute *attr,
@@ -817,13 +841,13 @@ static ssize_t mmc_dsr_show(struct device *dev,
struct mmc_host *host = card->host;
if (card->csd.dsr_imp && host->dsr_req)
- return sprintf(buf, "0x%x\n", host->dsr);
+ return sysfs_emit(buf, "0x%x\n", host->dsr);
else
/* return default DSR value */
- return sprintf(buf, "0x%x\n", 0x404);
+ return sysfs_emit(buf, "0x%x\n", 0x404);
}
-static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
+static DEVICE_ATTR(dsr, 0444, mmc_dsr_show, NULL);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
@@ -831,6 +855,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_date.attr,
&dev_attr_erase_size.attr,
&dev_attr_preferred_erase_size.attr,
+ &dev_attr_wp_grp_size.attr,
&dev_attr_fwrev.attr,
&dev_attr_ffu_capable.attr,
&dev_attr_hwrev.attr,
@@ -838,21 +863,24 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_name.attr,
&dev_attr_oemid.attr,
&dev_attr_prv.attr,
+ &dev_attr_rev.attr,
&dev_attr_pre_eol_info.attr,
&dev_attr_life_time.attr,
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
&dev_attr_raw_rpmb_size_mult.attr,
+ &dev_attr_enhanced_rpmb_supported.attr,
&dev_attr_rel_sectors.attr,
&dev_attr_ocr.attr,
+ &dev_attr_rca.attr,
&dev_attr_dsr.attr,
&dev_attr_cmdq_en.attr,
NULL,
};
ATTRIBUTE_GROUPS(mmc_std);
-static struct device_type mmc_type = {
+static const struct device_type mmc_type = {
.groups = mmc_std_groups,
};
@@ -932,7 +960,7 @@ static int mmc_select_powerclass(struct mmc_card *card)
int err, ddr;
/* Power class selection is supported for versions >= 4.0 */
- if (!mmc_can_ext_csd(card))
+ if (!mmc_card_can_ext_csd(card))
return 0;
bus_width = host->ios.bus_width;
@@ -984,16 +1012,18 @@ static int mmc_select_bus_width(struct mmc_card *card)
static unsigned ext_csd_bits[] = {
EXT_CSD_BUS_WIDTH_8,
EXT_CSD_BUS_WIDTH_4,
+ EXT_CSD_BUS_WIDTH_1,
};
static unsigned bus_widths[] = {
MMC_BUS_WIDTH_8,
MMC_BUS_WIDTH_4,
+ MMC_BUS_WIDTH_1,
};
struct mmc_host *host = card->host;
unsigned idx, bus_width = 0;
int err = 0;
- if (!mmc_can_ext_csd(card) ||
+ if (!mmc_card_can_ext_csd(card) ||
!(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
return 0;
@@ -1055,7 +1085,7 @@ static int mmc_select_hs(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS,
- true, true, true);
+ true, true, MMC_CMD_RETRIES);
if (err)
pr_warn("%s: switch to high-speed failed, err:%d\n",
mmc_hostname(card->host), err);
@@ -1087,7 +1117,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
ext_csd_bits,
card->ext_csd.generic_cmd6_time,
MMC_TIMING_MMC_DDR52,
- true, true, true);
+ true, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to bus width %d ddr failed\n",
mmc_hostname(host), 1 << bus_width);
@@ -1155,24 +1185,31 @@ static int mmc_select_hs400(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, 0,
- true, false, true);
+ false, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
+ /* Prepare host to downgrade to HS timing */
+ if (host->ops->hs400_downgrade)
+ host->ops->hs400_downgrade(host);
+
/* Set host controller to HS timing */
- mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+ mmc_set_timing(host, MMC_TIMING_MMC_HS);
/* Reduce frequency to HS frequency */
max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr);
- err = mmc_switch_status(card);
+ err = mmc_switch_status(card, true);
if (err)
goto out_err;
+ if (host->ops->hs400_prepare_ddr)
+ host->ops->hs400_prepare_ddr(host);
+
/* Switch card to DDR */
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
@@ -1190,7 +1227,7 @@ static int mmc_select_hs400(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, 0,
- true, false, true);
+ false, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to hs400 failed, err:%d\n",
mmc_hostname(host), err);
@@ -1201,7 +1238,18 @@ static int mmc_select_hs400(struct mmc_card *card)
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
mmc_set_bus_speed(card);
- err = mmc_switch_status(card);
+ if (host->ops->execute_hs400_tuning) {
+ mmc_retune_disable(host);
+ err = host->ops->execute_hs400_tuning(host, card);
+ mmc_retune_enable(host);
+ if (err)
+ goto out_err;
+ }
+
+ if (host->ops->hs400_complete)
+ host->ops->hs400_complete(host);
+
+ err = mmc_switch_status(card, true);
if (err)
goto out_err;
@@ -1233,26 +1281,29 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
val, card->ext_csd.generic_cmd6_time, 0,
- true, false, true);
+ false, true, MMC_CMD_RETRIES);
if (err)
goto out_err;
+ if (host->ops->hs400_downgrade)
+ host->ops->hs400_downgrade(host);
+
mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
- err = mmc_switch_status(card);
+ err = mmc_switch_status(card, true);
if (err)
goto out_err;
/* Switch HS DDR to HS */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
- 0, true, false, true);
+ 0, false, true, MMC_CMD_RETRIES);
if (err)
goto out_err;
mmc_set_timing(host, MMC_TIMING_MMC_HS);
- err = mmc_switch_status(card);
+ err = mmc_switch_status(card, true);
if (err)
goto out_err;
@@ -1261,7 +1312,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
val, card->ext_csd.generic_cmd6_time, 0,
- true, false, true);
+ false, true, MMC_CMD_RETRIES);
if (err)
goto out_err;
@@ -1272,12 +1323,16 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
* failed. If there really is a problem, we would expect tuning will
* fail and the result ends up the same.
*/
- err = __mmc_switch_status(card, false);
+ err = mmc_switch_status(card, false);
if (err)
goto out_err;
mmc_set_bus_speed(card);
+ /* Prepare tuning for HS400 mode. */
+ if (host->ops->prepare_hs400_tuning)
+ host->ops->prepare_hs400_tuning(host, &host->ios);
+
return 0;
out_err:
@@ -1286,17 +1341,34 @@ out_err:
return err;
}
+static void mmc_select_driver_type(struct mmc_card *card)
+{
+ int card_drv_type, drive_strength, drv_type = 0;
+ int fixed_drv_type = card->host->fixed_drv_type;
+
+ card_drv_type = card->ext_csd.raw_driver_strength |
+ mmc_driver_type_mask(0);
+
+ if (fixed_drv_type >= 0)
+ drive_strength = card_drv_type & mmc_driver_type_mask(fixed_drv_type)
+ ? fixed_drv_type : 0;
+ else
+ drive_strength = mmc_select_drive_strength(card,
+ card->ext_csd.hs200_max_dtr,
+ card_drv_type, &drv_type);
+
+ card->drive_strength = drive_strength;
+
+ if (drv_type)
+ mmc_set_driver_type(card->host, drv_type);
+}
+
static int mmc_select_hs400es(struct mmc_card *card)
{
struct mmc_host *host = card->host;
- int err = 0;
+ int err = -EINVAL;
u8 val;
- if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
- err = -ENOTSUPP;
- goto out_err;
- }
-
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V)
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
@@ -1308,27 +1380,35 @@ static int mmc_select_hs400es(struct mmc_card *card)
goto out_err;
err = mmc_select_bus_width(card);
- if (err < 0)
+ if (err != MMC_BUS_WIDTH_8) {
+ pr_err("%s: switch to 8bit bus width failed, err:%d\n",
+ mmc_hostname(host), err);
+ err = err < 0 ? err : -ENOTSUPP;
goto out_err;
+ }
/* Switch card to HS mode */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time, 0,
- true, false, true);
+ false, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to hs for hs400es failed, err:%d\n",
mmc_hostname(host), err);
goto out_err;
}
+ /*
+ * Bump to HS timing and frequency. Some cards don't handle
+ * SEND_STATUS reliably at the initial frequency.
+ */
mmc_set_timing(host, MMC_TIMING_MMC_HS);
- err = mmc_switch_status(card);
+ mmc_set_bus_speed(card);
+
+ err = mmc_switch_status(card, true);
if (err)
goto out_err;
- mmc_set_clock(host, card->ext_csd.hs_max_dtr);
-
/* Switch card to DDR with strobe bit */
val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -1341,13 +1421,15 @@ static int mmc_select_hs400es(struct mmc_card *card)
goto out_err;
}
+ mmc_select_driver_type(card);
+
/* Switch card to HS400 */
val = EXT_CSD_TIMING_HS400 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, 0,
- true, false, true);
+ false, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to hs400es failed, err:%d\n",
mmc_hostname(host), err);
@@ -1362,7 +1444,7 @@ static int mmc_select_hs400es(struct mmc_card *card)
if (host->ops->hs400_enhanced_strobe)
host->ops->hs400_enhanced_strobe(host, &host->ios);
- err = mmc_switch_status(card);
+ err = mmc_switch_status(card, true);
if (err)
goto out_err;
@@ -1374,23 +1456,6 @@ out_err:
return err;
}
-static void mmc_select_driver_type(struct mmc_card *card)
-{
- int card_drv_type, drive_strength, drv_type;
-
- card_drv_type = card->ext_csd.raw_driver_strength |
- mmc_driver_type_mask(0);
-
- drive_strength = mmc_select_drive_strength(card,
- card->ext_csd.hs200_max_dtr,
- card_drv_type, &drv_type);
-
- card->drive_strength = drive_strength;
-
- if (drv_type)
- mmc_set_driver_type(card->host, drv_type);
-}
-
/*
* For device supporting HS200 mode, the following sequence
* should be done before executing the tuning process.
@@ -1401,7 +1466,7 @@ static void mmc_select_driver_type(struct mmc_card *card)
static int mmc_select_hs200(struct mmc_card *card)
{
struct mmc_host *host = card->host;
- unsigned int old_timing, old_signal_voltage;
+ unsigned int old_timing, old_signal_voltage, old_clock;
int err = -EINVAL;
u8 val;
@@ -1429,25 +1494,36 @@ static int mmc_select_hs200(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, 0,
- true, false, true);
+ false, true, MMC_CMD_RETRIES);
if (err)
goto err;
+
+ /*
+ * Bump to HS timing and frequency. Some cards don't handle
+ * SEND_STATUS reliably at the initial frequency.
+ * NB: We can't move to full (HS200) speeds until after we've
+ * successfully switched over.
+ */
old_timing = host->ios.timing;
+ old_clock = host->ios.clock;
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+ mmc_set_clock(card->host, card->ext_csd.hs_max_dtr);
/*
* For HS200, CRC errors are not a reliable way to know the
* switch failed. If there really is a problem, we would expect
* tuning will fail and the result ends up the same.
*/
- err = __mmc_switch_status(card, false);
+ err = mmc_switch_status(card, false);
/*
* mmc_select_timing() assumes timing has not changed if
* it is a switch error.
*/
- if (err == -EBADMSG)
+ if (err == -EBADMSG) {
+ mmc_set_clock(host, old_clock);
mmc_set_timing(host, old_timing);
+ }
}
err:
if (err) {
@@ -1468,16 +1544,26 @@ static int mmc_select_timing(struct mmc_card *card)
{
int err = 0;
- if (!mmc_can_ext_csd(card))
+ if (!mmc_card_can_ext_csd(card))
goto bus_speed;
- if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
+ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
err = mmc_select_hs400es(card);
- else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+ goto out;
+ }
+
+ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) {
err = mmc_select_hs200(card);
- else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
+ if (err == -EBADMSG)
+ card->mmc_avail_type &= ~EXT_CSD_CARD_TYPE_HS200;
+ else
+ goto out;
+ }
+
+ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
err = mmc_select_hs(card);
+out:
if (err && err != -EBADMSG)
return err;
@@ -1562,6 +1648,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (oldcard) {
if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
+ pr_debug("%s: Perhaps the card was replaced\n",
+ mmc_hostname(host));
err = -ENOENT;
goto err;
}
@@ -1651,6 +1739,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
mmc_set_erase_size(card);
}
+ /*
+ * Reselect the card type since host caps could have been changed when
+ * debugging even if the card is not new.
+ */
+ mmc_select_card_type(card);
+
/* Enable ERASE_GRP_DEF. This bit is lost after a reset or power off. */
if (card->ext_csd.rev >= 3) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -1661,7 +1755,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
goto free_card;
if (err) {
- err = 0;
/*
* Just disable enhanced area off & sz
* will try to enable ERASE_GROUP_DEF
@@ -1679,7 +1772,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
mmc_set_erase_size(card);
}
}
-
+ mmc_set_wp_grp_size(card);
/*
* Ensure eMMC user default partition is enabled
*/
@@ -1711,6 +1804,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
card->ext_csd.power_off_notification = EXT_CSD_POWER_ON;
}
+ /* set erase_arg */
+ if (mmc_card_can_discard(card))
+ card->erase_arg = MMC_DISCARD_ARG;
+ else if (mmc_card_can_trim(card))
+ card->erase_arg = MMC_TRIM_ARG;
+ else
+ card->erase_arg = MMC_ERASE_ARG;
+
/*
* Select timing interface
*/
@@ -1719,14 +1820,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
goto free_card;
if (mmc_card_hs200(card)) {
+ host->doing_init_tune = 1;
+
err = mmc_hs200_tuning(card);
- if (err)
- goto free_card;
+ if (!err)
+ err = mmc_select_hs400(card);
+
+ host->doing_init_tune = 0;
- err = mmc_select_hs400(card);
if (err)
goto free_card;
- } else if (!mmc_card_hs400es(card)) {
+ } else if (mmc_card_hs400es(card)) {
+ if (host->ops->execute_hs400_tuning) {
+ err = host->ops->execute_hs400_tuning(host, card);
+ if (err)
+ goto free_card;
+ }
+ } else {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
if (err > 0 && mmc_card_hs(card)) {
@@ -1753,20 +1863,25 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (err) {
pr_warn("%s: Enabling HPI failed\n",
mmc_hostname(card->host));
- err = 0;
- } else
+ card->ext_csd.hpi_en = 0;
+ } else {
card->ext_csd.hpi_en = 1;
+ }
}
/*
- * If cache size is higher than 0, this indicates
- * the existence of cache and it can be turned on.
+ * If cache size is higher than 0, this indicates the existence of cache
+ * and it can be turned on. Note that some eMMCs from Micron has been
+ * reported to need ~800 ms timeout, while enabling the cache after
+ * sudden power failure tests. Let's extend the timeout to a minimum of
+ * DEFAULT_CACHE_EN_TIMEOUT_MS and do it for all cards.
*/
- if (!mmc_card_broken_hpi(card) &&
- card->ext_csd.cache_size > 0) {
+ if (card->ext_csd.cache_size > 0) {
+ unsigned int timeout_ms = MIN_CACHE_EN_TIMEOUT_MS;
+
+ timeout_ms = max(card->ext_csd.generic_cmd6_time, timeout_ms);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_CACHE_CTRL, 1,
- card->ext_csd.generic_cmd6_time);
+ EXT_CSD_CACHE_CTRL, 1, timeout_ms);
if (err && err != -EBADMSG)
goto free_card;
@@ -1777,42 +1892,58 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
pr_warn("%s: Cache is supported, but failed to turn on (%d)\n",
mmc_hostname(card->host), err);
card->ext_csd.cache_ctrl = 0;
- err = 0;
} else {
card->ext_csd.cache_ctrl = 1;
}
}
/*
+ * Enable Command Queue if supported. Note that Packed Commands cannot
+ * be used with Command Queue.
+ */
+ card->ext_csd.cmdq_en = false;
+ if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) {
+ err = mmc_cmdq_enable(card);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warn("%s: Enabling CMDQ failed\n",
+ mmc_hostname(card->host));
+ card->ext_csd.cmdq_support = false;
+ card->ext_csd.cmdq_depth = 0;
+ }
+ }
+ /*
* In some cases (e.g. RPMB or mmc_test), the Command Queue must be
* disabled for a time, so a flag is needed to indicate to re-enable the
* Command Queue.
*/
card->reenable_cmdq = card->ext_csd.cmdq_en;
- /*
- * The mandatory minimum values are defined for packed command.
- * read: 5, write: 3
- */
- if (card->ext_csd.max_packed_writes >= 3 &&
- card->ext_csd.max_packed_reads >= 5 &&
- host->caps2 & MMC_CAP2_PACKED_CMD) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_EXP_EVENTS_CTRL,
- EXT_CSD_PACKED_EVENT_EN,
- card->ext_csd.generic_cmd6_time);
- if (err && err != -EBADMSG)
- goto free_card;
- if (err) {
- pr_warn("%s: Enabling packed event failed\n",
- mmc_hostname(card->host));
- card->ext_csd.packed_event_en = 0;
- err = 0;
- } else {
- card->ext_csd.packed_event_en = 1;
+ if (host->cqe_ops && !host->cqe_enabled) {
+ err = host->cqe_ops->cqe_enable(host, card);
+ if (!err) {
+ host->cqe_enabled = true;
+
+ if (card->ext_csd.cmdq_en) {
+ pr_info("%s: Command Queue Engine enabled\n",
+ mmc_hostname(host));
+ } else {
+ host->hsq_enabled = true;
+ pr_info("%s: Host Software Queue enabled\n",
+ mmc_hostname(host));
+ }
}
}
+ if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
+ host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+ pr_err("%s: Host failed to negotiate down from 3.3V\n",
+ mmc_hostname(host));
+ err = -EINVAL;
+ goto free_card;
+ }
+
if (!oldcard)
host->card = card;
@@ -1825,9 +1956,17 @@ err:
return err;
}
-static int mmc_can_sleep(struct mmc_card *card)
+static bool mmc_card_can_sleep(struct mmc_card *card)
{
- return (card && card->ext_csd.rev >= 3);
+ return card->ext_csd.rev >= 3;
+}
+
+static int mmc_sleep_busy_cb(void *cb_data, bool *busy)
+{
+ struct mmc_host *host = cb_data;
+
+ *busy = host->ops->card_busy(host);
+ return 0;
}
static int mmc_sleep(struct mmc_host *host)
@@ -1835,6 +1974,7 @@ static int mmc_sleep(struct mmc_host *host)
struct mmc_command cmd = {};
struct mmc_card *card = host->card;
unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
+ bool use_r1b_resp;
int err;
/* Re-tuning can't be done once the card is deselected */
@@ -1847,45 +1987,53 @@ static int mmc_sleep(struct mmc_host *host)
cmd.opcode = MMC_SLEEP_AWAKE;
cmd.arg = card->rca << 16;
cmd.arg |= 1 << 15;
-
- /*
- * If the max_busy_timeout of the host is specified, validate it against
- * the sleep cmd timeout. A failure means we need to prevent the host
- * from doing hw busy detection, which is done by converting to a R1
- * response instead of a R1B.
- */
- if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) {
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- } else {
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- cmd.busy_timeout = timeout_ms;
- }
+ use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
goto out_release;
/*
- * If the host does not wait while the card signals busy, then we will
- * will have to wait the sleep/awake timeout. Note, we cannot use the
- * SEND_STATUS command to poll the status because that command (and most
- * others) is invalid while the card sleeps.
+ * If the host does not wait while the card signals busy, then we can
+ * try to poll, but only if the host supports HW polling, as the
+ * SEND_STATUS cmd is not allowed. If we can't poll, then we simply need
+ * to wait the sleep/awake timeout.
*/
- if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+ if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp)
+ goto out_release;
+
+ if (!host->ops->card_busy) {
mmc_delay(timeout_ms);
+ goto out_release;
+ }
+
+ err = __mmc_poll_for_busy(host, 0, timeout_ms, &mmc_sleep_busy_cb, host);
out_release:
mmc_retune_release(host);
return err;
}
-static int mmc_can_poweroff_notify(const struct mmc_card *card)
+static bool mmc_card_can_poweroff_notify(const struct mmc_card *card)
{
return card &&
mmc_card_mmc(card) &&
(card->ext_csd.power_off_notification == EXT_CSD_POWER_ON);
}
+static bool mmc_host_can_poweroff_notify(const struct mmc_host *host,
+ enum mmc_poweroff_type pm_type)
+{
+ if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE)
+ return true;
+
+ if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND &&
+ pm_type == MMC_POWEROFF_SUSPEND)
+ return true;
+
+ return pm_type == MMC_POWEROFF_SHUTDOWN;
+}
+
static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
{
unsigned int timeout = card->ext_csd.generic_cmd6_time;
@@ -1897,7 +2045,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
- notify_type, timeout, 0, true, false, false);
+ notify_type, timeout, 0, false, false, MMC_CMD_RETRIES);
if (err)
pr_err("%s: Power Off Notification timed out, %u\n",
mmc_hostname(card->host), timeout);
@@ -1909,15 +2057,6 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
}
/*
- * Host is being removed. Free up the current card.
- */
-static void mmc_remove(struct mmc_host *host)
-{
- mmc_remove_card(host->card);
- host->card = NULL;
-}
-
-/*
* Card detection - card is alive.
*/
static int mmc_alive(struct mmc_host *host)
@@ -1932,17 +2071,18 @@ static void mmc_detect(struct mmc_host *host)
{
int err;
- mmc_get_card(host->card);
+ mmc_get_card(host->card, NULL);
/*
* Just check if our card has been removed.
*/
err = _mmc_detect_card_removed(host);
- mmc_put_card(host->card);
+ mmc_put_card(host->card, NULL);
if (err) {
- mmc_remove(host);
+ mmc_remove_card(host->card);
+ host->card = NULL;
mmc_claim_host(host);
mmc_detach_bus(host);
@@ -1951,31 +2091,62 @@ static void mmc_detect(struct mmc_host *host)
}
}
-static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
+static bool _mmc_cache_enabled(struct mmc_host *host)
+{
+ return host->card->ext_csd.cache_size > 0 &&
+ host->card->ext_csd.cache_ctrl & 1;
+}
+
+/*
+ * Flush the internal cache of the eMMC to non-volatile storage.
+ */
+static int _mmc_flush_cache(struct mmc_host *host)
+{
+ int err = 0;
+
+ if (mmc_card_broken_cache_flush(host->card) && !host->card->written_flag)
+ return 0;
+
+ if (_mmc_cache_enabled(host)) {
+ err = mmc_switch(host->card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_FLUSH_CACHE, 1,
+ CACHE_FLUSH_TIMEOUT_MS);
+ if (err)
+ pr_err("%s: cache flush error %d\n", mmc_hostname(host), err);
+ else
+ host->card->written_flag = false;
+ }
+
+ return err;
+}
+
+static int _mmc_suspend(struct mmc_host *host, enum mmc_poweroff_type pm_type)
{
+ unsigned int notify_type = EXT_CSD_POWER_OFF_SHORT;
int err = 0;
- unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :
- EXT_CSD_POWER_OFF_LONG;
+
+ if (pm_type == MMC_POWEROFF_SHUTDOWN)
+ notify_type = EXT_CSD_POWER_OFF_LONG;
mmc_claim_host(host);
if (mmc_card_suspended(host->card))
goto out;
- if (mmc_card_doing_bkops(host->card)) {
- err = mmc_stop_bkops(host->card);
+ /*
+ * For the undervoltage case, we care more about device integrity.
+ * Avoid cache flush and notify the device to power off quickly.
+ */
+ if (pm_type != MMC_POWEROFF_UNDERVOLTAGE) {
+ err = _mmc_flush_cache(host);
if (err)
goto out;
}
- err = mmc_flush_cache(host->card);
- if (err)
- goto out;
-
- if (mmc_can_poweroff_notify(host->card) &&
- ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
+ if (mmc_card_can_poweroff_notify(host->card) &&
+ mmc_host_can_poweroff_notify(host, pm_type))
err = mmc_poweroff_notify(host->card, notify_type);
- else if (mmc_can_sleep(host->card))
+ else if (mmc_card_can_sleep(host->card))
err = mmc_sleep(host);
else if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
@@ -1990,13 +2161,27 @@ out:
}
/*
+ * Host is being removed. Free up the current card and do a graceful power-off.
+ */
+static void mmc_remove(struct mmc_host *host)
+{
+ get_device(&host->card->dev);
+ mmc_remove_card(host->card);
+
+ _mmc_suspend(host, MMC_POWEROFF_UNBIND);
+
+ put_device(&host->card->dev);
+ host->card = NULL;
+}
+
+/*
* Suspend callback
*/
static int mmc_suspend(struct mmc_host *host)
{
int err;
- err = _mmc_suspend(host, true);
+ err = _mmc_suspend(host, MMC_POWEROFF_SUSPEND);
if (!err) {
pm_runtime_disable(&host->card->dev);
pm_runtime_set_suspended(&host->card->dev);
@@ -2035,15 +2220,23 @@ static int mmc_shutdown(struct mmc_host *host)
int err = 0;
/*
- * In a specific case for poweroff notify, we need to resume the card
- * before we can shutdown it properly.
+ * In case of undervoltage, the card will be powered off (removed) by
+ * _mmc_handle_undervoltage()
+ */
+ if (mmc_card_removed(host->card))
+ return 0;
+
+ /*
+ * If the card remains suspended at this point and it was done by using
+ * the sleep-cmd (CMD5), we may need to re-initialize it first, to allow
+ * us to send the preferred poweroff-notification cmd at shutdown.
*/
- if (mmc_can_poweroff_notify(host->card) &&
- !(host->caps2 & MMC_CAP2_FULL_PWR_CYCLE))
+ if (mmc_card_can_poweroff_notify(host->card) &&
+ !mmc_host_can_poweroff_notify(host, MMC_POWEROFF_SUSPEND))
err = _mmc_resume(host);
if (!err)
- err = _mmc_suspend(host, false);
+ err = _mmc_suspend(host, MMC_POWEROFF_SHUTDOWN);
return err;
}
@@ -2067,7 +2260,7 @@ static int mmc_runtime_suspend(struct mmc_host *host)
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
- err = _mmc_suspend(host, true);
+ err = _mmc_suspend(host, MMC_POWEROFF_SUSPEND);
if (err)
pr_err("%s: error %d doing aggressive suspend\n",
mmc_hostname(host), err);
@@ -2090,17 +2283,15 @@ static int mmc_runtime_resume(struct mmc_host *host)
return 0;
}
-static int mmc_can_reset(struct mmc_card *card)
+static bool mmc_card_can_reset(struct mmc_card *card)
{
u8 rst_n_function;
rst_n_function = card->ext_csd.rst_n_function;
- if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
- return 0;
- return 1;
+ return ((rst_n_function & EXT_CSD_RST_N_EN_MASK) == EXT_CSD_RST_N_ENABLED);
}
-static int mmc_reset(struct mmc_host *host)
+static int _mmc_hw_reset(struct mmc_host *host)
{
struct mmc_card *card = host->card;
@@ -2108,13 +2299,13 @@ static int mmc_reset(struct mmc_host *host)
* In the case of recovery, we can't expect flushing the cache to work
* always, but we have a go and ignore errors.
*/
- mmc_flush_cache(host->card);
+ _mmc_flush_cache(host);
- if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
- mmc_can_reset(card)) {
+ if ((host->caps & MMC_CAP_HW_RESET) && host->ops->card_hw_reset &&
+ mmc_card_can_reset(card)) {
/* If the card accept RST_n signal, send it. */
mmc_set_clock(host, host->f_init);
- host->ops->hw_reset(host);
+ host->ops->card_hw_reset(host);
/* Set initial state and call mmc_set_ios */
mmc_set_initial_state(host);
} else {
@@ -2125,6 +2316,55 @@ static int mmc_reset(struct mmc_host *host)
return mmc_init_card(host, card->ocr, card);
}
+/**
+ * _mmc_handle_undervoltage - Handle an undervoltage event for MMC/eMMC devices
+ * @host: MMC host structure
+ *
+ * This function is triggered when an undervoltage condition is detected.
+ * It attempts to transition the device into a low-power or safe state to
+ * prevent data corruption.
+ *
+ * Steps performed:
+ * - Perform an emergency suspend using EXT_CSD_POWER_OFF_SHORT if possible.
+ * - If power-off notify is not supported, fallback mechanisms like sleep or
+ * deselecting the card are attempted.
+ * - Cache flushing is skipped to reduce execution time.
+ * - Mark the card as removed to prevent further interactions after
+ * undervoltage.
+ *
+ * Note: This function does not handle host claiming or releasing. The caller
+ * must ensure that the host is properly claimed before calling this
+ * function and released afterward.
+ *
+ * Returns: 0 on success, or a negative error code if any step fails.
+ */
+static int _mmc_handle_undervoltage(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+ int err;
+
+ /*
+ * Perform an emergency suspend to power off the eMMC quickly.
+ * This ensures the device enters a safe state before power is lost.
+ * We first attempt EXT_CSD_POWER_OFF_SHORT, but if power-off notify
+ * is not supported, we fall back to sleep mode or deselecting the card.
+ * Cache flushing is skipped to minimize delay.
+ */
+ err = _mmc_suspend(host, MMC_POWEROFF_UNDERVOLTAGE);
+ if (err)
+ pr_err("%s: undervoltage suspend failed: %pe\n",
+ mmc_hostname(host), ERR_PTR(err));
+
+ /*
+ * Mark the card as removed to prevent further operations.
+ * This ensures the system does not attempt to access the device
+ * after an undervoltage event, avoiding potential corruption.
+ */
+ mmc_card_set_removed(card);
+
+ return err;
+}
+
static const struct mmc_bus_ops mmc_ops = {
.remove = mmc_remove,
.detect = mmc_detect,
@@ -2134,7 +2374,10 @@ static const struct mmc_bus_ops mmc_ops = {
.runtime_resume = mmc_runtime_resume,
.alive = mmc_alive,
.shutdown = mmc_shutdown,
- .reset = mmc_reset,
+ .hw_reset = _mmc_hw_reset,
+ .cache_enabled = _mmc_cache_enabled,
+ .flush_cache = _mmc_flush_cache,
+ .handle_undervoltage = _mmc_handle_undervoltage,
};
/*
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 5f7c5920231a..a952cc8265af 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/core/mmc_ops.h
*
* Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#include <linux/slab.h>
@@ -23,7 +19,10 @@
#include "host.h"
#include "mmc_ops.h"
-#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+#define MMC_BKOPS_TIMEOUT_MS (120 * 1000) /* 120s */
+#define MMC_SANITIZE_TIMEOUT_MS (240 * 1000) /* 240s */
+#define MMC_OP_COND_PERIOD_US (4 * 1000) /* 4ms */
+#define MMC_OP_COND_TIMEOUT_MS 1000 /* 1s */
static const u8 tuning_blk_pattern_4bit[] = {
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
@@ -55,6 +54,18 @@ static const u8 tuning_blk_pattern_8bit[] = {
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
};
+struct mmc_busy_data {
+ struct mmc_card *card;
+ bool retry_crc_err;
+ enum mmc_busy_cmd busy_cmd;
+};
+
+struct mmc_op_cond_busy_data {
+ struct mmc_host *host;
+ u32 ocr;
+ struct mmc_command *cmd;
+};
+
int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries)
{
int err;
@@ -83,6 +94,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status)
{
return __mmc_send_status(card, status, MMC_CMD_RETRIES);
}
+EXPORT_SYMBOL_GPL(mmc_send_status);
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
@@ -132,10 +144,24 @@ int mmc_set_dsr(struct mmc_host *host)
return mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
}
+int __mmc_go_idle(struct mmc_host *host)
+{
+ struct mmc_command cmd = {};
+ int err;
+
+ cmd.opcode = MMC_GO_IDLE_STATE;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ mmc_delay(1);
+
+ return err;
+}
+
int mmc_go_idle(struct mmc_host *host)
{
int err;
- struct mmc_command cmd = {};
/*
* Non-SPI hosts need to prevent chipselect going active during
@@ -151,13 +177,7 @@ int mmc_go_idle(struct mmc_host *host)
mmc_delay(1);
}
- cmd.opcode = MMC_GO_IDLE_STATE;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
-
- mmc_delay(1);
+ err = __mmc_go_idle(host);
if (!mmc_host_is_spi(host)) {
mmc_set_chip_select(host, MMC_CS_DONTCARE);
@@ -169,37 +189,64 @@ int mmc_go_idle(struct mmc_host *host)
return err;
}
+static int __mmc_send_op_cond_cb(void *cb_data, bool *busy)
+{
+ struct mmc_op_cond_busy_data *data = cb_data;
+ struct mmc_host *host = data->host;
+ struct mmc_command *cmd = data->cmd;
+ u32 ocr = data->ocr;
+ int err = 0;
+
+ err = mmc_wait_for_cmd(host, cmd, 0);
+ if (err)
+ return err;
+
+ if (mmc_host_is_spi(host)) {
+ if (!(cmd->resp[0] & R1_SPI_IDLE)) {
+ *busy = false;
+ return 0;
+ }
+ } else {
+ if (cmd->resp[0] & MMC_CARD_BUSY) {
+ *busy = false;
+ return 0;
+ }
+ }
+
+ *busy = true;
+
+ /*
+ * According to eMMC specification v5.1 section 6.4.3, we
+ * should issue CMD1 repeatedly in the idle state until
+ * the eMMC is ready. Otherwise some eMMC devices seem to enter
+ * the inactive mode after mmc_init_card() issued CMD0 when
+ * the eMMC device is busy.
+ */
+ if (!ocr && !mmc_host_is_spi(host))
+ cmd->arg = cmd->resp[0] | BIT(30);
+
+ return 0;
+}
+
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
struct mmc_command cmd = {};
- int i, err = 0;
+ int err = 0;
+ struct mmc_op_cond_busy_data cb_data = {
+ .host = host,
+ .ocr = ocr,
+ .cmd = &cmd
+ };
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
- for (i = 100; i; i--) {
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
- break;
-
- /* if we're just probing, do a single pass */
- if (ocr == 0)
- break;
-
- /* otherwise wait until reset completes */
- if (mmc_host_is_spi(host)) {
- if (!(cmd.resp[0] & R1_SPI_IDLE))
- break;
- } else {
- if (cmd.resp[0] & MMC_CARD_BUSY)
- break;
- }
-
- err = -ETIMEDOUT;
-
- mmc_delay(10);
- }
+ err = __mmc_poll_for_busy(host, MMC_OP_COND_PERIOD_US,
+ MMC_OP_COND_TIMEOUT_MS,
+ &__mmc_send_op_cond_cb, &cb_data);
+ if (err)
+ return err;
if (rocr && !mmc_host_is_spi(host))
*rocr = cmd.resp[0];
@@ -241,9 +288,8 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
* NOTE: void *buf, caller for the buf is required to use DMA-capable
* buffer or on-stack buffer (with some overhead in callee).
*/
-static int
-mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
- u32 opcode, void *buf, unsigned len)
+int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
+ u32 args, void *buf, unsigned len)
{
struct mmc_request mrq = {};
struct mmc_command cmd = {};
@@ -254,7 +300,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
mrq.data = &data;
cmd.opcode = opcode;
- cmd.arg = 0;
+ cmd.arg = args;
/* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we
* rely on callers to never use this with "native" calls for reading
@@ -291,61 +337,40 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
return 0;
}
-static int mmc_spi_send_csd(struct mmc_card *card, u32 *csd)
+static int mmc_spi_send_cxd(struct mmc_host *host, u32 *cxd, u32 opcode)
{
int ret, i;
- __be32 *csd_tmp;
+ __be32 *cxd_tmp;
- csd_tmp = kzalloc(16, GFP_KERNEL);
- if (!csd_tmp)
+ cxd_tmp = kzalloc(16, GFP_KERNEL);
+ if (!cxd_tmp)
return -ENOMEM;
- ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd_tmp, 16);
+ ret = mmc_send_adtc_data(NULL, host, opcode, 0, cxd_tmp, 16);
if (ret)
goto err;
for (i = 0; i < 4; i++)
- csd[i] = be32_to_cpu(csd_tmp[i]);
+ cxd[i] = be32_to_cpu(cxd_tmp[i]);
err:
- kfree(csd_tmp);
+ kfree(cxd_tmp);
return ret;
}
int mmc_send_csd(struct mmc_card *card, u32 *csd)
{
if (mmc_host_is_spi(card->host))
- return mmc_spi_send_csd(card, csd);
+ return mmc_spi_send_cxd(card->host, csd, MMC_SEND_CSD);
return mmc_send_cxd_native(card->host, card->rca << 16, csd,
MMC_SEND_CSD);
}
-static int mmc_spi_send_cid(struct mmc_host *host, u32 *cid)
-{
- int ret, i;
- __be32 *cid_tmp;
-
- cid_tmp = kzalloc(16, GFP_KERNEL);
- if (!cid_tmp)
- return -ENOMEM;
-
- ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid_tmp, 16);
- if (ret)
- goto err;
-
- for (i = 0; i < 4; i++)
- cid[i] = be32_to_cpu(cid_tmp[i]);
-
-err:
- kfree(cid_tmp);
- return ret;
-}
-
int mmc_send_cid(struct mmc_host *host, u32 *cid)
{
if (mmc_host_is_spi(host))
- return mmc_spi_send_cid(host, cid);
+ return mmc_spi_send_cxd(host, cid, MMC_SEND_CID);
return mmc_send_cxd_native(host, 0, cid, MMC_ALL_SEND_CID);
}
@@ -358,7 +383,7 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
if (!card || !new_ext_csd)
return -EINVAL;
- if (!mmc_can_ext_csd(card))
+ if (!mmc_card_can_ext_csd(card))
return -EOPNOTSUPP;
/*
@@ -369,7 +394,7 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
if (!ext_csd)
return -ENOMEM;
- err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd,
+ err = mmc_send_adtc_data(card, card->host, MMC_SEND_EXT_CSD, 0, ext_csd,
512);
if (err)
kfree(ext_csd);
@@ -416,7 +441,7 @@ static int mmc_switch_status_error(struct mmc_host *host, u32 status)
if (status & R1_SPI_ILLEGAL_COMMAND)
return -EBADMSG;
} else {
- if (status & 0xFDFFA000)
+ if (R1_STATUS(status))
pr_warn("%s: unexpected status %#x after switch\n",
mmc_hostname(host), status);
if (status & R1_SWITCH_ERROR)
@@ -426,7 +451,7 @@ static int mmc_switch_status_error(struct mmc_host *host, u32 status)
}
/* Caller must hold re-tuning */
-int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
+int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
{
u32 status;
int err;
@@ -440,35 +465,59 @@ int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
return mmc_switch_status_error(card->host, status);
}
-int mmc_switch_status(struct mmc_card *card)
+static int mmc_busy_cb(void *cb_data, bool *busy)
{
- return __mmc_switch_status(card, true);
+ struct mmc_busy_data *data = cb_data;
+ struct mmc_host *host = data->card->host;
+ u32 status = 0;
+ int err;
+
+ if (data->busy_cmd != MMC_BUSY_IO && host->ops->card_busy) {
+ *busy = host->ops->card_busy(host);
+ return 0;
+ }
+
+ err = mmc_send_status(data->card, &status);
+ if (data->retry_crc_err && err == -EILSEQ) {
+ *busy = true;
+ return 0;
+ }
+ if (err)
+ return err;
+
+ switch (data->busy_cmd) {
+ case MMC_BUSY_CMD6:
+ err = mmc_switch_status_error(host, status);
+ break;
+ case MMC_BUSY_ERASE:
+ err = R1_STATUS(status) ? -EIO : 0;
+ break;
+ case MMC_BUSY_HPI:
+ case MMC_BUSY_EXTR_SINGLE:
+ case MMC_BUSY_IO:
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if (err)
+ return err;
+
+ *busy = !mmc_ready_for_data(status);
+ return 0;
}
-static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
- bool send_status, bool retry_crc_err)
+int __mmc_poll_for_busy(struct mmc_host *host, unsigned int period_us,
+ unsigned int timeout_ms,
+ int (*busy_cb)(void *cb_data, bool *busy),
+ void *cb_data)
{
- struct mmc_host *host = card->host;
int err;
unsigned long timeout;
- u32 status = 0;
+ unsigned int udelay = period_us ? period_us : 32, udelay_max = 32768;
bool expired = false;
bool busy = false;
- /* We have an unspecified cmd timeout, use the fallback value. */
- if (!timeout_ms)
- timeout_ms = MMC_OPS_TIMEOUT_MS;
-
- /*
- * In cases when not allowed to poll by using CMD13 or because we aren't
- * capable of polling by using ->card_busy(), then rely on waiting the
- * stated timeout to be sufficient.
- */
- if (!send_status && !host->ops->card_busy) {
- mmc_delay(timeout_ms);
- return 0;
- }
-
timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
do {
/*
@@ -477,21 +526,9 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
*/
expired = time_after(jiffies, timeout);
- if (host->ops->card_busy) {
- busy = host->ops->card_busy(host);
- } else {
- err = mmc_send_status(card, &status);
- if (retry_crc_err && err == -EILSEQ) {
- busy = true;
- } else if (err) {
- return err;
- } else {
- err = mmc_switch_status_error(host, status);
- if (err)
- return err;
- busy = R1_CURRENT_STATE(status) == R1_STATE_PRG;
- }
- }
+ err = (*busy_cb)(cb_data, &busy);
+ if (err)
+ return err;
/* Timeout if the device still remains busy. */
if (expired && busy) {
@@ -499,10 +536,54 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
mmc_hostname(host), __func__);
return -ETIMEDOUT;
}
+
+ /* Throttle the polling rate to avoid hogging the CPU. */
+ if (busy) {
+ usleep_range(udelay, udelay * 2);
+ if (udelay < udelay_max)
+ udelay *= 2;
+ }
} while (busy);
return 0;
}
+EXPORT_SYMBOL_GPL(__mmc_poll_for_busy);
+
+int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+ bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
+{
+ struct mmc_host *host = card->host;
+ struct mmc_busy_data cb_data;
+
+ cb_data.card = card;
+ cb_data.retry_crc_err = retry_crc_err;
+ cb_data.busy_cmd = busy_cmd;
+
+ return __mmc_poll_for_busy(host, 0, timeout_ms, &mmc_busy_cb, &cb_data);
+}
+EXPORT_SYMBOL_GPL(mmc_poll_for_busy);
+
+bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+ unsigned int timeout_ms)
+{
+ /*
+ * If the max_busy_timeout of the host is specified, make sure it's
+ * enough to fit the used timeout_ms. In case it's not, let's instruct
+ * the host to avoid HW busy detection, by converting to a R1 response
+ * instead of a R1B. Note, some hosts requires R1B, which also means
+ * they are on their own when it comes to deal with the busy timeout.
+ */
+ if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
+ (timeout_ms > host->max_busy_timeout)) {
+ cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1 | MMC_RSP_R1;
+ return false;
+ }
+
+ cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+ cmd->busy_timeout = timeout_ms;
+ return true;
+}
+EXPORT_SYMBOL_GPL(mmc_prepare_busy_cmd);
/**
* __mmc_switch - modify EXT_CSD register
@@ -513,69 +594,58 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
* @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout
* @timing: new timing to change to
- * @use_busy_signal: use the busy signal as response type
* @send_status: send status cmd to poll for busy
* @retry_crc_err: retry when CRC errors when polling with CMD13 for busy
+ * @retries: number of retries
*
* Modifies the EXT_CSD register for selected card.
*/
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, unsigned char timing,
- bool use_busy_signal, bool send_status, bool retry_crc_err)
+ bool send_status, bool retry_crc_err, unsigned int retries)
{
struct mmc_host *host = card->host;
int err;
struct mmc_command cmd = {};
- bool use_r1b_resp = use_busy_signal;
+ bool use_r1b_resp;
unsigned char old_timing = host->ios.timing;
mmc_retune_hold(host);
- /*
- * If the cmd timeout and the max_busy_timeout of the host are both
- * specified, let's validate them. A failure means we need to prevent
- * the host from doing hw busy detection, which is done by converting
- * to a R1 response instead of a R1B.
- */
- if (timeout_ms && host->max_busy_timeout &&
- (timeout_ms > host->max_busy_timeout))
- use_r1b_resp = false;
+ if (!timeout_ms) {
+ pr_warn("%s: unspecified timeout for CMD6 - use generic\n",
+ mmc_hostname(host));
+ timeout_ms = card->ext_csd.generic_cmd6_time;
+ }
cmd.opcode = MMC_SWITCH;
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
(index << 16) |
(value << 8) |
set;
- cmd.flags = MMC_CMD_AC;
- if (use_r1b_resp) {
- cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
- /*
- * A busy_timeout of zero means the host can decide to use
- * whatever value it finds suitable.
- */
- cmd.busy_timeout = timeout_ms;
- } else {
- cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
- }
-
- if (index == EXT_CSD_SANITIZE_START)
- cmd.sanitize_busy = true;
+ use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
- err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ err = mmc_wait_for_cmd(host, &cmd, retries);
if (err)
goto out;
- /* No need to check card status in case of unblocking command */
- if (!use_busy_signal)
- goto out;
-
/*If SPI or used HW busy detection above, then we don't need to poll. */
if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) ||
mmc_host_is_spi(host))
goto out_tim;
+ /*
+ * If the host doesn't support HW polling via the ->card_busy() ops and
+ * when it's not allowed to poll by using CMD13, then we need to rely on
+ * waiting the stated timeout to be sufficient.
+ */
+ if (!send_status && !host->ops->card_busy) {
+ mmc_delay(timeout_ms);
+ goto out_tim;
+ }
+
/* Let's try to poll to find out when the command is completed. */
- err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err);
+ err = mmc_poll_for_busy(card, timeout_ms, retry_crc_err, MMC_BUSY_CMD6);
if (err)
goto out;
@@ -585,7 +655,7 @@ out_tim:
mmc_set_timing(host, timing);
if (send_status) {
- err = mmc_switch_status(card);
+ err = mmc_switch_status(card, true);
if (err && timing)
mmc_set_timing(host, old_timing);
}
@@ -599,7 +669,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms)
{
return __mmc_switch(card, set, index, value, timeout_ms, 0,
- true, true, false);
+ true, false, MMC_CMD_RETRIES);
}
EXPORT_SYMBOL_GPL(mmc_switch);
@@ -672,7 +742,7 @@ out:
}
EXPORT_SYMBOL_GPL(mmc_send_tuning);
-int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
+int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode)
{
struct mmc_command cmd = {};
@@ -695,7 +765,7 @@ int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
return mmc_wait_for_cmd(host, &cmd, 0);
}
-EXPORT_SYMBOL_GPL(mmc_abort_tuning);
+EXPORT_SYMBOL_GPL(mmc_send_abort_tuning);
static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
@@ -795,38 +865,35 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
return mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
}
-static int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
+static int mmc_send_hpi_cmd(struct mmc_card *card)
{
+ unsigned int busy_timeout_ms = card->ext_csd.out_of_int_time;
+ struct mmc_host *host = card->host;
+ bool use_r1b_resp = false;
struct mmc_command cmd = {};
- unsigned int opcode;
int err;
- if (!card->ext_csd.hpi) {
- pr_warn("%s: Card didn't support HPI command\n",
- mmc_hostname(card->host));
- return -EINVAL;
- }
-
- opcode = card->ext_csd.hpi_cmd;
- if (opcode == MMC_STOP_TRANSMISSION)
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- else if (opcode == MMC_SEND_STATUS)
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- cmd.opcode = opcode;
+ cmd.opcode = card->ext_csd.hpi_cmd;
cmd.arg = card->rca << 16 | 1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (cmd.opcode == MMC_STOP_TRANSMISSION)
+ use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd,
+ busy_timeout_ms);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
if (err) {
- pr_warn("%s: error %d interrupting operation. "
- "HPI command response %#x\n", mmc_hostname(card->host),
- err, cmd.resp[0]);
+ pr_warn("%s: HPI error %d. Command response %#x\n",
+ mmc_hostname(host), err, cmd.resp[0]);
return err;
}
- if (status)
- *status = cmd.resp[0];
- return 0;
+ /* No need to poll when using HW busy detection. */
+ if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp)
+ return 0;
+
+ /* Let's poll to find out when the HPI request completes. */
+ return mmc_poll_for_busy(card, busy_timeout_ms, false, MMC_BUSY_HPI);
}
/**
@@ -836,18 +903,16 @@ static int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
* Issued High Priority Interrupt, and check for card status
* until out-of prg-state.
*/
-int mmc_interrupt_hpi(struct mmc_card *card)
+static int mmc_interrupt_hpi(struct mmc_card *card)
{
int err;
u32 status;
- unsigned long prg_wait;
if (!card->ext_csd.hpi_en) {
pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
return 1;
}
- mmc_claim_host(card->host);
err = mmc_send_status(card, &status);
if (err) {
pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
@@ -874,66 +939,22 @@ int mmc_interrupt_hpi(struct mmc_card *card)
goto out;
}
- err = mmc_send_hpi_cmd(card, &status);
- if (err)
- goto out;
-
- prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time);
- do {
- err = mmc_send_status(card, &status);
-
- if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN)
- break;
- if (time_after(jiffies, prg_wait))
- err = -ETIMEDOUT;
- } while (!err);
-
+ err = mmc_send_hpi_cmd(card);
out:
- mmc_release_host(card->host);
return err;
}
-int mmc_can_ext_csd(struct mmc_card *card)
+bool mmc_card_can_ext_csd(struct mmc_card *card)
{
return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3);
}
-/**
- * mmc_stop_bkops - stop ongoing BKOPS
- * @card: MMC card to check BKOPS
- *
- * Send HPI command to stop ongoing background operations to
- * allow rapid servicing of foreground operations, e.g. read/
- * writes. Wait until the card comes out of the programming state
- * to avoid errors in servicing read/write requests.
- */
-int mmc_stop_bkops(struct mmc_card *card)
-{
- int err = 0;
-
- err = mmc_interrupt_hpi(card);
-
- /*
- * If err is EINVAL, we can't issue an HPI.
- * It should complete the BKOPS.
- */
- if (!err || (err == -EINVAL)) {
- mmc_card_clr_doing_bkops(card);
- mmc_retune_release(card->host);
- err = 0;
- }
-
- return err;
-}
-
static int mmc_read_bkops_status(struct mmc_card *card)
{
int err;
u8 *ext_csd;
- mmc_claim_host(card->host);
err = mmc_get_ext_csd(card, &ext_csd);
- mmc_release_host(card->host);
if (err)
return err;
@@ -944,22 +965,17 @@ static int mmc_read_bkops_status(struct mmc_card *card)
}
/**
- * mmc_start_bkops - start BKOPS for supported cards
- * @card: MMC card to start BKOPS
- * @form_exception: A flag to indicate if this function was
- * called due to an exception raised by the card
+ * mmc_run_bkops - Run BKOPS for supported cards
+ * @card: MMC card to run BKOPS for
*
- * Start background operations whenever requested.
- * When the urgent BKOPS bit is set in a R1 command response
- * then background operations should be started immediately.
+ * Run background operations synchronously for cards having manual BKOPS
+ * enabled and in case it reports urgent BKOPS level.
*/
-void mmc_start_bkops(struct mmc_card *card, bool from_exception)
+void mmc_run_bkops(struct mmc_card *card)
{
int err;
- int timeout;
- bool use_busy_signal;
- if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card))
+ if (!card->ext_csd.man_bkops_en)
return;
err = mmc_read_bkops_status(card);
@@ -969,67 +985,33 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
return;
}
- if (!card->ext_csd.raw_bkops_status)
- return;
-
- if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
- from_exception)
+ if (!card->ext_csd.raw_bkops_status ||
+ card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2)
return;
- mmc_claim_host(card->host);
- if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
- timeout = MMC_OPS_TIMEOUT_MS;
- use_busy_signal = true;
- } else {
- timeout = 0;
- use_busy_signal = false;
- }
-
mmc_retune_hold(card->host);
- err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BKOPS_START, 1, timeout, 0,
- use_busy_signal, true, false);
- if (err) {
- pr_warn("%s: Error %d starting bkops\n",
- mmc_hostname(card->host), err);
- mmc_retune_release(card->host);
- goto out;
- }
-
/*
- * For urgent bkops status (LEVEL_2 and more)
- * bkops executed synchronously, otherwise
- * the operation is in progress
+ * For urgent BKOPS status, LEVEL_2 and higher, let's execute
+ * synchronously. Future wise, we may consider to start BKOPS, for less
+ * urgent levels by using an asynchronous background task, when idle.
*/
- if (!use_busy_signal)
- mmc_card_set_doing_bkops(card);
- else
- mmc_retune_release(card->host);
-out:
- mmc_release_host(card->host);
-}
-
-/*
- * Flush the cache to the non-volatile storage.
- */
-int mmc_flush_cache(struct mmc_card *card)
-{
- int err = 0;
-
- if (mmc_card_mmc(card) &&
- (card->ext_csd.cache_size > 0) &&
- (card->ext_csd.cache_ctrl & 1)) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_FLUSH_CACHE, 1, 0);
- if (err)
- pr_err("%s: cache flush error %d\n",
- mmc_hostname(card->host), err);
- }
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BKOPS_START, 1, MMC_BKOPS_TIMEOUT_MS);
+ /*
+ * If the BKOPS timed out, the card is probably still busy in the
+ * R1_STATE_PRG. Rather than continue to wait, let's try to abort
+ * it with a HPI command to get back into R1_STATE_TRAN.
+ */
+ if (err == -ETIMEDOUT && !mmc_interrupt_hpi(card))
+ pr_warn("%s: BKOPS aborted\n", mmc_hostname(card->host));
+ else if (err)
+ pr_warn("%s: Error %d running bkops\n",
+ mmc_hostname(card->host), err);
- return err;
+ mmc_retune_release(card->host);
}
-EXPORT_SYMBOL(mmc_flush_cache);
+EXPORT_SYMBOL(mmc_run_bkops);
static int mmc_cmdq_switch(struct mmc_card *card, bool enable)
{
@@ -1058,3 +1040,112 @@ int mmc_cmdq_disable(struct mmc_card *card)
return mmc_cmdq_switch(card, false);
}
EXPORT_SYMBOL_GPL(mmc_cmdq_disable);
+
+int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms)
+{
+ struct mmc_host *host = card->host;
+ int err;
+
+ if (!mmc_card_can_sanitize(card)) {
+ pr_warn("%s: Sanitize not supported\n", mmc_hostname(host));
+ return -EOPNOTSUPP;
+ }
+
+ if (!timeout_ms)
+ timeout_ms = MMC_SANITIZE_TIMEOUT_MS;
+
+ pr_debug("%s: Sanitize in progress...\n", mmc_hostname(host));
+
+ mmc_retune_hold(host);
+
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_SANITIZE_START,
+ 1, timeout_ms, 0, true, false, 0);
+ if (err)
+ pr_err("%s: Sanitize failed err=%d\n", mmc_hostname(host), err);
+
+ /*
+ * If the sanitize operation timed out, the card is probably still busy
+ * in the R1_STATE_PRG. Rather than continue to wait, let's try to abort
+ * it with a HPI command to get back into R1_STATE_TRAN.
+ */
+ if (err == -ETIMEDOUT && !mmc_interrupt_hpi(card))
+ pr_warn("%s: Sanitize aborted\n", mmc_hostname(host));
+
+ mmc_retune_release(host);
+
+ pr_debug("%s: Sanitize completed\n", mmc_hostname(host));
+ return err;
+}
+EXPORT_SYMBOL_GPL(mmc_sanitize);
+
+/**
+ * mmc_read_tuning() - read data blocks from the mmc
+ * @host: mmc host doing the read
+ * @blksz: data block size
+ * @blocks: number of blocks to read
+ *
+ * Read one or more blocks of data from the beginning of the mmc. This is a
+ * low-level helper for tuning operation. It is assumed that CMD23 can be used
+ * for multi-block read if the host supports it.
+ *
+ * Note: Allocate and free a temporary buffer to store the data read. The data
+ * is not available outside of the function, only the status of the read
+ * operation.
+ *
+ * Return: 0 in case of success, otherwise -EIO / -ENOMEM / -E2BIG
+ */
+int mmc_read_tuning(struct mmc_host *host, unsigned int blksz, unsigned int blocks)
+{
+ struct mmc_request mrq = {};
+ struct mmc_command sbc = {};
+ struct mmc_command cmd = {};
+ struct mmc_command stop = {};
+ struct mmc_data data = {};
+ struct scatterlist sg;
+ void *buf;
+ unsigned int len;
+
+ if (blocks > 1) {
+ if (mmc_host_can_cmd23(host)) {
+ mrq.sbc = &sbc;
+ sbc.opcode = MMC_SET_BLOCK_COUNT;
+ sbc.arg = blocks;
+ sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ }
+ cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
+ mrq.stop = &stop;
+ stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ } else {
+ cmd.opcode = MMC_READ_SINGLE_BLOCK;
+ }
+
+ mrq.cmd = &cmd;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ mrq.data = &data;
+ data.flags = MMC_DATA_READ;
+ data.blksz = blksz;
+ data.blocks = blocks;
+ data.blk_addr = 0;
+ data.sg = &sg;
+ data.sg_len = 1;
+ data.timeout_ns = 1000000000;
+
+ if (check_mul_overflow(blksz, blocks, &len))
+ return -E2BIG;
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ sg_init_one(&sg, buf, len);
+
+ mmc_wait_for_req(host, &mrq);
+ kfree(buf);
+
+ if (sbc.error || cmd.error || data.error)
+ return -EIO;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mmc_read_tuning);
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index a1390d486381..514c40ff4b4e 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* linux/drivers/mmc/core/mmc_ops.h
*
* Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#ifndef _MMC_MMC_OPS_H
@@ -14,37 +10,66 @@
#include <linux/types.h>
+enum mmc_busy_cmd {
+ MMC_BUSY_CMD6,
+ MMC_BUSY_ERASE,
+ MMC_BUSY_HPI,
+ MMC_BUSY_EXTR_SINGLE,
+ MMC_BUSY_IO,
+};
+
struct mmc_host;
struct mmc_card;
+struct mmc_command;
int mmc_select_card(struct mmc_card *card);
int mmc_deselect_cards(struct mmc_host *host);
int mmc_set_dsr(struct mmc_host *host);
+int __mmc_go_idle(struct mmc_host *host);
int mmc_go_idle(struct mmc_host *host);
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_set_relative_addr(struct mmc_card *card);
+int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
+ u32 args, void *buf, unsigned len);
int mmc_send_csd(struct mmc_card *card, u32 *csd);
int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries);
-int mmc_send_status(struct mmc_card *card, u32 *status);
int mmc_send_cid(struct mmc_host *host, u32 *cid);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
int mmc_bus_test(struct mmc_card *card, u8 bus_width);
-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);
-int mmc_switch_status(struct mmc_card *card);
-int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+bool mmc_card_can_ext_csd(struct mmc_card *card);
+int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+ unsigned int timeout_ms);
+int __mmc_poll_for_busy(struct mmc_host *host, unsigned int period_us,
+ unsigned int timeout_ms,
+ int (*busy_cb)(void *cb_data, bool *busy),
+ void *cb_data);
+int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+ bool retry_crc_err, enum mmc_busy_cmd busy_cmd);
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, unsigned char timing,
- bool use_busy_signal, bool send_status, bool retry_crc_err);
+ bool send_status, bool retry_crc_err, unsigned int retries);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms);
-int mmc_stop_bkops(struct mmc_card *card);
-void mmc_start_bkops(struct mmc_card *card, bool from_exception);
-int mmc_flush_cache(struct mmc_card *card);
+void mmc_run_bkops(struct mmc_card *card);
int mmc_cmdq_enable(struct mmc_card *card);
int mmc_cmdq_disable(struct mmc_card *card);
+int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms);
+
+static inline u32 unstuff_bits(const u32 *resp, int start, int size)
+{
+ const int __size = size;
+ const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1;
+ const int __off = 3 - (start / 32);
+ const int __shft = start & 31;
+ u32 __res = resp[__off] >> __shft;
+
+ if (__size + __shft > 32)
+ __res |= resp[__off - 1] << ((32 - __shft) % 32);
+
+ return __res & __mask;
+}
#endif
diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c
index 7a304a6e5bf1..01d1e62c2ce7 100644
--- a/drivers/mmc/core/mmc_test.c
+++ b/drivers/mmc/core/mmc_test.c
@@ -1,10 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2007-2008 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#include <linux/mmc/core.h>
@@ -14,7 +10,6 @@
#include <linux/slab.h>
#include <linux/scatterlist.h>
-#include <linux/swap.h> /* For nr_free_buffer_pages() */
#include <linux/list.h>
#include <linux/debugfs.h>
@@ -75,6 +70,7 @@ struct mmc_test_mem {
* @sg_len: length of currently mapped scatterlist @sg
* @mem: allocated memory
* @sg: scatterlist
+ * @sg_areq: scatterlist for non-blocking request
*/
struct mmc_test_area {
unsigned long max_sz;
@@ -86,6 +82,7 @@ struct mmc_test_area {
unsigned int sg_len;
struct mmc_test_mem *mem;
struct scatterlist *sg;
+ struct scatterlist *sg_areq;
};
/**
@@ -101,7 +98,7 @@ struct mmc_test_transfer_result {
struct list_head link;
unsigned int count;
unsigned int sectors;
- struct timespec ts;
+ struct timespec64 ts;
unsigned int rate;
unsigned int iops;
};
@@ -171,11 +168,6 @@ struct mmc_test_multiple_rw {
enum mmc_test_prep_media prepare;
};
-struct mmc_test_async_req {
- struct mmc_async_req areq;
- struct mmc_test_card *test;
-};
-
/*******************************************************************/
/* General helper functions */
/*******************************************************************/
@@ -188,20 +180,14 @@ static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
return mmc_set_blocklen(test->card, size);
}
-static bool mmc_test_card_cmd23(struct mmc_card *card)
-{
- return mmc_card_mmc(card) ||
- (mmc_card_sd(card) && card->scr.cmds & SD_SCR_CMD23_SUPPORT);
-}
-
static void mmc_test_prepare_sbc(struct mmc_test_card *test,
struct mmc_request *mrq, unsigned int blocks)
{
struct mmc_card *card = test->card;
- if (!mrq->sbc || !mmc_host_cmd23(card->host) ||
- !mmc_test_card_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) ||
- (card->quirks & MMC_QUIRK_BLK_NO_CMD23)) {
+ if (!mrq->sbc || !mmc_host_can_cmd23(card->host) ||
+ !mmc_card_can_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) ||
+ mmc_card_blk_no_cmd23(card)) {
mrq->sbc = NULL;
return;
}
@@ -515,14 +501,11 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
/*
* Calculate transfer rate in bytes per second.
*/
-static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
+static unsigned int mmc_test_rate(uint64_t bytes, struct timespec64 *ts)
{
uint64_t ns;
- ns = ts->tv_sec;
- ns *= 1000000000;
- ns += ts->tv_nsec;
-
+ ns = timespec64_to_ns(ts);
bytes *= 1000000000;
while (ns > UINT_MAX) {
@@ -542,7 +525,7 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
* Save transfer results for future usage
*/
static void mmc_test_save_transfer_result(struct mmc_test_card *test,
- unsigned int count, unsigned int sectors, struct timespec ts,
+ unsigned int count, unsigned int sectors, struct timespec64 ts,
unsigned int rate, unsigned int iops)
{
struct mmc_test_transfer_result *tr;
@@ -567,21 +550,21 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test,
* Print the transfer rate.
*/
static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
- struct timespec *ts1, struct timespec *ts2)
+ struct timespec64 *ts1, struct timespec64 *ts2)
{
unsigned int rate, iops, sectors = bytes >> 9;
- struct timespec ts;
+ struct timespec64 ts;
- ts = timespec_sub(*ts2, *ts1);
+ ts = timespec64_sub(*ts2, *ts1);
rate = mmc_test_rate(bytes, &ts);
iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */
- pr_info("%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
+ pr_info("%s: Transfer of %u sectors (%u%s KiB) took %llu.%09u "
"seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n",
mmc_hostname(test->card->host), sectors, sectors >> 1,
- (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
- (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024,
+ (sectors & 1 ? ".5" : ""), (u64)ts.tv_sec,
+ (u32)ts.tv_nsec, rate / 1000, rate / 1024,
iops / 100, iops % 100);
mmc_test_save_transfer_result(test, 1, sectors, ts, rate, iops);
@@ -591,26 +574,23 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
* Print the average transfer rate.
*/
static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
- unsigned int count, struct timespec *ts1,
- struct timespec *ts2)
+ unsigned int count, struct timespec64 *ts1,
+ struct timespec64 *ts2)
{
unsigned int rate, iops, sectors = bytes >> 9;
uint64_t tot = bytes * count;
- struct timespec ts;
+ struct timespec64 ts;
- ts = timespec_sub(*ts2, *ts1);
+ ts = timespec64_sub(*ts2, *ts1);
rate = mmc_test_rate(tot, &ts);
iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */
- pr_info("%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
- "%lu.%09lu seconds (%u kB/s, %u KiB/s, "
- "%u.%02u IOPS, sg_len %d)\n",
- mmc_hostname(test->card->host), count, sectors, count,
- sectors >> 1, (sectors & 1 ? ".5" : ""),
- (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
- rate / 1000, rate / 1024, iops / 100, iops % 100,
- test->area.sg_len);
+ pr_info("%s: Transfer of %u x %u sectors (%u x %u%s KiB) took %ptSp seconds (%u kB/s, %u KiB/s, %u.%02u IOPS, sg_len %d)\n",
+ mmc_hostname(test->card->host), count, sectors, count,
+ sectors >> 1, (sectors & 1 ? ".5" : ""), &ts,
+ rate / 1000, rate / 1024, iops / 100, iops % 100,
+ test->area.sg_len);
mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
}
@@ -634,7 +614,7 @@ static unsigned int mmc_test_capacity(struct mmc_card *card)
* Fill the first couple of sectors of the card with known data
* so that bad reads/writes can be detected
*/
-static int __mmc_test_prepare(struct mmc_test_card *test, int write)
+static int __mmc_test_prepare(struct mmc_test_card *test, int write, int val)
{
int ret, i;
@@ -643,7 +623,7 @@ static int __mmc_test_prepare(struct mmc_test_card *test, int write)
return ret;
if (write)
- memset(test->buffer, 0xDF, 512);
+ memset(test->buffer, val, 512);
else {
for (i = 0; i < 512; i++)
test->buffer[i] = i;
@@ -660,31 +640,17 @@ static int __mmc_test_prepare(struct mmc_test_card *test, int write)
static int mmc_test_prepare_write(struct mmc_test_card *test)
{
- return __mmc_test_prepare(test, 1);
+ return __mmc_test_prepare(test, 1, 0xDF);
}
static int mmc_test_prepare_read(struct mmc_test_card *test)
{
- return __mmc_test_prepare(test, 0);
+ return __mmc_test_prepare(test, 0, 0);
}
static int mmc_test_cleanup(struct mmc_test_card *test)
{
- int ret, i;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- memset(test->buffer, 0, 512);
-
- for (i = 0; i < BUFFER_SIZE / 512; i++) {
- ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
- if (ret)
- return ret;
- }
-
- return 0;
+ return __mmc_test_prepare(test, 1, 0);
}
/*******************************************************************/
@@ -741,30 +707,6 @@ static int mmc_test_check_result(struct mmc_test_card *test,
return ret;
}
-static enum mmc_blk_status mmc_test_check_result_async(struct mmc_card *card,
- struct mmc_async_req *areq)
-{
- struct mmc_test_async_req *test_async =
- container_of(areq, struct mmc_test_async_req, areq);
- int ret;
-
- mmc_test_wait_busy(test_async->test);
-
- /*
- * FIXME: this would earlier just casts a regular error code,
- * either of the kernel type -ERRORCODE or the local test framework
- * RESULT_* errorcode, into an enum mmc_blk_status and return as
- * result check. Instead, convert it to some reasonable type by just
- * returning either MMC_BLK_SUCCESS or MMC_BLK_CMD_ERR.
- * If possible, a reasonable error code should be returned.
- */
- ret = mmc_test_check_result(test_async->test, areq->mrq);
- if (ret)
- return MMC_BLK_CMD_ERR;
-
- return MMC_BLK_SUCCESS;
-}
-
/*
* Checks that a "short transfer" behaved as expected
*/
@@ -800,85 +742,119 @@ static int mmc_test_check_broken_result(struct mmc_test_card *test,
return ret;
}
+struct mmc_test_req {
+ struct mmc_request mrq;
+ struct mmc_command sbc;
+ struct mmc_command cmd;
+ struct mmc_command stop;
+ struct mmc_command status;
+ struct mmc_data data;
+};
+
/*
* Tests nonblock transfer with certain parameters
*/
-static void mmc_test_nonblock_reset(struct mmc_request *mrq,
- struct mmc_command *cmd,
- struct mmc_command *stop,
- struct mmc_data *data)
+static void mmc_test_req_reset(struct mmc_test_req *rq)
+{
+ memset(rq, 0, sizeof(struct mmc_test_req));
+
+ rq->mrq.cmd = &rq->cmd;
+ rq->mrq.data = &rq->data;
+ rq->mrq.stop = &rq->stop;
+}
+
+static struct mmc_test_req *mmc_test_req_alloc(void)
{
- memset(mrq, 0, sizeof(struct mmc_request));
- memset(cmd, 0, sizeof(struct mmc_command));
- memset(data, 0, sizeof(struct mmc_data));
- memset(stop, 0, sizeof(struct mmc_command));
+ struct mmc_test_req *rq = kmalloc(sizeof(*rq), GFP_KERNEL);
+
+ if (rq)
+ mmc_test_req_reset(rq);
+
+ return rq;
+}
+
+static void mmc_test_wait_done(struct mmc_request *mrq)
+{
+ complete(&mrq->completion);
+}
+
+static int mmc_test_start_areq(struct mmc_test_card *test,
+ struct mmc_request *mrq,
+ struct mmc_request *prev_mrq)
+{
+ struct mmc_host *host = test->card->host;
+ int err = 0;
+
+ if (mrq) {
+ init_completion(&mrq->completion);
+ mrq->done = mmc_test_wait_done;
+ mmc_pre_req(host, mrq);
+ }
+
+ if (prev_mrq) {
+ wait_for_completion(&prev_mrq->completion);
+ err = mmc_test_wait_busy(test);
+ if (!err)
+ err = mmc_test_check_result(test, prev_mrq);
+ }
+
+ if (!err && mrq) {
+ err = mmc_start_request(host, mrq);
+ if (err)
+ mmc_retune_release(host);
+ }
- mrq->cmd = cmd;
- mrq->data = data;
- mrq->stop = stop;
+ if (prev_mrq)
+ mmc_post_req(host, prev_mrq, 0);
+
+ if (err && mrq)
+ mmc_post_req(host, mrq, err);
+
+ return err;
}
+
static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
- struct scatterlist *sg, unsigned sg_len,
- unsigned dev_addr, unsigned blocks,
- unsigned blksz, int write, int count)
-{
- struct mmc_request mrq1;
- struct mmc_command cmd1;
- struct mmc_command stop1;
- struct mmc_data data1;
-
- struct mmc_request mrq2;
- struct mmc_command cmd2;
- struct mmc_command stop2;
- struct mmc_data data2;
-
- struct mmc_test_async_req test_areq[2];
- struct mmc_async_req *done_areq;
- struct mmc_async_req *cur_areq = &test_areq[0].areq;
- struct mmc_async_req *other_areq = &test_areq[1].areq;
- enum mmc_blk_status status;
+ unsigned int dev_addr, int write,
+ int count)
+{
+ struct mmc_test_req *rq1, *rq2;
+ struct mmc_request *mrq, *prev_mrq;
int i;
int ret = RESULT_OK;
+ struct mmc_test_area *t = &test->area;
+ struct scatterlist *sg = t->sg;
+ struct scatterlist *sg_areq = t->sg_areq;
- test_areq[0].test = test;
- test_areq[1].test = test;
-
- mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
- mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
+ rq1 = mmc_test_req_alloc();
+ rq2 = mmc_test_req_alloc();
+ if (!rq1 || !rq2) {
+ ret = RESULT_FAIL;
+ goto err;
+ }
- cur_areq->mrq = &mrq1;
- cur_areq->err_check = mmc_test_check_result_async;
- other_areq->mrq = &mrq2;
- other_areq->err_check = mmc_test_check_result_async;
+ mrq = &rq1->mrq;
+ prev_mrq = NULL;
for (i = 0; i < count; i++) {
- mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
- blocks, blksz, write);
- done_areq = mmc_start_areq(test->card->host, cur_areq, &status);
-
- if (status != MMC_BLK_SUCCESS || (!done_areq && i > 0)) {
- ret = RESULT_FAIL;
+ mmc_test_req_reset(container_of(mrq, struct mmc_test_req, mrq));
+ mmc_test_prepare_mrq(test, mrq, sg, t->sg_len, dev_addr,
+ t->blocks, 512, write);
+ ret = mmc_test_start_areq(test, mrq, prev_mrq);
+ if (ret)
goto err;
- }
- if (done_areq) {
- if (done_areq->mrq == &mrq2)
- mmc_test_nonblock_reset(&mrq2, &cmd2,
- &stop2, &data2);
- else
- mmc_test_nonblock_reset(&mrq1, &cmd1,
- &stop1, &data1);
- }
- swap(cur_areq, other_areq);
- dev_addr += blocks;
- }
+ if (!prev_mrq)
+ prev_mrq = &rq2->mrq;
- done_areq = mmc_start_areq(test->card->host, NULL, &status);
- if (status != MMC_BLK_SUCCESS)
- ret = RESULT_FAIL;
+ swap(mrq, prev_mrq);
+ swap(sg, sg_areq);
+ dev_addr += t->blocks;
+ }
- return ret;
+ ret = mmc_test_start_areq(test, NULL, prev_mrq);
err:
+ kfree(rq1);
+ kfree(rq2);
return ret;
}
@@ -947,7 +923,6 @@ static int mmc_test_transfer(struct mmc_test_card *test,
unsigned blocks, unsigned blksz, int write)
{
int ret, i;
- unsigned long flags;
if (write) {
for (i = 0; i < blocks * blksz; i++)
@@ -955,9 +930,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
} else {
memset(test->scratch, 0, BUFFER_SIZE);
}
- local_irq_save(flags);
sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
- local_irq_restore(flags);
ret = mmc_test_set_blksize(test, blksz);
if (ret)
@@ -1002,9 +975,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
return RESULT_FAIL;
}
} else {
- local_irq_save(flags);
sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
- local_irq_restore(flags);
for (i = 0; i < blocks * blksz; i++) {
if (test->scratch[i] != (u8)i)
return RESULT_FAIL;
@@ -1401,10 +1372,11 @@ static int mmc_test_no_highmem(struct mmc_test_card *test)
* Map sz bytes so that it can be transferred.
*/
static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
- int max_scatter, int min_sg_len)
+ int max_scatter, int min_sg_len, bool nonblock)
{
struct mmc_test_area *t = &test->area;
int err;
+ unsigned int sg_len = 0;
t->blocks = sz >> 9;
@@ -1416,6 +1388,22 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
t->max_seg_sz, &t->sg_len, min_sg_len);
}
+
+ if (err || !nonblock)
+ goto err;
+
+ if (max_scatter) {
+ err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg_areq,
+ t->max_segs, t->max_seg_sz,
+ &sg_len);
+ } else {
+ err = mmc_test_map_sg(t->mem, sz, t->sg_areq, 1, t->max_segs,
+ t->max_seg_sz, &sg_len, min_sg_len);
+ }
+ if (!err && sg_len != t->sg_len)
+ err = -EINVAL;
+
+err:
if (err)
pr_info("%s: Failed to map sg list\n",
mmc_hostname(test->card->host));
@@ -1442,10 +1430,9 @@ static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
int max_scatter, int timed, int count,
bool nonblock, int min_sg_len)
{
- struct timespec ts1, ts2;
+ struct timespec64 ts1, ts2;
int ret = 0;
int i;
- struct mmc_test_area *t = &test->area;
/*
* In the case of a maximally scattered transfer, the maximum transfer
@@ -1463,15 +1450,14 @@ static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
sz = max_tfr;
}
- ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len);
+ ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len, nonblock);
if (ret)
return ret;
if (timed)
- getnstimeofday(&ts1);
+ ktime_get_ts64(&ts1);
if (nonblock)
- ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len,
- dev_addr, t->blocks, 512, write, count);
+ ret = mmc_test_nonblock_transfer(test, dev_addr, write, count);
else
for (i = 0; i < count && ret == 0; i++) {
ret = mmc_test_area_transfer(test, dev_addr, write);
@@ -1482,7 +1468,7 @@ static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
return ret;
if (timed)
- getnstimeofday(&ts2);
+ ktime_get_ts64(&ts2);
if (timed)
mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2);
@@ -1515,7 +1501,7 @@ static int mmc_test_area_erase(struct mmc_test_card *test)
{
struct mmc_test_area *t = &test->area;
- if (!mmc_can_erase(test->card))
+ if (!mmc_card_can_erase(test->card))
return 0;
return mmc_erase(test->card, t->dev_addr, t->max_sz >> 9,
@@ -1530,6 +1516,7 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test)
struct mmc_test_area *t = &test->area;
kfree(t->sg);
+ kfree(t->sg_areq);
mmc_test_free_mem(t->mem);
return 0;
@@ -1589,6 +1576,13 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
goto out_free;
}
+ t->sg_areq = kmalloc_array(t->max_segs, sizeof(*t->sg_areq),
+ GFP_KERNEL);
+ if (!t->sg_areq) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
t->dev_addr = mmc_test_capacity(test->card) / 2;
t->dev_addr -= t->dev_addr % (t->max_sz >> 9);
@@ -1740,30 +1734,30 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
struct mmc_test_area *t = &test->area;
unsigned long sz;
unsigned int dev_addr;
- struct timespec ts1, ts2;
+ struct timespec64 ts1, ts2;
int ret;
- if (!mmc_can_trim(test->card))
+ if (!mmc_card_can_trim(test->card))
return RESULT_UNSUP_CARD;
- if (!mmc_can_erase(test->card))
+ if (!mmc_card_can_erase(test->card))
return RESULT_UNSUP_HOST;
for (sz = 512; sz < t->max_sz; sz <<= 1) {
dev_addr = t->dev_addr + (sz >> 9);
- getnstimeofday(&ts1);
+ ktime_get_ts64(&ts1);
ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
if (ret)
return ret;
- getnstimeofday(&ts2);
+ ktime_get_ts64(&ts2);
mmc_test_print_rate(test, sz, &ts1, &ts2);
}
dev_addr = t->dev_addr;
- getnstimeofday(&ts1);
+ ktime_get_ts64(&ts1);
ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
if (ret)
return ret;
- getnstimeofday(&ts2);
+ ktime_get_ts64(&ts2);
mmc_test_print_rate(test, sz, &ts1, &ts2);
return 0;
}
@@ -1772,19 +1766,19 @@ static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
{
struct mmc_test_area *t = &test->area;
unsigned int dev_addr, i, cnt;
- struct timespec ts1, ts2;
+ struct timespec64 ts1, ts2;
int ret;
cnt = t->max_sz / sz;
dev_addr = t->dev_addr;
- getnstimeofday(&ts1);
+ ktime_get_ts64(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
if (ret)
return ret;
dev_addr += (sz >> 9);
}
- getnstimeofday(&ts2);
+ ktime_get_ts64(&ts2);
mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
return 0;
}
@@ -1811,7 +1805,7 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
{
struct mmc_test_area *t = &test->area;
unsigned int dev_addr, i, cnt;
- struct timespec ts1, ts2;
+ struct timespec64 ts1, ts2;
int ret;
ret = mmc_test_area_erase(test);
@@ -1819,14 +1813,14 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
return ret;
cnt = t->max_sz / sz;
dev_addr = t->dev_addr;
- getnstimeofday(&ts1);
+ ktime_get_ts64(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
if (ret)
return ret;
dev_addr += (sz >> 9);
}
- getnstimeofday(&ts2);
+ ktime_get_ts64(&ts2);
mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
return 0;
}
@@ -1857,13 +1851,13 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
struct mmc_test_area *t = &test->area;
unsigned long sz;
unsigned int dev_addr, i, cnt;
- struct timespec ts1, ts2;
+ struct timespec64 ts1, ts2;
int ret;
- if (!mmc_can_trim(test->card))
+ if (!mmc_card_can_trim(test->card))
return RESULT_UNSUP_CARD;
- if (!mmc_can_erase(test->card))
+ if (!mmc_card_can_erase(test->card))
return RESULT_UNSUP_HOST;
for (sz = 512; sz <= t->max_sz; sz <<= 1) {
@@ -1875,7 +1869,7 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
return ret;
cnt = t->max_sz / sz;
dev_addr = t->dev_addr;
- getnstimeofday(&ts1);
+ ktime_get_ts64(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_erase(test->card, dev_addr, sz >> 9,
MMC_TRIM_ARG);
@@ -1883,7 +1877,7 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
return ret;
dev_addr += (sz >> 9);
}
- getnstimeofday(&ts2);
+ ktime_get_ts64(&ts2);
mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
}
return 0;
@@ -1901,11 +1895,11 @@ static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt)
}
static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
- unsigned long sz)
+ unsigned long sz, int secs, int force_retuning)
{
unsigned int dev_addr, cnt, rnd_addr, range1, range2, last_ea = 0, ea;
unsigned int ssz;
- struct timespec ts1, ts2, ts;
+ struct timespec64 ts1, ts2, ts;
int ret;
ssz = sz >> 9;
@@ -1914,11 +1908,11 @@ static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
range1 = rnd_addr / test->card->pref_erase;
range2 = range1 / ssz;
- getnstimeofday(&ts1);
+ ktime_get_ts64(&ts1);
for (cnt = 0; cnt < UINT_MAX; cnt++) {
- getnstimeofday(&ts2);
- ts = timespec_sub(ts2, ts1);
- if (ts.tv_sec >= 10)
+ ktime_get_ts64(&ts2);
+ ts = timespec64_sub(ts2, ts1);
+ if (ts.tv_sec >= secs)
break;
ea = mmc_test_rnd_num(range1);
if (ea == last_ea)
@@ -1926,6 +1920,8 @@ static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
last_ea = ea;
dev_addr = rnd_addr + test->card->pref_erase * ea +
ssz * mmc_test_rnd_num(range2);
+ if (force_retuning)
+ mmc_retune_needed(test->card->host);
ret = mmc_test_area_io(test, sz, dev_addr, write, 0, 0);
if (ret)
return ret;
@@ -1950,24 +1946,35 @@ static int mmc_test_random_perf(struct mmc_test_card *test, int write)
*/
if (write) {
next = rnd_next;
- ret = mmc_test_rnd_perf(test, write, 0, sz);
+ ret = mmc_test_rnd_perf(test, write, 0, sz, 10, 0);
if (ret)
return ret;
rnd_next = next;
}
- ret = mmc_test_rnd_perf(test, write, 1, sz);
+ ret = mmc_test_rnd_perf(test, write, 1, sz, 10, 0);
if (ret)
return ret;
}
sz = t->max_tfr;
if (write) {
next = rnd_next;
- ret = mmc_test_rnd_perf(test, write, 0, sz);
+ ret = mmc_test_rnd_perf(test, write, 0, sz, 10, 0);
if (ret)
return ret;
rnd_next = next;
}
- return mmc_test_rnd_perf(test, write, 1, sz);
+ return mmc_test_rnd_perf(test, write, 1, sz, 10, 0);
+}
+
+static int mmc_test_retuning(struct mmc_test_card *test)
+{
+ if (!mmc_can_retune(test->card->host)) {
+ pr_info("%s: No retuning - test skipped\n",
+ mmc_hostname(test->card->host));
+ return RESULT_UNSUP_HOST;
+ }
+
+ return mmc_test_rnd_perf(test, 0, 0, 8192, 30, 1);
}
/*
@@ -1991,7 +1998,7 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
{
struct mmc_test_area *t = &test->area;
unsigned int dev_addr, i, cnt, sz, ssz;
- struct timespec ts1, ts2;
+ struct timespec64 ts1, ts2;
int ret;
sz = t->max_tfr;
@@ -2018,7 +2025,7 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
cnt = tot_sz / sz;
dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
- getnstimeofday(&ts1);
+ ktime_get_ts64(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_test_area_io(test, sz, dev_addr, write,
max_scatter, 0);
@@ -2026,7 +2033,7 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
return ret;
dev_addr += ssz;
}
- getnstimeofday(&ts2);
+ ktime_get_ts64(&ts2);
mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
@@ -2098,10 +2105,10 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test,
return 0;
/* prepare test area */
- if (mmc_can_erase(test->card) &&
+ if (mmc_card_can_erase(test->card) &&
tdata->prepare & MMC_TEST_PREP_ERASE) {
ret = mmc_erase(test->card, dev_addr,
- size / 512, MMC_SECURE_ERASE_ARG);
+ size / 512, test->card->erase_arg);
if (ret)
ret = mmc_erase(test->card, dev_addr,
size / 512, MMC_ERASE_ARG);
@@ -2317,38 +2324,22 @@ static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
static int mmc_test_reset(struct mmc_test_card *test)
{
struct mmc_card *card = test->card;
- struct mmc_host *host = card->host;
int err;
- err = mmc_hw_reset(host);
- if (!err)
+ err = mmc_hw_reset(card);
+ if (!err) {
+ /*
+ * Reset will re-enable the card's command queue, but tests
+ * expect it to be disabled.
+ */
+ if (card->ext_csd.cmdq_en)
+ mmc_cmdq_disable(card);
return RESULT_OK;
- else if (err == -EOPNOTSUPP)
+ } else if (err == -EOPNOTSUPP) {
return RESULT_UNSUP_HOST;
-
- return RESULT_FAIL;
-}
-
-struct mmc_test_req {
- struct mmc_request mrq;
- struct mmc_command sbc;
- struct mmc_command cmd;
- struct mmc_command stop;
- struct mmc_command status;
- struct mmc_data data;
-};
-
-static struct mmc_test_req *mmc_test_req_alloc(void)
-{
- struct mmc_test_req *rq = kzalloc(sizeof(*rq), GFP_KERNEL);
-
- if (rq) {
- rq->mrq.cmd = &rq->cmd;
- rq->mrq.data = &rq->data;
- rq->mrq.stop = &rq->stop;
}
- return rq;
+ return RESULT_FAIL;
}
static int mmc_test_send_status(struct mmc_test_card *test,
@@ -2371,11 +2362,9 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
struct mmc_test_req *rq = mmc_test_req_alloc();
struct mmc_host *host = test->card->host;
struct mmc_test_area *t = &test->area;
- struct mmc_test_async_req test_areq = { .test = test };
struct mmc_request *mrq;
unsigned long timeout;
bool expired = false;
- enum mmc_blk_status blkstat = MMC_BLK_SUCCESS;
int ret = 0, cmd_ret;
u32 status = 0;
int count = 0;
@@ -2388,14 +2377,11 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
mrq->sbc = &rq->sbc;
mrq->cap_cmd_during_tfr = true;
- test_areq.areq.mrq = mrq;
- test_areq.areq.err_check = mmc_test_check_result_async;
-
mmc_test_prepare_mrq(test, mrq, t->sg, t->sg_len, dev_addr, t->blocks,
512, write);
if (use_sbc && t->blocks > 1 && !mrq->sbc) {
- ret = mmc_host_cmd23(host) ?
+ ret = mmc_host_can_cmd23(host) ?
RESULT_UNSUP_CARD :
RESULT_UNSUP_HOST;
goto out_free;
@@ -2403,11 +2389,9 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
/* Start ongoing data request */
if (use_areq) {
- mmc_start_areq(host, &test_areq.areq, &blkstat);
- if (blkstat != MMC_BLK_SUCCESS) {
- ret = RESULT_FAIL;
+ ret = mmc_test_start_areq(test, mrq, NULL);
+ if (ret)
goto out_free;
- }
} else {
mmc_wait_for_req(host, mrq);
}
@@ -2441,9 +2425,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
/* Wait for data request to complete */
if (use_areq) {
- mmc_start_areq(host, NULL, &blkstat);
- if (blkstat != MMC_BLK_SUCCESS)
- ret = RESULT_FAIL;
+ ret = mmc_test_start_areq(test, NULL, mrq);
} else {
mmc_wait_for_req_done(test->card->host, mrq);
}
@@ -2497,7 +2479,7 @@ static int __mmc_test_cmds_during_tfr(struct mmc_test_card *test,
if (!(test->card->host->caps & MMC_CAP_CMD_DURING_TFR))
return RESULT_UNSUP_HOST;
- ret = mmc_test_area_map(test, sz, 0, 0);
+ ret = mmc_test_area_map(test, sz, 0, 0, use_areq);
if (ret)
return ret;
@@ -2670,22 +2652,22 @@ static const struct mmc_test_case mmc_test_cases[] = {
},
{
- .name = "Correct xfer_size at write (start failure)",
+ .name = "Proper xfer_size at write (start failure)",
.run = mmc_test_xfersize_write,
},
{
- .name = "Correct xfer_size at read (start failure)",
+ .name = "Proper xfer_size at read (start failure)",
.run = mmc_test_xfersize_read,
},
{
- .name = "Correct xfer_size at write (midway failure)",
+ .name = "Proper xfer_size at write (midway failure)",
.run = mmc_test_multi_xfersize_write,
},
{
- .name = "Correct xfer_size at read (midway failure)",
+ .name = "Proper xfer_size at read (midway failure)",
.run = mmc_test_multi_xfersize_read,
},
@@ -2943,6 +2925,14 @@ static const struct mmc_test_case mmc_test_cases[] = {
.run = mmc_test_cmds_during_write_cmd23_nonblock,
.cleanup = mmc_test_area_cleanup,
},
+
+ {
+ .name = "Re-tuning reliability",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_retuning,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
};
static DEFINE_MUTEX(mmc_test_lock);
@@ -3067,7 +3057,7 @@ static LIST_HEAD(mmc_test_file_test);
static int mtf_test_show(struct seq_file *sf, void *data)
{
- struct mmc_card *card = (struct mmc_card *)sf->private;
+ struct mmc_card *card = sf->private;
struct mmc_test_general_result *gr;
mutex_lock(&mmc_test_lock);
@@ -3081,11 +3071,9 @@ static int mtf_test_show(struct seq_file *sf, void *data)
seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result);
list_for_each_entry(tr, &gr->tr_lst, link) {
- seq_printf(sf, "%u %d %lu.%09lu %u %u.%02u\n",
- tr->count, tr->sectors,
- (unsigned long)tr->ts.tv_sec,
- (unsigned long)tr->ts.tv_nsec,
- tr->rate, tr->iops / 100, tr->iops % 100);
+ seq_printf(sf, "%u %d %ptSp %u %u.%02u\n",
+ tr->count, tr->sectors, &tr->ts, tr->rate,
+ tr->iops / 100, tr->iops % 100);
}
}
@@ -3102,8 +3090,8 @@ static int mtf_test_open(struct inode *inode, struct file *file)
static ssize_t mtf_test_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
- struct seq_file *sf = (struct seq_file *)file->private_data;
- struct mmc_card *card = (struct mmc_card *)sf->private;
+ struct seq_file *sf = file->private_data;
+ struct mmc_card *card = sf->private;
struct mmc_test_card *test;
long testcase;
int ret;
@@ -3127,13 +3115,13 @@ static ssize_t mtf_test_write(struct file *file, const char __user *buf,
test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
#ifdef CONFIG_HIGHMEM
test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER);
+ if (!test->highmem) {
+ count = -ENOMEM;
+ goto free_test_buffer;
+ }
#endif
-#ifdef CONFIG_HIGHMEM
- if (test->buffer && test->highmem) {
-#else
if (test->buffer) {
-#endif
mutex_lock(&mmc_test_lock);
mmc_test_run(test, testcase);
mutex_unlock(&mmc_test_lock);
@@ -3141,6 +3129,7 @@ static ssize_t mtf_test_write(struct file *file, const char __user *buf,
#ifdef CONFIG_HIGHMEM
__free_pages(test->highmem, BUFFER_ORDER);
+free_test_buffer:
#endif
kfree(test->buffer);
kfree(test);
@@ -3171,17 +3160,7 @@ static int mtf_testlist_show(struct seq_file *sf, void *data)
return 0;
}
-static int mtf_testlist_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mtf_testlist_show, inode->i_private);
-}
-
-static const struct file_operations mmc_test_fops_testlist = {
- .open = mtf_testlist_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mtf_testlist);
static void mmc_test_free_dbgfs_file(struct mmc_card *card)
{
@@ -3208,14 +3187,7 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
if (card->debugfs_root)
file = debugfs_create_file(name, mode, card->debugfs_root,
- card, fops);
-
- if (IS_ERR_OR_NULL(file)) {
- dev_err(&card->dev,
- "Can't create %s. Perhaps debugfs is disabled.\n",
- name);
- return -ENODEV;
- }
+ card, fops);
df = kmalloc(sizeof(*df), GFP_KERNEL);
if (!df) {
@@ -3236,13 +3208,13 @@ static int mmc_test_register_dbgfs_file(struct mmc_card *card)
mutex_lock(&mmc_test_lock);
- ret = __mmc_test_register_dbgfs_file(card, "test", S_IWUSR | S_IRUGO,
+ ret = __mmc_test_register_dbgfs_file(card, "test", 0644,
&mmc_test_fops_test);
if (ret)
goto err;
- ret = __mmc_test_register_dbgfs_file(card, "testlist", S_IRUGO,
- &mmc_test_fops_testlist);
+ ret = __mmc_test_register_dbgfs_file(card, "testlist", 0444,
+ &mtf_testlist_fops);
if (ret)
goto err;
@@ -3259,6 +3231,12 @@ static int mmc_test_probe(struct mmc_card *card)
if (!mmc_card_mmc(card) && !mmc_card_sd(card))
return -ENODEV;
+ if (mmc_card_ult_capacity(card)) {
+ pr_info("%s: mmc-test currently UNSUPPORTED for SDUC\n",
+ mmc_hostname(card->host));
+ return -EOPNOTSUPP;
+ }
+
ret = mmc_test_register_dbgfs_file(card);
if (ret)
return ret;
@@ -3287,17 +3265,12 @@ static void mmc_test_remove(struct mmc_card *card)
mmc_test_free_dbgfs_file(card);
}
-static void mmc_test_shutdown(struct mmc_card *card)
-{
-}
-
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmc_test",
},
.probe = mmc_test_probe,
.remove = mmc_test_remove,
- .shutdown = mmc_test_shutdown,
};
static int __init mmc_test_init(void)
diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c
index e3ad30fa8307..2374669b588a 100644
--- a/drivers/mmc/core/pwrseq.c
+++ b/drivers/mmc/core/pwrseq.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Linaro Ltd
*
* Author: Ulf Hansson <ulf.hansson@linaro.org>
*
- * License terms: GNU General Public License (GPL) version 2
- *
* MMC power sequence management
*/
#include <linux/kernel.h>
@@ -30,7 +29,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
mutex_lock(&pwrseq_list_mutex);
list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
- if (p->dev->of_node == np) {
+ if (device_match_of_node(p->dev, np)) {
if (!try_module_get(p->owner))
dev_err(host->parent,
"increasing module refcount failed\n");
diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h
index 819386f4ec61..f3bb103db9ad 100644
--- a/drivers/mmc/core/pwrseq.h
+++ b/drivers/mmc/core/pwrseq.h
@@ -1,9 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2014 Linaro Ltd
*
* Author: Ulf Hansson <ulf.hansson@linaro.org>
- *
- * License terms: GNU General Public License (GPL) version 2
*/
#ifndef _MMC_CORE_PWRSEQ_H
#define _MMC_CORE_PWRSEQ_H
diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
index efb8a7965dd4..35af67e26945 100644
--- a/drivers/mmc/core/pwrseq_emmc.c
+++ b/drivers/mmc/core/pwrseq_emmc.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015, Samsung Electronics Co., Ltd.
*
* Author: Marek Szyprowski <m.szyprowski@samsung.com>
*
- * License terms: GNU General Public License (GPL) version 2
- *
* Simple eMMC hardware reset provider
*/
#include <linux/delay.h>
@@ -30,19 +29,14 @@ struct mmc_pwrseq_emmc {
#define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq)
-static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
-{
- gpiod_set_value(pwrseq->reset_gpio, 1);
- udelay(1);
- gpiod_set_value(pwrseq->reset_gpio, 0);
- udelay(200);
-}
-
static void mmc_pwrseq_emmc_reset(struct mmc_host *host)
{
struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq);
- __mmc_pwrseq_emmc_reset(pwrseq);
+ gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
+ udelay(1);
+ gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
+ udelay(200);
}
static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
@@ -50,8 +44,11 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
{
struct mmc_pwrseq_emmc *pwrseq = container_of(this,
struct mmc_pwrseq_emmc, reset_nb);
+ gpiod_set_value(pwrseq->reset_gpio, 1);
+ udelay(1);
+ gpiod_set_value(pwrseq->reset_gpio, 0);
+ udelay(200);
- __mmc_pwrseq_emmc_reset(pwrseq);
return NOTIFY_DONE;
}
@@ -72,14 +69,18 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
if (IS_ERR(pwrseq->reset_gpio))
return PTR_ERR(pwrseq->reset_gpio);
- /*
- * register reset handler to ensure emmc reset also from
- * emergency_reboot(), priority 255 is the highest priority
- * so it will be executed before any system reboot handler.
- */
- pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb;
- pwrseq->reset_nb.priority = 255;
- register_restart_handler(&pwrseq->reset_nb);
+ if (!gpiod_cansleep(pwrseq->reset_gpio)) {
+ /*
+ * register reset handler to ensure emmc reset also from
+ * emergency_reboot(), priority 255 is the highest priority
+ * so it will be executed before any system reboot handler.
+ */
+ pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb;
+ pwrseq->reset_nb.priority = 255;
+ register_restart_handler(&pwrseq->reset_nb);
+ } else {
+ dev_notice(dev, "EMMC reset pin tied to a sleepy GPIO driver; reset on emergency-reboot disabled\n");
+ }
pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
pwrseq->pwrseq.dev = dev;
@@ -89,14 +90,12 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
return mmc_pwrseq_register(&pwrseq->pwrseq);
}
-static int mmc_pwrseq_emmc_remove(struct platform_device *pdev)
+static void mmc_pwrseq_emmc_remove(struct platform_device *pdev)
{
struct mmc_pwrseq_emmc *pwrseq = platform_get_drvdata(pdev);
unregister_restart_handler(&pwrseq->reset_nb);
mmc_pwrseq_unregister(&pwrseq->pwrseq);
-
- return 0;
}
static const struct of_device_id mmc_pwrseq_emmc_of_match[] = {
@@ -116,4 +115,5 @@ static struct platform_driver mmc_pwrseq_emmc_driver = {
};
module_platform_driver(mmc_pwrseq_emmc_driver);
+MODULE_DESCRIPTION("Hardware reset support for eMMC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/core/pwrseq_sd8787.c b/drivers/mmc/core/pwrseq_sd8787.c
index 1a21e14458d3..30282155a0e1 100644
--- a/drivers/mmc/core/pwrseq_sd8787.c
+++ b/drivers/mmc/core/pwrseq_sd8787.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* pwrseq_sd8787.c - power sequence support for Marvell SD8787 BT + Wifi chip
*
@@ -6,17 +7,6 @@
* Based on the original work pwrseq_simple.c
* Copyright (C) 2014 Linaro Ltd
* Author: Ulf Hansson <ulf.hansson@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/delay.h>
@@ -24,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -59,13 +50,37 @@ static void mmc_pwrseq_sd8787_power_off(struct mmc_host *host)
gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
}
+static void mmc_pwrseq_wilc1000_pre_power_on(struct mmc_host *host)
+{
+ struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq);
+
+ /* The pwrdn_gpio is really CHIP_EN, reset_gpio is RESETN */
+ gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1);
+ msleep(5);
+ gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
+}
+
+static void mmc_pwrseq_wilc1000_power_off(struct mmc_host *host)
+{
+ struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq);
+
+ gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
+ gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 0);
+}
+
static const struct mmc_pwrseq_ops mmc_pwrseq_sd8787_ops = {
.pre_power_on = mmc_pwrseq_sd8787_pre_power_on,
.power_off = mmc_pwrseq_sd8787_power_off,
};
+static const struct mmc_pwrseq_ops mmc_pwrseq_wilc1000_ops = {
+ .pre_power_on = mmc_pwrseq_wilc1000_pre_power_on,
+ .power_off = mmc_pwrseq_wilc1000_power_off,
+};
+
static const struct of_device_id mmc_pwrseq_sd8787_of_match[] = {
- { .compatible = "mmc-pwrseq-sd8787",},
+ { .compatible = "mmc-pwrseq-sd8787", .data = &mmc_pwrseq_sd8787_ops },
+ { .compatible = "mmc-pwrseq-wilc1000", .data = &mmc_pwrseq_wilc1000_ops },
{/* sentinel */},
};
MODULE_DEVICE_TABLE(of, mmc_pwrseq_sd8787_of_match);
@@ -74,11 +89,14 @@ static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev)
{
struct mmc_pwrseq_sd8787 *pwrseq;
struct device *dev = &pdev->dev;
+ const struct of_device_id *match;
pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
if (!pwrseq)
return -ENOMEM;
+ match = of_match_node(mmc_pwrseq_sd8787_of_match, pdev->dev.of_node);
+
pwrseq->pwrdn_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_LOW);
if (IS_ERR(pwrseq->pwrdn_gpio))
return PTR_ERR(pwrseq->pwrdn_gpio);
@@ -88,20 +106,18 @@ static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev)
return PTR_ERR(pwrseq->reset_gpio);
pwrseq->pwrseq.dev = dev;
- pwrseq->pwrseq.ops = &mmc_pwrseq_sd8787_ops;
+ pwrseq->pwrseq.ops = match->data;
pwrseq->pwrseq.owner = THIS_MODULE;
platform_set_drvdata(pdev, pwrseq);
return mmc_pwrseq_register(&pwrseq->pwrseq);
}
-static int mmc_pwrseq_sd8787_remove(struct platform_device *pdev)
+static void mmc_pwrseq_sd8787_remove(struct platform_device *pdev)
{
struct mmc_pwrseq_sd8787 *pwrseq = platform_get_drvdata(pdev);
mmc_pwrseq_unregister(&pwrseq->pwrseq);
-
- return 0;
}
static struct platform_driver mmc_pwrseq_sd8787_driver = {
@@ -114,4 +130,5 @@ static struct platform_driver mmc_pwrseq_sd8787_driver = {
};
module_platform_driver(mmc_pwrseq_sd8787_driver);
+MODULE_DESCRIPTION("Power sequence support for Marvell SD8787 BT + Wifi chip");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
index 13ef162cf066..4b47e6c3b04b 100644
--- a/drivers/mmc/core/pwrseq_simple.c
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Linaro Ltd
*
* Author: Ulf Hansson <ulf.hansson@linaro.org>
*
- * License terms: GNU General Public License (GPL) version 2
- *
* Simple MMC power sequence management
*/
#include <linux/clk.h>
@@ -18,6 +17,8 @@
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/property.h>
+#include <linux/of.h>
+#include <linux/reset.h>
#include <linux/mmc/host.h>
@@ -30,6 +31,7 @@ struct mmc_pwrseq_simple {
u32 power_off_delay_us;
struct clk *ext_clk;
struct gpio_descs *reset_gpios;
+ struct reset_control *reset_ctrl;
};
#define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq)
@@ -40,14 +42,21 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
if (!IS_ERR(reset_gpios)) {
- int i;
- int values[reset_gpios->ndescs];
+ unsigned long *values;
+ int nvalues = reset_gpios->ndescs;
+
+ values = bitmap_alloc(nvalues, GFP_KERNEL);
+ if (!values)
+ return;
+
+ if (value)
+ bitmap_fill(values, nvalues);
+ else
+ bitmap_zero(values, nvalues);
- for (i = 0; i < reset_gpios->ndescs; i++)
- values[i] = value;
+ gpiod_multi_set_value_cansleep(reset_gpios, values);
- gpiod_set_array_value_cansleep(
- reset_gpios->ndescs, reset_gpios->desc, values);
+ bitmap_free(values);
}
}
@@ -60,14 +69,21 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
pwrseq->clk_enabled = true;
}
- mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
+ if (pwrseq->reset_ctrl) {
+ reset_control_deassert(pwrseq->reset_ctrl);
+ reset_control_assert(pwrseq->reset_ctrl);
+ } else
+ mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
}
static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
{
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
- mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
+ if (pwrseq->reset_ctrl)
+ reset_control_deassert(pwrseq->reset_ctrl);
+ else
+ mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
if (pwrseq->post_power_on_delay_ms)
msleep(pwrseq->post_power_on_delay_ms);
@@ -77,7 +93,10 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
{
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
- mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
+ if (pwrseq->reset_ctrl)
+ reset_control_assert(pwrseq->reset_ctrl);
+ else
+ mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
if (pwrseq->power_off_delay_us)
usleep_range(pwrseq->power_off_delay_us,
@@ -105,6 +124,7 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
{
struct mmc_pwrseq_simple *pwrseq;
struct device *dev = &pdev->dev;
+ int ngpio;
pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
if (!pwrseq)
@@ -112,14 +132,28 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
pwrseq->ext_clk = devm_clk_get(dev, "ext_clock");
if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT)
- return PTR_ERR(pwrseq->ext_clk);
-
- pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset",
- GPIOD_OUT_HIGH);
- if (IS_ERR(pwrseq->reset_gpios) &&
- PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
- PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
- return PTR_ERR(pwrseq->reset_gpios);
+ return dev_err_probe(dev, PTR_ERR(pwrseq->ext_clk), "external clock not ready\n");
+
+ ngpio = of_count_phandle_with_args(dev->of_node, "reset-gpios", "#gpio-cells");
+ if (ngpio == 1) {
+ pwrseq->reset_ctrl = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(pwrseq->reset_ctrl))
+ return dev_err_probe(dev, PTR_ERR(pwrseq->reset_ctrl),
+ "reset control not ready\n");
+ }
+
+ /*
+ * Fallback to GPIO based reset control in case of multiple reset lines
+ * are specified or the platform doesn't have support for RESET at all.
+ */
+ if (!pwrseq->reset_ctrl) {
+ pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(pwrseq->reset_gpios) &&
+ PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
+ PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
+ return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios),
+ "reset GPIOs not ready\n");
+ }
}
device_property_read_u32(dev, "post-power-on-delay-ms",
@@ -135,13 +169,11 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
return mmc_pwrseq_register(&pwrseq->pwrseq);
}
-static int mmc_pwrseq_simple_remove(struct platform_device *pdev)
+static void mmc_pwrseq_simple_remove(struct platform_device *pdev)
{
struct mmc_pwrseq_simple *pwrseq = platform_get_drvdata(pdev);
mmc_pwrseq_unregister(&pwrseq->pwrseq);
-
- return 0;
}
static struct platform_driver mmc_pwrseq_simple_driver = {
@@ -154,4 +186,5 @@ static struct platform_driver mmc_pwrseq_simple_driver = {
};
module_platform_driver(mmc_pwrseq_simple_driver);
+MODULE_DESCRIPTION("Simple power sequence management for MMC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index affa7370ba82..284856c8f655 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -1,19 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/freezer.h>
-#include <linux/kthread.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
+#include <linux/backing-dev.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -22,105 +18,152 @@
#include "block.h"
#include "core.h"
#include "card.h"
+#include "crypto.h"
+#include "host.h"
-#define MMC_QUEUE_BOUNCESZ 65536
+#define MMC_DMA_MAP_MERGE_SEGMENTS 512
-/*
- * Prepare a MMC request. This just filters out odd stuff.
- */
-static int mmc_prep_request(struct request_queue *q, struct request *req)
+static inline bool mmc_cqe_dcmd_busy(struct mmc_queue *mq)
{
- struct mmc_queue *mq = q->queuedata;
+ /* Allow only 1 DCMD at a time */
+ return mq->in_flight[MMC_ISSUE_DCMD];
+}
- if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
- return BLKPREP_KILL;
+void mmc_cqe_check_busy(struct mmc_queue *mq)
+{
+ if ((mq->cqe_busy & MMC_CQE_DCMD_BUSY) && !mmc_cqe_dcmd_busy(mq))
+ mq->cqe_busy &= ~MMC_CQE_DCMD_BUSY;
+}
- req->rq_flags |= RQF_DONTPREP;
+static inline bool mmc_cqe_can_dcmd(struct mmc_host *host)
+{
+ return host->caps2 & MMC_CAP2_CQE_DCMD;
+}
- return BLKPREP_OK;
+static enum mmc_issue_type mmc_cqe_issue_type(struct mmc_host *host,
+ struct request *req)
+{
+ switch (req_op(req)) {
+ case REQ_OP_DRV_IN:
+ case REQ_OP_DRV_OUT:
+ case REQ_OP_DISCARD:
+ case REQ_OP_SECURE_ERASE:
+ case REQ_OP_WRITE_ZEROES:
+ return MMC_ISSUE_SYNC;
+ case REQ_OP_FLUSH:
+ return mmc_cqe_can_dcmd(host) ? MMC_ISSUE_DCMD : MMC_ISSUE_SYNC;
+ default:
+ return MMC_ISSUE_ASYNC;
+ }
}
-static int mmc_queue_thread(void *d)
+enum mmc_issue_type mmc_issue_type(struct mmc_queue *mq, struct request *req)
{
- struct mmc_queue *mq = d;
- struct request_queue *q = mq->queue;
- struct mmc_context_info *cntx = &mq->card->host->context_info;
-
- current->flags |= PF_MEMALLOC;
-
- down(&mq->thread_sem);
- do {
- struct request *req;
-
- spin_lock_irq(q->queue_lock);
- set_current_state(TASK_INTERRUPTIBLE);
- req = blk_fetch_request(q);
- mq->asleep = false;
- cntx->is_waiting_last_req = false;
- cntx->is_new_req = false;
- if (!req) {
- /*
- * Dispatch queue is empty so set flags for
- * mmc_request_fn() to wake us up.
- */
- if (mq->qcnt)
- cntx->is_waiting_last_req = true;
- else
- mq->asleep = true;
- }
- spin_unlock_irq(q->queue_lock);
-
- if (req || mq->qcnt) {
- set_current_state(TASK_RUNNING);
- mmc_blk_issue_rq(mq, req);
- cond_resched();
- } else {
- if (kthread_should_stop()) {
- set_current_state(TASK_RUNNING);
- break;
- }
- up(&mq->thread_sem);
- schedule();
- down(&mq->thread_sem);
- }
- } while (1);
- up(&mq->thread_sem);
+ struct mmc_host *host = mq->card->host;
- return 0;
+ if (host->cqe_enabled && !host->hsq_enabled)
+ return mmc_cqe_issue_type(host, req);
+
+ if (req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_WRITE)
+ return MMC_ISSUE_ASYNC;
+
+ return MMC_ISSUE_SYNC;
}
-/*
- * Generic MMC request handler. This is called for any queue on a
- * particular host. When the host is not busy, we look for a request
- * on any queue on this host, and attempt to issue it. This may
- * not be the queue we were asked to process.
- */
-static void mmc_request_fn(struct request_queue *q)
+static void __mmc_cqe_recovery_notifier(struct mmc_queue *mq)
+{
+ if (!mq->recovery_needed) {
+ mq->recovery_needed = true;
+ schedule_work(&mq->recovery_work);
+ }
+}
+
+void mmc_cqe_recovery_notifier(struct mmc_request *mrq)
{
+ struct mmc_queue_req *mqrq = container_of(mrq, struct mmc_queue_req,
+ brq.mrq);
+ struct request *req = mmc_queue_req_to_req(mqrq);
+ struct request_queue *q = req->q;
struct mmc_queue *mq = q->queuedata;
- struct request *req;
- struct mmc_context_info *cntx;
+ unsigned long flags;
- if (!mq) {
- while ((req = blk_fetch_request(q)) != NULL) {
- req->rq_flags |= RQF_QUIET;
- __blk_end_request_all(req, BLK_STS_IOERR);
+ spin_lock_irqsave(&mq->lock, flags);
+ __mmc_cqe_recovery_notifier(mq);
+ spin_unlock_irqrestore(&mq->lock, flags);
+}
+
+static enum blk_eh_timer_return mmc_cqe_timed_out(struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_request *mrq = &mqrq->brq.mrq;
+ struct mmc_queue *mq = req->q->queuedata;
+ struct mmc_host *host = mq->card->host;
+ enum mmc_issue_type issue_type = mmc_issue_type(mq, req);
+ bool recovery_needed = false;
+
+ switch (issue_type) {
+ case MMC_ISSUE_ASYNC:
+ case MMC_ISSUE_DCMD:
+ if (host->cqe_ops->cqe_timeout(host, mrq, &recovery_needed)) {
+ if (recovery_needed)
+ mmc_cqe_recovery_notifier(mrq);
+ return BLK_EH_RESET_TIMER;
}
- return;
+ /* The request has gone already */
+ return BLK_EH_DONE;
+ default:
+ /* Timeout is handled by mmc core */
+ return BLK_EH_RESET_TIMER;
}
+}
- cntx = &mq->card->host->context_info;
+static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req)
+{
+ struct request_queue *q = req->q;
+ struct mmc_queue *mq = q->queuedata;
+ struct mmc_card *card = mq->card;
+ struct mmc_host *host = card->host;
+ unsigned long flags;
+ bool ignore_tout;
- if (cntx->is_waiting_last_req) {
- cntx->is_new_req = true;
- wake_up_interruptible(&cntx->wait);
- }
+ spin_lock_irqsave(&mq->lock, flags);
+ ignore_tout = mq->recovery_needed || !host->cqe_enabled || host->hsq_enabled;
+ spin_unlock_irqrestore(&mq->lock, flags);
- if (mq->asleep)
- wake_up_process(mq->thread);
+ return ignore_tout ? BLK_EH_RESET_TIMER : mmc_cqe_timed_out(req);
}
-static struct scatterlist *mmc_alloc_sg(int sg_len, gfp_t gfp)
+static void mmc_mq_recovery_handler(struct work_struct *work)
+{
+ struct mmc_queue *mq = container_of(work, struct mmc_queue,
+ recovery_work);
+ struct request_queue *q = mq->queue;
+ struct mmc_host *host = mq->card->host;
+
+ mmc_get_card(mq->card, &mq->ctx);
+
+ mq->in_recovery = true;
+
+ if (host->cqe_enabled && !host->hsq_enabled)
+ mmc_blk_cqe_recovery(mq);
+ else
+ mmc_blk_mq_recovery(mq);
+
+ mq->in_recovery = false;
+
+ spin_lock_irq(&mq->lock);
+ mq->recovery_needed = false;
+ spin_unlock_irq(&mq->lock);
+
+ if (host->hsq_enabled)
+ host->cqe_ops->cqe_recovery_finish(host);
+
+ mmc_put_card(mq->card, &mq->ctx);
+
+ blk_mq_run_hw_queues(q, true);
+}
+
+static struct scatterlist *mmc_alloc_sg(unsigned short sg_len, gfp_t gfp)
{
struct scatterlist *sg;
@@ -131,8 +174,8 @@ static struct scatterlist *mmc_alloc_sg(int sg_len, gfp_t gfp)
return sg;
}
-static void mmc_queue_setup_discard(struct request_queue *q,
- struct mmc_card *card)
+static void mmc_queue_setup_discard(struct mmc_card *card,
+ struct queue_limits *lim)
{
unsigned max_discard;
@@ -140,281 +183,345 @@ static void mmc_queue_setup_discard(struct request_queue *q,
if (!max_discard)
return;
- queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
- blk_queue_max_discard_sectors(q, max_discard);
- q->limits.discard_granularity = card->pref_erase << 9;
+ lim->max_hw_discard_sectors = max_discard;
+ if (mmc_card_can_secure_erase_trim(card))
+ lim->max_secure_erase_sectors = max_discard;
+ if (mmc_card_can_trim(card) && card->erased_byte == 0)
+ lim->max_write_zeroes_sectors = max_discard;
+
/* granularity must not be greater than max. discard */
if (card->pref_erase > max_discard)
- q->limits.discard_granularity = 0;
- if (mmc_can_secure_erase_trim(card))
- queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q);
+ lim->discard_granularity = SECTOR_SIZE;
+ else
+ lim->discard_granularity = card->pref_erase << 9;
}
-static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host)
+static unsigned short mmc_get_max_segments(struct mmc_host *host)
{
- unsigned int bouncesz = MMC_QUEUE_BOUNCESZ;
-
- if (host->max_segs != 1 || (host->caps & MMC_CAP_NO_BOUNCE_BUFF))
- return 0;
-
- if (bouncesz > host->max_req_size)
- bouncesz = host->max_req_size;
- if (bouncesz > host->max_seg_size)
- bouncesz = host->max_seg_size;
- if (bouncesz > host->max_blk_count * 512)
- bouncesz = host->max_blk_count * 512;
-
- if (bouncesz <= 512)
- return 0;
-
- return bouncesz;
+ return host->can_dma_map_merge ? MMC_DMA_MAP_MERGE_SEGMENTS :
+ host->max_segs;
}
-/**
- * mmc_init_request() - initialize the MMC-specific per-request data
- * @q: the request queue
- * @req: the request
- * @gfp: memory allocation policy
- */
-static int mmc_init_request(struct request_queue *q, struct request *req,
- gfp_t gfp)
+static int mmc_mq_init_request(struct blk_mq_tag_set *set, struct request *req,
+ unsigned int hctx_idx, unsigned int numa_node)
{
struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req);
- struct mmc_queue *mq = q->queuedata;
+ struct mmc_queue *mq = set->driver_data;
struct mmc_card *card = mq->card;
struct mmc_host *host = card->host;
- if (card->bouncesz) {
- mq_rq->bounce_buf = kmalloc(card->bouncesz, gfp);
- if (!mq_rq->bounce_buf)
- return -ENOMEM;
- if (card->bouncesz > 512) {
- mq_rq->sg = mmc_alloc_sg(1, gfp);
- if (!mq_rq->sg)
- return -ENOMEM;
- mq_rq->bounce_sg = mmc_alloc_sg(card->bouncesz / 512,
- gfp);
- if (!mq_rq->bounce_sg)
- return -ENOMEM;
- }
- } else {
- mq_rq->bounce_buf = NULL;
- mq_rq->bounce_sg = NULL;
- mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp);
- if (!mq_rq->sg)
- return -ENOMEM;
- }
+ mq_rq->sg = mmc_alloc_sg(mmc_get_max_segments(host), GFP_KERNEL);
+ if (!mq_rq->sg)
+ return -ENOMEM;
return 0;
}
-static void mmc_exit_request(struct request_queue *q, struct request *req)
+static void mmc_mq_exit_request(struct blk_mq_tag_set *set, struct request *req,
+ unsigned int hctx_idx)
{
struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req);
- /* It is OK to kfree(NULL) so this will be smooth */
- kfree(mq_rq->bounce_sg);
- mq_rq->bounce_sg = NULL;
-
- kfree(mq_rq->bounce_buf);
- mq_rq->bounce_buf = NULL;
-
kfree(mq_rq->sg);
mq_rq->sg = NULL;
}
-/**
- * mmc_init_queue - initialise a queue structure.
- * @mq: mmc queue
- * @card: mmc card to attach this queue
- * @lock: queue lock
- * @subname: partition subname
- *
- * Initialise a MMC card request queue.
- */
-int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
- spinlock_t *lock, const char *subname)
+static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
+ struct request *req = bd->rq;
+ struct request_queue *q = req->q;
+ struct mmc_queue *mq = q->queuedata;
+ struct mmc_card *card = mq->card;
struct mmc_host *host = card->host;
- u64 limit = BLK_BOUNCE_HIGH;
- int ret = -ENOMEM;
+ enum mmc_issue_type issue_type;
+ enum mmc_issued issued;
+ bool get_card, cqe_retune_ok;
+ blk_status_t ret;
+
+ if (mmc_card_removed(mq->card)) {
+ req->rq_flags |= RQF_QUIET;
+ return BLK_STS_IOERR;
+ }
- if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
- limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
+ issue_type = mmc_issue_type(mq, req);
- mq->card = card;
- mq->queue = blk_alloc_queue(GFP_KERNEL);
- if (!mq->queue)
- return -ENOMEM;
- mq->queue->queue_lock = lock;
- mq->queue->request_fn = mmc_request_fn;
- mq->queue->init_rq_fn = mmc_init_request;
- mq->queue->exit_rq_fn = mmc_exit_request;
- mq->queue->cmd_size = sizeof(struct mmc_queue_req);
- mq->queue->queuedata = mq;
- mq->qcnt = 0;
- ret = blk_init_allocated_queue(mq->queue);
- if (ret) {
- blk_cleanup_queue(mq->queue);
- return ret;
+ spin_lock_irq(&mq->lock);
+
+ if (mq->recovery_needed || mq->busy) {
+ spin_unlock_irq(&mq->lock);
+ return BLK_STS_RESOURCE;
}
- blk_queue_prep_rq(mq->queue, mmc_prep_request);
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
- queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
- if (mmc_can_erase(card))
- mmc_queue_setup_discard(mq->queue, card);
-
- card->bouncesz = mmc_queue_calc_bouncesz(host);
- if (card->bouncesz) {
- blk_queue_max_hw_sectors(mq->queue, card->bouncesz / 512);
- blk_queue_max_segments(mq->queue, card->bouncesz / 512);
- blk_queue_max_segment_size(mq->queue, card->bouncesz);
- } else {
- blk_queue_bounce_limit(mq->queue, limit);
- blk_queue_max_hw_sectors(mq->queue,
- min(host->max_blk_count, host->max_req_size / 512));
- blk_queue_max_segments(mq->queue, host->max_segs);
- blk_queue_max_segment_size(mq->queue, host->max_seg_size);
+ switch (issue_type) {
+ case MMC_ISSUE_DCMD:
+ if (mmc_cqe_dcmd_busy(mq)) {
+ mq->cqe_busy |= MMC_CQE_DCMD_BUSY;
+ spin_unlock_irq(&mq->lock);
+ return BLK_STS_RESOURCE;
+ }
+ break;
+ case MMC_ISSUE_ASYNC:
+ if (host->hsq_enabled && mq->in_flight[issue_type] > host->hsq_depth) {
+ spin_unlock_irq(&mq->lock);
+ return BLK_STS_RESOURCE;
+ }
+ break;
+ default:
+ /*
+ * Timeouts are handled by mmc core, and we don't have a host
+ * API to abort requests, so we can't handle the timeout anyway.
+ * However, when the timeout happens, blk_mq_complete_request()
+ * no longer works (to stop the request disappearing under us).
+ * To avoid racing with that, set a large timeout.
+ */
+ req->timeout = 600 * HZ;
+ break;
}
- sema_init(&mq->thread_sem, 1);
+ /* Parallel dispatch of requests is not supported at the moment */
+ mq->busy = true;
+
+ mq->in_flight[issue_type] += 1;
+ get_card = (mmc_tot_in_flight(mq) == 1);
+ cqe_retune_ok = (mmc_cqe_qcnt(mq) == 1);
- mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
- host->index, subname ? subname : "");
+ spin_unlock_irq(&mq->lock);
- if (IS_ERR(mq->thread)) {
- ret = PTR_ERR(mq->thread);
- goto cleanup_queue;
+ if (!(req->rq_flags & RQF_DONTPREP)) {
+ req_to_mmc_queue_req(req)->retries = 0;
+ req->rq_flags |= RQF_DONTPREP;
}
- return 0;
+ if (get_card)
+ mmc_get_card(card, &mq->ctx);
-cleanup_queue:
- blk_cleanup_queue(mq->queue);
- return ret;
-}
+ if (host->cqe_enabled) {
+ host->retune_now = host->need_retune && cqe_retune_ok &&
+ !host->hold_retune;
+ }
-void mmc_cleanup_queue(struct mmc_queue *mq)
-{
- struct request_queue *q = mq->queue;
- unsigned long flags;
+ blk_mq_start_request(req);
- /* Make sure the queue isn't suspended, as that will deadlock */
- mmc_queue_resume(mq);
+ issued = mmc_blk_mq_issue_rq(mq, req);
- /* Then terminate our worker thread */
- kthread_stop(mq->thread);
+ switch (issued) {
+ case MMC_REQ_BUSY:
+ ret = BLK_STS_RESOURCE;
+ break;
+ case MMC_REQ_FAILED_TO_START:
+ ret = BLK_STS_IOERR;
+ break;
+ default:
+ ret = BLK_STS_OK;
+ break;
+ }
- /* Empty the queue */
- spin_lock_irqsave(q->queue_lock, flags);
- q->queuedata = NULL;
- blk_start_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
+ if (issued != MMC_REQ_STARTED) {
+ bool put_card = false;
+
+ spin_lock_irq(&mq->lock);
+ mq->in_flight[issue_type] -= 1;
+ if (mmc_tot_in_flight(mq) == 0)
+ put_card = true;
+ mq->busy = false;
+ spin_unlock_irq(&mq->lock);
+ if (put_card)
+ mmc_put_card(card, &mq->ctx);
+ } else {
+ WRITE_ONCE(mq->busy, false);
+ }
- mq->card = NULL;
+ return ret;
}
-EXPORT_SYMBOL(mmc_cleanup_queue);
-/**
- * mmc_queue_suspend - suspend a MMC request queue
- * @mq: MMC queue to suspend
- *
- * Stop the block request queue, and wait for our thread to
- * complete any outstanding requests. This ensures that we
- * won't suspend while a request is being processed.
- */
-void mmc_queue_suspend(struct mmc_queue *mq)
+static const struct blk_mq_ops mmc_mq_ops = {
+ .queue_rq = mmc_mq_queue_rq,
+ .init_request = mmc_mq_init_request,
+ .exit_request = mmc_mq_exit_request,
+ .complete = mmc_blk_mq_complete,
+ .timeout = mmc_mq_timed_out,
+};
+
+static struct gendisk *mmc_alloc_disk(struct mmc_queue *mq,
+ struct mmc_card *card, unsigned int features)
{
- struct request_queue *q = mq->queue;
- unsigned long flags;
+ struct mmc_host *host = card->host;
+ struct queue_limits lim = {
+ .features = features,
+ };
+ struct gendisk *disk;
+
+ if (mmc_card_can_erase(card))
+ mmc_queue_setup_discard(card, &lim);
+
+ lim.max_hw_sectors = min(host->max_blk_count, host->max_req_size / 512);
+
+ if (mmc_card_mmc(card) && card->ext_csd.data_sector_size)
+ lim.logical_block_size = card->ext_csd.data_sector_size;
+ else
+ lim.logical_block_size = 512;
+
+ WARN_ON_ONCE(lim.logical_block_size != 512 &&
+ lim.logical_block_size != 4096);
+
+ /*
+ * Setting a virt_boundary implicity sets a max_segment_size, so try
+ * to set the hardware one here.
+ */
+ if (host->can_dma_map_merge) {
+ lim.virt_boundary_mask = dma_get_merge_boundary(mmc_dev(host));
+ lim.max_segments = MMC_DMA_MAP_MERGE_SEGMENTS;
+ } else {
+ lim.max_segment_size =
+ round_down(host->max_seg_size, lim.logical_block_size);
+ lim.max_segments = host->max_segs;
+ }
- if (!mq->suspended) {
- mq->suspended |= true;
+ if (mmc_host_is_spi(host) && host->use_spi_crc)
+ lim.features |= BLK_FEAT_STABLE_WRITES;
- spin_lock_irqsave(q->queue_lock, flags);
- blk_stop_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
+ disk = blk_mq_alloc_disk(&mq->tag_set, &lim, mq);
+ if (IS_ERR(disk))
+ return disk;
+ mq->queue = disk->queue;
- down(&mq->thread_sem);
- }
-}
+ blk_queue_rq_timeout(mq->queue, 60 * HZ);
-/**
- * mmc_queue_resume - resume a previously suspended MMC request queue
- * @mq: MMC queue to resume
- */
-void mmc_queue_resume(struct mmc_queue *mq)
-{
- struct request_queue *q = mq->queue;
- unsigned long flags;
+ if (mmc_dev(host)->dma_parms)
+ dma_set_max_seg_size(mmc_dev(host), queue_max_segment_size(mq->queue));
- if (mq->suspended) {
- mq->suspended = false;
+ INIT_WORK(&mq->recovery_work, mmc_mq_recovery_handler);
+ INIT_WORK(&mq->complete_work, mmc_blk_mq_complete_work);
- up(&mq->thread_sem);
+ mutex_init(&mq->complete_lock);
- spin_lock_irqsave(q->queue_lock, flags);
- blk_start_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
- }
+ init_waitqueue_head(&mq->wait);
+
+ mmc_crypto_setup_queue(mq->queue, host);
+ return disk;
}
-/*
- * Prepare the sg list(s) to be handed of to the host driver
- */
-unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
+static inline bool mmc_merge_capable(struct mmc_host *host)
{
- unsigned int sg_len;
- size_t buflen;
- struct scatterlist *sg;
- struct request *req = mmc_queue_req_to_req(mqrq);
- int i;
-
- if (!mqrq->bounce_buf)
- return blk_rq_map_sg(mq->queue, req, mqrq->sg);
+ return host->caps2 & MMC_CAP2_MERGE_CAPABLE;
+}
- sg_len = blk_rq_map_sg(mq->queue, req, mqrq->bounce_sg);
+/* Set queue depth to get a reasonable value for q->nr_requests */
+#define MMC_QUEUE_DEPTH 64
- mqrq->bounce_sg_len = sg_len;
+/**
+ * mmc_init_queue - initialise a queue structure.
+ * @mq: mmc queue
+ * @card: mmc card to attach this queue
+ * @features: block layer features (BLK_FEAT_*)
+ *
+ * Initialise a MMC card request queue.
+ */
+struct gendisk *mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
+ unsigned int features)
+{
+ struct mmc_host *host = card->host;
+ struct gendisk *disk;
+ int ret;
- buflen = 0;
- for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
- buflen += sg->length;
+ mq->card = card;
+
+ spin_lock_init(&mq->lock);
+
+ memset(&mq->tag_set, 0, sizeof(mq->tag_set));
+ mq->tag_set.ops = &mmc_mq_ops;
+ /*
+ * The queue depth for CQE must match the hardware because the request
+ * tag is used to index the hardware queue.
+ */
+ if (host->cqe_enabled && !host->hsq_enabled)
+ mq->tag_set.queue_depth =
+ min_t(int, card->ext_csd.cmdq_depth, host->cqe_qdepth);
+ else
+ mq->tag_set.queue_depth = MMC_QUEUE_DEPTH;
+ mq->tag_set.numa_node = NUMA_NO_NODE;
+ mq->tag_set.flags = BLK_MQ_F_BLOCKING;
+ mq->tag_set.nr_hw_queues = 1;
+ mq->tag_set.cmd_size = sizeof(struct mmc_queue_req);
+ mq->tag_set.driver_data = mq;
+
+ /*
+ * Since blk_mq_alloc_tag_set() calls .init_request() of mmc_mq_ops,
+ * the host->can_dma_map_merge should be set before to get max_segs
+ * from mmc_get_max_segments().
+ */
+ if (mmc_merge_capable(host) &&
+ host->max_segs < MMC_DMA_MAP_MERGE_SEGMENTS &&
+ dma_get_merge_boundary(mmc_dev(host)))
+ host->can_dma_map_merge = 1;
+ else
+ host->can_dma_map_merge = 0;
+
+ ret = blk_mq_alloc_tag_set(&mq->tag_set);
+ if (ret)
+ return ERR_PTR(ret);
+
+
+ disk = mmc_alloc_disk(mq, card, features);
+ if (IS_ERR(disk))
+ blk_mq_free_tag_set(&mq->tag_set);
+ return disk;
+}
- sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
+void mmc_queue_suspend(struct mmc_queue *mq)
+{
+ blk_mq_quiesce_queue(mq->queue);
+
+ /*
+ * The host remains claimed while there are outstanding requests, so
+ * simply claiming and releasing here ensures there are none.
+ */
+ mmc_claim_host(mq->card->host);
+ mmc_release_host(mq->card->host);
+}
- return 1;
+void mmc_queue_resume(struct mmc_queue *mq)
+{
+ blk_mq_unquiesce_queue(mq->queue);
}
-/*
- * If writing, bounce the data to the buffer before the request
- * is sent to the host driver
- */
-void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
+void mmc_cleanup_queue(struct mmc_queue *mq)
{
- if (!mqrq->bounce_buf)
- return;
+ struct request_queue *q = mq->queue;
- if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != WRITE)
- return;
+ /*
+ * The legacy code handled the possibility of being suspended,
+ * so do that here too.
+ */
+ if (blk_queue_quiesced(q))
+ blk_mq_unquiesce_queue(q);
+
+ /*
+ * If the recovery completes the last (and only remaining) request in
+ * the queue, and the card has been removed, we could end up here with
+ * the recovery not quite finished yet, so cancel it.
+ */
+ cancel_work_sync(&mq->recovery_work);
+
+ blk_mq_free_tag_set(&mq->tag_set);
+
+ /*
+ * A request can be completed before the next request, potentially
+ * leaving a complete_work with nothing to do. Such a work item might
+ * still be queued at this point. Flush it.
+ */
+ flush_work(&mq->complete_work);
- sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
- mqrq->bounce_buf, mqrq->sg[0].length);
+ mq->card = NULL;
}
/*
- * If reading, bounce the data from the buffer after the request
- * has been handled by the host driver
+ * Prepare the sg list(s) to be handed of to the host driver
*/
-void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
+unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
{
- if (!mqrq->bounce_buf)
- return;
-
- if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != READ)
- return;
+ struct request *req = mmc_queue_req_to_req(mqrq);
- sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
- mqrq->bounce_buf, mqrq->sg[0].length);
+ return blk_rq_map_sg(req, mqrq->sg);
}
diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h
index 361b46408e0f..1498840a4ea0 100644
--- a/drivers/mmc/core/queue.h
+++ b/drivers/mmc/core/queue.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
#ifndef MMC_QUEUE_H
#define MMC_QUEUE_H
@@ -7,6 +8,20 @@
#include <linux/mmc/core.h>
#include <linux/mmc/host.h>
+enum mmc_issued {
+ MMC_REQ_STARTED,
+ MMC_REQ_BUSY,
+ MMC_REQ_FAILED_TO_START,
+ MMC_REQ_FINISHED,
+};
+
+enum mmc_issue_type {
+ MMC_ISSUE_SYNC,
+ MMC_ISSUE_DCMD,
+ MMC_ISSUE_ASYNC,
+ MMC_ISSUE_MAX,
+};
+
static inline struct mmc_queue_req *req_to_mmc_queue_req(struct request *rq)
{
return blk_mq_rq_to_pdu(rq);
@@ -19,7 +34,6 @@ static inline struct request *mmc_queue_req_to_req(struct mmc_queue_req *mqr)
return blk_mq_rq_from_pdu(mqr);
}
-struct task_struct;
struct mmc_blk_data;
struct mmc_blk_ioc_data;
@@ -29,60 +43,81 @@ struct mmc_blk_request {
struct mmc_command cmd;
struct mmc_command stop;
struct mmc_data data;
- int retune_retry_done;
};
/**
* enum mmc_drv_op - enumerates the operations in the mmc_queue_req
* @MMC_DRV_OP_IOCTL: ioctl operation
+ * @MMC_DRV_OP_IOCTL_RPMB: RPMB-oriented ioctl operation
* @MMC_DRV_OP_BOOT_WP: write protect boot partitions
+ * @MMC_DRV_OP_GET_CARD_STATUS: get card status
+ * @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card
*/
enum mmc_drv_op {
MMC_DRV_OP_IOCTL,
+ MMC_DRV_OP_IOCTL_RPMB,
MMC_DRV_OP_BOOT_WP,
+ MMC_DRV_OP_GET_CARD_STATUS,
+ MMC_DRV_OP_GET_EXT_CSD,
};
struct mmc_queue_req {
struct mmc_blk_request brq;
struct scatterlist *sg;
- char *bounce_buf;
- struct scatterlist *bounce_sg;
- unsigned int bounce_sg_len;
- struct mmc_async_req areq;
enum mmc_drv_op drv_op;
int drv_op_result;
- struct mmc_blk_ioc_data **idata;
+ void *drv_op_data;
unsigned int ioc_count;
+ int retries;
};
struct mmc_queue {
struct mmc_card *card;
- struct task_struct *thread;
- struct semaphore thread_sem;
- bool suspended;
- bool asleep;
+ struct mmc_ctx ctx;
+ struct blk_mq_tag_set tag_set;
struct mmc_blk_data *blkdata;
struct request_queue *queue;
- /*
- * FIXME: this counter is not a very reliable way of keeping
- * track of how many requests that are ongoing. Switch to just
- * letting the block core keep track of requests and per-request
- * associated mmc_queue_req data.
- */
- int qcnt;
+ spinlock_t lock;
+ int in_flight[MMC_ISSUE_MAX];
+ unsigned int cqe_busy;
+#define MMC_CQE_DCMD_BUSY BIT(0)
+ bool busy;
+ bool recovery_needed;
+ bool in_recovery;
+ bool rw_wait;
+ bool waiting;
+ struct work_struct recovery_work;
+ wait_queue_head_t wait;
+ struct request *recovery_req;
+ struct request *complete_req;
+ struct mutex complete_lock;
+ struct work_struct complete_work;
};
-extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
- const char *);
+struct gendisk *mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
+ unsigned int features);
extern void mmc_cleanup_queue(struct mmc_queue *);
extern void mmc_queue_suspend(struct mmc_queue *);
extern void mmc_queue_resume(struct mmc_queue *);
-
extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
struct mmc_queue_req *);
-extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
-extern void mmc_queue_bounce_post(struct mmc_queue_req *);
-extern int mmc_access_rpmb(struct mmc_queue *);
+void mmc_cqe_check_busy(struct mmc_queue *mq);
+void mmc_cqe_recovery_notifier(struct mmc_request *mrq);
+
+enum mmc_issue_type mmc_issue_type(struct mmc_queue *mq, struct request *req);
+
+static inline int mmc_tot_in_flight(struct mmc_queue *mq)
+{
+ return mq->in_flight[MMC_ISSUE_SYNC] +
+ mq->in_flight[MMC_ISSUE_DCMD] +
+ mq->in_flight[MMC_ISSUE_ASYNC];
+}
+
+static inline int mmc_cqe_qcnt(struct mmc_queue *mq)
+{
+ return mq->in_flight[MMC_ISSUE_DCMD] +
+ mq->in_flight[MMC_ISSUE_ASYNC];
+}
#endif
diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
index fb725934fa21..c417ed34c057 100644
--- a/drivers/mmc/core/quirks.h
+++ b/drivers/mmc/core/quirks.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* This file contains work-arounds for many known SD/MMC
* and SDIO hardware bugs.
@@ -9,11 +10,50 @@
*
*/
+#include <linux/of.h>
#include <linux/mmc/sdio_ids.h>
#include "card.h"
-static const struct mmc_fixup mmc_blk_fixups[] = {
+static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = {
+ /*
+ * Kingston Canvas Go! Plus microSD cards never finish SD cache flush.
+ * This has so far only been observed on cards from 11/2019, while new
+ * cards from 2023/05 do not exhibit this behavior.
+ */
+ _FIXUP_EXT("SD64G", CID_MANFID_KINGSTON_SD, 0x5449, 2019, 11,
+ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
+
+ /*
+ * GIGASTONE Gaming Plus microSD cards manufactured on 02/2022 never
+ * clear Flush Cache bit and set Poweroff Notification Ready bit.
+ */
+ _FIXUP_EXT("ASTC", CID_MANFID_GIGASTONE, 0x3456, 2022, 2,
+ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ MMC_QUIRK_BROKEN_SD_CACHE | MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY,
+ EXT_CSD_REV_ANY),
+
+ /*
+ * Swissbit series S46-u cards throw I/O errors during tuning requests
+ * after the initial tuning request expectedly times out. This has
+ * only been observed on cards manufactured on 01/2019 that are using
+ * Bay Trail host controllers.
+ */
+ _FIXUP_EXT("0016G", CID_MANFID_SWISSBIT, 0x5342, 2019, 1,
+ 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ MMC_QUIRK_NO_UHS_DDR50_TUNING, EXT_CSD_REV_ANY),
+
+ /*
+ * Some SD cards reports discard support while they don't
+ */
+ MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
+ MMC_QUIRK_BROKEN_SD_DISCARD),
+
+ END_FIXUP
+};
+
+static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
#define INAND_CMD38_ARG_EXT_CSD 113
#define INAND_CMD38_ARG_ERASE 0x00
#define INAND_CMD38_ARG_TRIM 0x01
@@ -52,6 +92,14 @@ static const struct mmc_fixup mmc_blk_fixups[] = {
MMC_QUIRK_BLK_NO_CMD23),
/*
+ * Some SD cards lockup while using CMD23 multiblock transfers.
+ */
+ MMC_FIXUP("AF SD", CID_MANFID_ATP, CID_OEMID_ANY, add_quirk_sd,
+ MMC_QUIRK_BLK_NO_CMD23),
+ MMC_FIXUP("APUSD", CID_MANFID_APACER, 0x5048, add_quirk_sd,
+ MMC_QUIRK_BLK_NO_CMD23),
+
+ /*
* Some MMC cards need longer data read timeout than indicated in CSD.
*/
MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
@@ -90,21 +138,49 @@ static const struct mmc_fixup mmc_blk_fixups[] = {
MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_TRIM_BROKEN),
+ /*
+ * Micron MTFC4GACAJCN-1M supports TRIM but does not appear to support
+ * WRITE_ZEROES offloading. It also supports caching, but the cache can
+ * only be flushed after a write has occurred.
+ */
+ MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
+ MMC_QUIRK_TRIM_BROKEN | MMC_QUIRK_BROKEN_CACHE_FLUSH),
+
+ /*
+ * Kingston EMMC04G-M627 advertises TRIM but it does not seems to
+ * support being used to offload WRITE_ZEROES.
+ */
+ MMC_FIXUP("M62704", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
+ MMC_QUIRK_TRIM_BROKEN),
+
END_FIXUP
};
-static const struct mmc_fixup mmc_ext_csd_fixups[] = {
+static const struct mmc_fixup __maybe_unused mmc_ext_csd_fixups[] = {
/*
* Certain Hynix eMMC 4.41 cards might get broken when HPI feature
* is used so disable the HPI feature for such buggy cards.
*/
MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+ /*
+ * Certain Micron (Numonyx) eMMC 4.5 cards might get broken when HPI
+ * feature is used so disable the HPI feature for such buggy cards.
+ */
+ MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_NUMONYX,
+ 0x014e, add_quirk, MMC_QUIRK_BROKEN_HPI, 6),
END_FIXUP
};
-static const struct mmc_fixup sdio_fixup_methods[] = {
+
+static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = {
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251,
+ add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251,
+ add_quirk, MMC_QUIRK_DISABLE_CD),
+
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
@@ -117,9 +193,38 @@ static const struct mmc_fixup sdio_fixup_methods[] = {
SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0,
add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING),
+ SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887_F0,
+ add_limit_rate_quirk, 150000000),
+
+ END_FIXUP
+};
+
+static const struct mmc_fixup __maybe_unused sdio_card_init_methods[] = {
+ SDIO_FIXUP_COMPATIBLE("ti,wl1251", wl1251_quirk, 0),
+
+ SDIO_FIXUP_COMPATIBLE("silabs,wf200", add_quirk,
+ MMC_QUIRK_BROKEN_BYTE_MODE_512 |
+ MMC_QUIRK_LENIENT_FN0 |
+ MMC_QUIRK_BLKSZ_FOR_BYTE_MODE),
+
END_FIXUP
};
+static inline bool mmc_fixup_of_compatible_match(struct mmc_card *card,
+ const char *compatible)
+{
+ struct device_node *np;
+
+ for_each_child_of_node(mmc_dev(card->host)->of_node, np) {
+ if (of_device_is_compatible(np, compatible)) {
+ of_node_put(np);
+ return true;
+ }
+ }
+
+ return false;
+}
+
static inline void mmc_fixup_device(struct mmc_card *card,
const struct mmc_fixup *table)
{
@@ -127,22 +232,36 @@ static inline void mmc_fixup_device(struct mmc_card *card,
u64 rev = cid_rev_card(card);
for (f = table; f->vendor_fixup; f++) {
- if ((f->manfid == CID_MANFID_ANY ||
- f->manfid == card->cid.manfid) &&
- (f->oemid == CID_OEMID_ANY ||
- f->oemid == card->cid.oemid) &&
- (f->name == CID_NAME_ANY ||
- !strncmp(f->name, card->cid.prod_name,
- sizeof(card->cid.prod_name))) &&
- (f->cis_vendor == card->cis.vendor ||
- f->cis_vendor == (u16) SDIO_ANY_ID) &&
- (f->cis_device == card->cis.device ||
- f->cis_device == (u16) SDIO_ANY_ID) &&
- (f->ext_csd_rev == EXT_CSD_REV_ANY ||
- f->ext_csd_rev == card->ext_csd.rev) &&
- rev >= f->rev_start && rev <= f->rev_end) {
- dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup);
- f->vendor_fixup(card, f->data);
- }
+ if (f->manfid != CID_MANFID_ANY &&
+ f->manfid != card->cid.manfid)
+ continue;
+ if (f->oemid != CID_OEMID_ANY &&
+ f->oemid != card->cid.oemid)
+ continue;
+ if (f->name != CID_NAME_ANY &&
+ strncmp(f->name, card->cid.prod_name,
+ sizeof(card->cid.prod_name)))
+ continue;
+ if (f->cis_vendor != (u16)SDIO_ANY_ID &&
+ f->cis_vendor != card->cis.vendor)
+ continue;
+ if (f->cis_device != (u16)SDIO_ANY_ID &&
+ f->cis_device != card->cis.device)
+ continue;
+ if (f->ext_csd_rev != EXT_CSD_REV_ANY &&
+ f->ext_csd_rev != card->ext_csd.rev)
+ continue;
+ if (rev < f->rev_start || rev > f->rev_end)
+ continue;
+ if (f->of_compatible &&
+ !mmc_fixup_of_compatible_match(card, f->of_compatible))
+ continue;
+ if (f->year != CID_YEAR_ANY && f->year != card->cid.year)
+ continue;
+ if (f->month != CID_MONTH_ANY && f->month != card->cid.month)
+ continue;
+
+ dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup);
+ f->vendor_fixup(card, f->data);
}
}
diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c
new file mode 100644
index 000000000000..a85179f1a4de
--- /dev/null
+++ b/drivers/mmc/core/regulator.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Helper functions for MMC regulators.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/log2.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+
+#include <linux/mmc/host.h>
+
+#include "core.h"
+#include "host.h"
+
+#ifdef CONFIG_REGULATOR
+
+/**
+ * mmc_ocrbitnum_to_vdd - Convert a OCR bit number to its voltage
+ * @vdd_bit: OCR bit number
+ * @min_uV: minimum voltage value (mV)
+ * @max_uV: maximum voltage value (mV)
+ *
+ * This function returns the voltage range according to the provided OCR
+ * bit number. If conversion is not possible a negative errno value returned.
+ */
+static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV)
+{
+ int tmp;
+
+ if (!vdd_bit)
+ return -EINVAL;
+
+ /*
+ * REVISIT mmc_vddrange_to_ocrmask() may have set some
+ * bits this regulator doesn't quite support ... don't
+ * be too picky, most cards and regulators are OK with
+ * a 0.1V range goof (it's a small error percentage).
+ */
+ tmp = vdd_bit - ilog2(MMC_VDD_165_195);
+ if (tmp == 0) {
+ *min_uV = 1650 * 1000;
+ *max_uV = 1950 * 1000;
+ } else {
+ *min_uV = 1900 * 1000 + tmp * 100 * 1000;
+ *max_uV = *min_uV + 100 * 1000;
+ }
+
+ return 0;
+}
+
+/**
+ * mmc_regulator_get_ocrmask - return mask of supported voltages
+ * @supply: regulator to use
+ *
+ * This returns either a negative errno, or a mask of voltages that
+ * can be provided to MMC/SD/SDIO devices using the specified voltage
+ * regulator. This would normally be called before registering the
+ * MMC host adapter.
+ */
+static int mmc_regulator_get_ocrmask(struct regulator *supply)
+{
+ int result = 0;
+ int count;
+ int i;
+ int vdd_uV;
+ int vdd_mV;
+
+ count = regulator_count_voltages(supply);
+ if (count < 0)
+ return count;
+
+ for (i = 0; i < count; i++) {
+ vdd_uV = regulator_list_voltage(supply, i);
+ if (vdd_uV <= 0)
+ continue;
+
+ vdd_mV = vdd_uV / 1000;
+ result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
+ }
+
+ if (!result) {
+ vdd_uV = regulator_get_voltage(supply);
+ if (vdd_uV <= 0)
+ return vdd_uV;
+
+ vdd_mV = vdd_uV / 1000;
+ result = mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
+ }
+
+ return result;
+}
+
+/**
+ * mmc_regulator_set_ocr - set regulator to match host->ios voltage
+ * @mmc: the host to regulate
+ * @supply: regulator to use
+ * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * MMC host drivers may use this to enable or disable a regulator using
+ * a particular supply voltage. This would normally be called from the
+ * set_ios() method.
+ */
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+ struct regulator *supply,
+ unsigned short vdd_bit)
+{
+ int result = 0;
+ int min_uV, max_uV;
+
+ if (IS_ERR(supply))
+ return 0;
+
+ if (vdd_bit) {
+ mmc_ocrbitnum_to_vdd(vdd_bit, &min_uV, &max_uV);
+
+ result = regulator_set_voltage(supply, min_uV, max_uV);
+ if (result == 0 && !mmc->regulator_enabled) {
+ result = regulator_enable(supply);
+ if (!result)
+ mmc->regulator_enabled = true;
+ }
+ } else if (mmc->regulator_enabled) {
+ result = regulator_disable(supply);
+ if (result == 0)
+ mmc->regulator_enabled = false;
+ }
+
+ if (result)
+ dev_err(mmc_dev(mmc),
+ "could not set regulator OCR (%d)\n", result);
+ return result;
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr);
+
+static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator,
+ int min_uV, int target_uV,
+ int max_uV)
+{
+ int current_uV;
+
+ /*
+ * Check if supported first to avoid errors since we may try several
+ * signal levels during power up and don't want to show errors.
+ */
+ if (!regulator_is_supported_voltage(regulator, min_uV, max_uV))
+ return -EINVAL;
+
+ /*
+ * The voltage is already set, no need to switch.
+ * Return 1 to indicate that no switch happened.
+ */
+ current_uV = regulator_get_voltage(regulator);
+ if (current_uV == target_uV)
+ return 1;
+
+ return regulator_set_voltage_triplet(regulator, min_uV, target_uV,
+ max_uV);
+}
+
+/**
+ * mmc_regulator_set_vqmmc - Set VQMMC as per the ios
+ * @mmc: the host to regulate
+ * @ios: io bus settings
+ *
+ * For 3.3V signaling, we try to match VQMMC to VMMC as closely as possible.
+ * That will match the behavior of old boards where VQMMC and VMMC were supplied
+ * by the same supply. The Bus Operating conditions for 3.3V signaling in the
+ * SD card spec also define VQMMC in terms of VMMC.
+ * If this is not possible we'll try the full 2.7-3.6V of the spec.
+ *
+ * For 1.2V and 1.8V signaling we'll try to get as close as possible to the
+ * requested voltage. This is definitely a good idea for UHS where there's a
+ * separate regulator on the card that's trying to make 1.8V and it's best if
+ * we match.
+ *
+ * This function is expected to be used by a controller's
+ * start_signal_voltage_switch() function.
+ */
+int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct device *dev = mmc_dev(mmc);
+ int ret, volt, min_uV, max_uV;
+
+ /* If no vqmmc supply then we can't change the voltage */
+ if (IS_ERR(mmc->supply.vqmmc))
+ return -EINVAL;
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_120:
+ return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
+ 1100000, 1200000, 1300000);
+ case MMC_SIGNAL_VOLTAGE_180:
+ return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
+ 1700000, 1800000, 1950000);
+ case MMC_SIGNAL_VOLTAGE_330:
+ ret = mmc_ocrbitnum_to_vdd(mmc->ios.vdd, &volt, &max_uV);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "%s: found vmmc voltage range of %d-%duV\n",
+ __func__, volt, max_uV);
+
+ min_uV = max(volt - 300000, 2700000);
+ max_uV = min(max_uV + 200000, 3600000);
+
+ /*
+ * Due to a limitation in the current implementation of
+ * regulator_set_voltage_triplet() which is taking the lowest
+ * voltage possible if below the target, search for a suitable
+ * voltage in two steps and try to stay close to vmmc
+ * with a 0.3V tolerance at first.
+ */
+ ret = mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
+ min_uV, volt, max_uV);
+ if (ret >= 0)
+ return ret;
+
+ return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
+ 2700000, volt, 3600000);
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc);
+
+/**
+ * mmc_regulator_set_vqmmc2 - Set vqmmc2 as per the ios->vqmmc2_voltage
+ * @mmc: The mmc host to regulate
+ * @ios: The io bus settings
+ *
+ * Sets a new voltage level for the vqmmc2 regulator, which may correspond to
+ * the vdd2 regulator for an SD UHS-II interface. This function is expected to
+ * be called by mmc host drivers.
+ *
+ * Returns a negative error code on failure, zero if the voltage level was
+ * changed successfully or a positive value if the level didn't need to change.
+ */
+int mmc_regulator_set_vqmmc2(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ if (IS_ERR(mmc->supply.vqmmc2))
+ return -EINVAL;
+
+ switch (ios->vqmmc2_voltage) {
+ case MMC_VQMMC2_VOLTAGE_180:
+ return mmc_regulator_set_voltage_if_supported(
+ mmc->supply.vqmmc2, 1700000, 1800000, 1950000);
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc2);
+
+#else
+
+static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
+{
+ return 0;
+}
+
+#endif /* CONFIG_REGULATOR */
+
+/* To be called from a high-priority workqueue */
+void mmc_undervoltage_workfn(struct work_struct *work)
+{
+ struct mmc_supply *supply;
+ struct mmc_host *host;
+
+ supply = container_of(work, struct mmc_supply, uv_work);
+ host = container_of(supply, struct mmc_host, supply);
+
+ mmc_handle_undervoltage(host);
+}
+
+static int mmc_handle_regulator_event(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct mmc_supply *supply = container_of(nb, struct mmc_supply,
+ vmmc_nb);
+ struct mmc_host *host = container_of(supply, struct mmc_host, supply);
+ unsigned long flags;
+
+ switch (event) {
+ case REGULATOR_EVENT_UNDER_VOLTAGE:
+ spin_lock_irqsave(&host->lock, flags);
+ if (host->undervoltage) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return NOTIFY_OK;
+ }
+
+ host->undervoltage = true;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ queue_work(system_highpri_wq, &host->supply.uv_work);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+/**
+ * mmc_regulator_register_undervoltage_notifier - Register for undervoltage
+ * events
+ * @host: MMC host
+ *
+ * To be called by a bus driver when a card supporting graceful shutdown
+ * is attached.
+ */
+void mmc_regulator_register_undervoltage_notifier(struct mmc_host *host)
+{
+ int ret;
+
+ if (IS_ERR_OR_NULL(host->supply.vmmc))
+ return;
+
+ host->supply.vmmc_nb.notifier_call = mmc_handle_regulator_event;
+ ret = regulator_register_notifier(host->supply.vmmc,
+ &host->supply.vmmc_nb);
+ if (ret)
+ dev_warn(mmc_dev(host), "Failed to register vmmc notifier: %d\n", ret);
+}
+
+/**
+ * mmc_regulator_unregister_undervoltage_notifier - Unregister undervoltage
+ * notifier
+ * @host: MMC host
+ */
+void mmc_regulator_unregister_undervoltage_notifier(struct mmc_host *host)
+{
+ if (IS_ERR_OR_NULL(host->supply.vmmc))
+ return;
+
+ regulator_unregister_notifier(host->supply.vmmc, &host->supply.vmmc_nb);
+ cancel_work_sync(&host->supply.uv_work);
+}
+
+/**
+ * mmc_regulator_get_supply - try to get VMMC and VQMMC regulators for a host
+ * @mmc: the host to regulate
+ *
+ * Returns 0 or errno. errno should be handled, it is either a critical error
+ * or -EPROBE_DEFER. 0 means no critical error but it does not mean all
+ * regulators have been found because they all are optional. If you require
+ * certain regulators, you need to check separately in your driver if they got
+ * populated after calling this function.
+ */
+int mmc_regulator_get_supply(struct mmc_host *mmc)
+{
+ struct device *dev = mmc_dev(mmc);
+ int ret;
+
+ mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
+ mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
+ mmc->supply.vqmmc2 = devm_regulator_get_optional(dev, "vqmmc2");
+
+ if (IS_ERR(mmc->supply.vmmc)) {
+ if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "vmmc regulator not available\n");
+
+ dev_dbg(dev, "No vmmc regulator found\n");
+ } else {
+ ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
+ if (ret > 0)
+ mmc->ocr_avail = ret;
+ else
+ dev_warn(dev, "Failed getting OCR mask: %d\n", ret);
+ }
+
+ if (IS_ERR(mmc->supply.vqmmc)) {
+ if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER)
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "vqmmc regulator not available\n");
+
+ dev_dbg(dev, "No vqmmc regulator found\n");
+ }
+
+ if (IS_ERR(mmc->supply.vqmmc2)) {
+ if (PTR_ERR(mmc->supply.vqmmc2) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_dbg(dev, "No vqmmc2 regulator found\n");
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
+
+/**
+ * mmc_regulator_enable_vqmmc - enable VQMMC regulator for a host
+ * @mmc: the host to regulate
+ *
+ * Returns 0 or errno. Enables the regulator for vqmmc.
+ * Keeps track of the enable status for ensuring that calls to
+ * regulator_enable/disable are balanced.
+ */
+int mmc_regulator_enable_vqmmc(struct mmc_host *mmc)
+{
+ int ret = 0;
+
+ if (!IS_ERR(mmc->supply.vqmmc) && !mmc->vqmmc_enabled) {
+ ret = regulator_enable(mmc->supply.vqmmc);
+ if (ret < 0)
+ dev_err(mmc_dev(mmc), "enabling vqmmc regulator failed\n");
+ else
+ mmc->vqmmc_enabled = true;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_enable_vqmmc);
+
+/**
+ * mmc_regulator_disable_vqmmc - disable VQMMC regulator for a host
+ * @mmc: the host to regulate
+ *
+ * Returns 0 or errno. Disables the regulator for vqmmc.
+ * Keeps track of the enable status for ensuring that calls to
+ * regulator_enable/disable are balanced.
+ */
+void mmc_regulator_disable_vqmmc(struct mmc_host *mmc)
+{
+ if (!IS_ERR(mmc->supply.vqmmc) && mmc->vqmmc_enabled) {
+ regulator_disable(mmc->supply.vqmmc);
+ mmc->vqmmc_enabled = false;
+ }
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_disable_vqmmc);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index a1b0aa14d5e3..948948ca9b4a 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1,20 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/mmc/core/sd.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/string.h>
#include <linux/pm_runtime.h>
+#include <linux/random.h>
+#include <linux/scatterlist.h>
+#include <linux/sysfs.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@@ -26,6 +27,7 @@
#include "host.h"
#include "bus.h"
#include "mmc_ops.h"
+#include "quirks.h"
#include "sd.h"
#include "sd_ops.h"
@@ -39,11 +41,11 @@ static const unsigned char tran_mant[] = {
35, 40, 45, 50, 55, 60, 70, 80,
};
-static const unsigned int tacc_exp[] = {
+static const unsigned int taac_exp[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
-static const unsigned int tacc_mant[] = {
+static const unsigned int taac_mant[] = {
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
@@ -55,19 +57,13 @@ static const unsigned int sd_au_size[] = {
SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512,
};
-#define UNSTUFF_BITS(resp,start,size) \
- ({ \
- const int __size = size; \
- const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
- const int __off = 3 - ((start) / 32); \
- const int __shft = (start) & 31; \
- u32 __res; \
- \
- __res = resp[__off] >> __shft; \
- if (__size + __shft > 32) \
- __res |= resp[__off-1] << ((32 - __shft) % 32); \
- __res & __mask; \
- })
+#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 1000
+#define SD_WRITE_EXTR_SINGLE_TIMEOUT_MS 1000
+
+struct sd_busy_data {
+ struct mmc_card *card;
+ u8 *reg_buf;
+};
/*
* Given the decoded CSD structure, decode the raw CID to our CID structure.
@@ -77,92 +73,110 @@ void mmc_decode_cid(struct mmc_card *card)
u32 *resp = card->raw_cid;
/*
+ * Add the raw card ID (cid) data to the entropy pool. It doesn't
+ * matter that not all of it is unique, it's just bonus entropy.
+ */
+ add_device_randomness(&card->raw_cid, sizeof(card->raw_cid));
+
+ /*
* SD doesn't currently have a version field so we will
* have to assume we can parse this.
*/
- card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
- card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
- card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
- card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
- card->cid.year = UNSTUFF_BITS(resp, 12, 8);
- card->cid.month = UNSTUFF_BITS(resp, 8, 4);
+ card->cid.manfid = unstuff_bits(resp, 120, 8);
+ card->cid.oemid = unstuff_bits(resp, 104, 16);
+ card->cid.prod_name[0] = unstuff_bits(resp, 96, 8);
+ card->cid.prod_name[1] = unstuff_bits(resp, 88, 8);
+ card->cid.prod_name[2] = unstuff_bits(resp, 80, 8);
+ card->cid.prod_name[3] = unstuff_bits(resp, 72, 8);
+ card->cid.prod_name[4] = unstuff_bits(resp, 64, 8);
+ card->cid.hwrev = unstuff_bits(resp, 60, 4);
+ card->cid.fwrev = unstuff_bits(resp, 56, 4);
+ card->cid.serial = unstuff_bits(resp, 24, 32);
+ card->cid.year = unstuff_bits(resp, 12, 8);
+ card->cid.month = unstuff_bits(resp, 8, 4);
card->cid.year += 2000; /* SD cards year offset */
+
+ /* some product names may include trailing whitespace */
+ strim(card->cid.prod_name);
}
/*
* Given a 128-bit response, decode to our card CSD structure.
*/
-static int mmc_decode_csd(struct mmc_card *card)
+static int mmc_decode_csd(struct mmc_card *card, bool is_sduc)
{
struct mmc_csd *csd = &card->csd;
unsigned int e, m, csd_struct;
u32 *resp = card->raw_csd;
- csd_struct = UNSTUFF_BITS(resp, 126, 2);
+ csd_struct = unstuff_bits(resp, 126, 2);
switch (csd_struct) {
case 0:
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+ m = unstuff_bits(resp, 115, 4);
+ e = unstuff_bits(resp, 112, 3);
+ csd->taac_ns = (taac_exp[e] * taac_mant[m] + 9) / 10;
+ csd->taac_clks = unstuff_bits(resp, 104, 8) * 100;
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
+ m = unstuff_bits(resp, 99, 4);
+ e = unstuff_bits(resp, 96, 3);
csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+ csd->cmdclass = unstuff_bits(resp, 84, 12);
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
+ e = unstuff_bits(resp, 47, 3);
+ m = unstuff_bits(resp, 62, 12);
csd->capacity = (1 + m) << (e + 2);
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ csd->read_blkbits = unstuff_bits(resp, 80, 4);
+ csd->read_partial = unstuff_bits(resp, 79, 1);
+ csd->write_misalign = unstuff_bits(resp, 78, 1);
+ csd->read_misalign = unstuff_bits(resp, 77, 1);
+ csd->dsr_imp = unstuff_bits(resp, 76, 1);
+ csd->r2w_factor = unstuff_bits(resp, 26, 3);
+ csd->write_blkbits = unstuff_bits(resp, 22, 4);
+ csd->write_partial = unstuff_bits(resp, 21, 1);
- if (UNSTUFF_BITS(resp, 46, 1)) {
+ if (unstuff_bits(resp, 46, 1)) {
csd->erase_size = 1;
} else if (csd->write_blkbits >= 9) {
- csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1;
+ csd->erase_size = unstuff_bits(resp, 39, 7) + 1;
csd->erase_size <<= csd->write_blkbits - 9;
}
+
+ if (unstuff_bits(resp, 13, 1))
+ mmc_card_set_readonly(card);
break;
case 1:
+ case 2:
/*
- * This is a block-addressed SDHC or SDXC card. Most
- * interesting fields are unused and have fixed
+ * This is a block-addressed SDHC, SDXC or SDUC card.
+ * Most interesting fields are unused and have fixed
* values. To avoid getting tripped by buggy cards,
* we assume those fixed values ourselves.
*/
mmc_card_set_blockaddr(card);
- csd->tacc_ns = 0; /* Unused */
- csd->tacc_clks = 0; /* Unused */
+ csd->taac_ns = 0; /* Unused */
+ csd->taac_clks = 0; /* Unused */
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
+ m = unstuff_bits(resp, 99, 4);
+ e = unstuff_bits(resp, 96, 3);
csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
- csd->c_size = UNSTUFF_BITS(resp, 48, 22);
+ csd->cmdclass = unstuff_bits(resp, 84, 12);
+
+ if (csd_struct == 1)
+ m = unstuff_bits(resp, 48, 22);
+ else
+ m = unstuff_bits(resp, 48, 28);
+ csd->c_size = m;
- /* SDXC cards have a minimum C_SIZE of 0x00FFFF */
- if (csd->c_size >= 0xFFFF)
+ if (csd->c_size >= 0x400000 && is_sduc)
+ mmc_card_set_ult_capacity(card);
+ else if (csd->c_size >= 0xFFFF)
mmc_card_set_ext_capacity(card);
- m = UNSTUFF_BITS(resp, 48, 22);
- csd->capacity = (1 + m) << 10;
+ csd->capacity = (1 + (typeof(sector_t))m) << 10;
csd->read_blkbits = 9;
csd->read_partial = 0;
@@ -172,6 +186,9 @@ static int mmc_decode_csd(struct mmc_card *card)
csd->write_blkbits = 9;
csd->write_partial = 0;
csd->erase_size = 1;
+
+ if (unstuff_bits(resp, 13, 1))
+ mmc_card_set_readonly(card);
break;
default:
pr_err("%s: unrecognised CSD structure version %d\n",
@@ -187,7 +204,7 @@ static int mmc_decode_csd(struct mmc_card *card)
/*
* Given a 64-bit response, decode to our card SCR structure.
*/
-static int mmc_decode_scr(struct mmc_card *card)
+int mmc_decode_scr(struct mmc_card *card)
{
struct sd_scr *scr = &card->scr;
unsigned int scr_struct;
@@ -196,26 +213,41 @@ static int mmc_decode_scr(struct mmc_card *card)
resp[3] = card->raw_scr[1];
resp[2] = card->raw_scr[0];
- scr_struct = UNSTUFF_BITS(resp, 60, 4);
+ scr_struct = unstuff_bits(resp, 60, 4);
if (scr_struct != 0) {
pr_err("%s: unrecognised SCR structure version %d\n",
mmc_hostname(card->host), scr_struct);
return -EINVAL;
}
- scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
- scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+ scr->sda_vsn = unstuff_bits(resp, 56, 4);
+ scr->bus_widths = unstuff_bits(resp, 48, 4);
if (scr->sda_vsn == SCR_SPEC_VER_2)
/* Check if Physical Layer Spec v3.0 is supported */
- scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1);
+ scr->sda_spec3 = unstuff_bits(resp, 47, 1);
- if (UNSTUFF_BITS(resp, 55, 1))
+ if (scr->sda_spec3) {
+ scr->sda_spec4 = unstuff_bits(resp, 42, 1);
+ scr->sda_specx = unstuff_bits(resp, 38, 4);
+ }
+
+ if (unstuff_bits(resp, 55, 1))
card->erased_byte = 0xFF;
else
card->erased_byte = 0x0;
- if (scr->sda_spec3)
- scr->cmds = UNSTUFF_BITS(resp, 32, 2);
+ if (scr->sda_spec4)
+ scr->cmds = unstuff_bits(resp, 32, 4);
+ else if (scr->sda_spec3)
+ scr->cmds = unstuff_bits(resp, 32, 2);
+
+ /* SD Spec says: any SD Card shall set at least bits 0 and 2 */
+ if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) ||
+ !(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ pr_err("%s: invalid bus width\n", mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
return 0;
}
@@ -226,6 +258,8 @@ static int mmc_read_ssr(struct mmc_card *card)
{
unsigned int au, es, et, eo;
__be32 *raw_ssr;
+ u32 resp[4] = {};
+ u8 discard_support;
int i;
if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
@@ -251,17 +285,17 @@ static int mmc_read_ssr(struct mmc_card *card)
kfree(raw_ssr);
/*
- * UNSTUFF_BITS only works with four u32s so we have to offset the
+ * unstuff_bits only works with four u32s so we have to offset the
* bitfield positions accordingly.
*/
- au = UNSTUFF_BITS(card->raw_ssr, 428 - 384, 4);
+ au = unstuff_bits(card->raw_ssr, 428 - 384, 4);
if (au) {
if (au <= 9 || card->scr.sda_spec3) {
card->ssr.au = sd_au_size[au];
- es = UNSTUFF_BITS(card->raw_ssr, 408 - 384, 16);
- et = UNSTUFF_BITS(card->raw_ssr, 402 - 384, 6);
+ es = unstuff_bits(card->raw_ssr, 408 - 384, 16);
+ et = unstuff_bits(card->raw_ssr, 402 - 384, 6);
if (es && et) {
- eo = UNSTUFF_BITS(card->raw_ssr, 400 - 384, 2);
+ eo = unstuff_bits(card->raw_ssr, 400 - 384, 2);
card->ssr.erase_timeout = (et * 1000) / es;
card->ssr.erase_offset = eo * 1000;
}
@@ -271,6 +305,14 @@ static int mmc_read_ssr(struct mmc_card *card)
}
}
+ /*
+ * starting SD5.1 discard is supported if DISCARD_SUPPORT (b313) is set
+ */
+ resp[3] = card->raw_ssr[6];
+ discard_support = unstuff_bits(resp, 313 - 288, 1);
+ card->erase_arg = (card->scr.sda_specx && discard_support) ?
+ SD_DISCARD_ARG : SD_ERASE_ARG;
+
return 0;
}
@@ -291,8 +333,6 @@ static int mmc_read_switch(struct mmc_card *card)
return 0;
}
- err = -EIO;
-
status = kmalloc(64, GFP_KERNEL);
if (!status)
return -ENOMEM;
@@ -302,7 +342,7 @@ static int mmc_read_switch(struct mmc_card *card)
* The argument does not matter, as the support bits do not
* change with the arguments.
*/
- err = mmc_sd_switch(card, 0, 0, 0, status);
+ err = mmc_sd_switch(card, SD_SWITCH_CHECK, 0, 0, status);
if (err) {
/*
* If the host or the card can't do the switch,
@@ -319,7 +359,7 @@ static int mmc_read_switch(struct mmc_card *card)
}
if (status[13] & SD_MODE_HIGH_SPEED)
- card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR;
+ card->sw_caps.hs_max_dtr = card->host->max_sd_hs_hz ?: HIGH_SPEED_MAX_DTR;
if (card->scr.sda_spec3) {
card->sw_caps.sd3_bus_mode = status[13];
@@ -358,11 +398,12 @@ int mmc_sd_switch_hs(struct mmc_card *card)
if (!status)
return -ENOMEM;
- err = mmc_sd_switch(card, 1, 0, 1, status);
+ err = mmc_sd_switch(card, SD_SWITCH_SET, 0,
+ HIGH_SPEED_BUS_SPEED, status);
if (err)
goto out;
- if ((status[16] & 0xF) != 1) {
+ if ((status[16] & 0xF) != HIGH_SPEED_BUS_SPEED) {
pr_warn("%s: Problem switching card into high-speed mode!\n",
mmc_hostname(card->host));
err = 0;
@@ -390,7 +431,8 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
card_drv_type, &drv_type);
if (drive_strength) {
- err = mmc_sd_switch(card, 1, 2, drive_strength, status);
+ err = mmc_sd_switch(card, SD_SWITCH_SET, 2,
+ drive_strength, status);
if (err)
return err;
if ((status[15] & 0xF) != drive_strength) {
@@ -413,7 +455,7 @@ static void sd_update_bus_speed_mode(struct mmc_card *card)
* If the host doesn't support any of the UHS-I modes, fallback on
* default speed.
*/
- if (!mmc_host_uhs(card->host)) {
+ if (!mmc_host_can_uhs(card->host)) {
card->sd_bus_speed = 0;
return;
}
@@ -470,7 +512,7 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
return 0;
}
- err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status);
+ err = mmc_sd_switch(card, SD_SWITCH_SET, 0, card->sd_bus_speed, status);
if (err)
return err;
@@ -512,7 +554,7 @@ static u32 sd_get_host_max_current(struct mmc_host *host)
static int sd_set_current_limit(struct mmc_card *card, u8 *status)
{
- int current_limit = SD_SET_CURRENT_NO_CHANGE;
+ int current_limit = SD_SET_CURRENT_LIMIT_200;
int err;
u32 max_current;
@@ -556,12 +598,10 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status)
else if (max_current >= 400 &&
card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
current_limit = SD_SET_CURRENT_LIMIT_400;
- else if (max_current >= 200 &&
- card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
- current_limit = SD_SET_CURRENT_LIMIT_200;
- if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
- err = mmc_sd_switch(card, 1, 3, current_limit, status);
+ if (current_limit != SD_SET_CURRENT_LIMIT_200) {
+ err = mmc_sd_switch(card, SD_SWITCH_SET, 3,
+ current_limit, status);
if (err)
return err;
@@ -575,6 +615,29 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status)
}
/*
+ * Determine if the card should tune or not.
+ */
+static bool mmc_sd_use_tuning(struct mmc_card *card)
+{
+ /*
+ * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
+ * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
+ */
+ if (mmc_host_is_spi(card->host))
+ return false;
+
+ switch (card->host->ios.timing) {
+ case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_SDR104:
+ return true;
+ case MMC_TIMING_UHS_DDR50:
+ return !mmc_card_no_uhs_ddr50_tuning(card);
+ }
+
+ return false;
+}
+
+/*
* UHS-I specific initialization procedure
*/
static int mmc_sd_init_uhs_card(struct mmc_card *card)
@@ -582,9 +645,6 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
int err;
u8 *status;
- if (!card->scr.sda_spec3)
- return 0;
-
if (!(card->csd.cmdclass & CCC_SWITCH))
return 0;
@@ -593,14 +653,11 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
return -ENOMEM;
/* Set 4-bit bus width */
- if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
- err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err)
- goto out;
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+ if (err)
+ goto out;
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- }
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
/*
* Select the bus speed mode depending on host
@@ -623,14 +680,7 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
if (err)
goto out;
- /*
- * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
- * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
- */
- if (!mmc_host_is_spi(card->host) &&
- (card->host->ios.timing == MMC_TIMING_UHS_SDR50 ||
- card->host->ios.timing == MMC_TIMING_UHS_DDR50 ||
- card->host->ios.timing == MMC_TIMING_UHS_SDR104)) {
+ if (mmc_sd_use_tuning(card)) {
err = mmc_execute_tuning(card);
/*
@@ -675,26 +725,54 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
-MMC_DEV_ATTR(ocr, "%08x\n", card->ocr);
+MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
+MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
-static ssize_t mmc_dsr_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t mmc_dsr_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct mmc_card *card = mmc_dev_to_card(dev);
- struct mmc_host *host = card->host;
-
- if (card->csd.dsr_imp && host->dsr_req)
- return sprintf(buf, "0x%x\n", host->dsr);
- else
- /* return default DSR value */
- return sprintf(buf, "0x%x\n", 0x404);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+ struct mmc_host *host = card->host;
+
+ if (card->csd.dsr_imp && host->dsr_req)
+ return sysfs_emit(buf, "0x%x\n", host->dsr);
+ /* return default DSR value */
+ return sysfs_emit(buf, "0x%x\n", 0x404);
}
-static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
+static DEVICE_ATTR(dsr, 0444, mmc_dsr_show, NULL);
+
+MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor);
+MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device);
+MMC_DEV_ATTR(revision, "%u.%u\n", card->major_rev, card->minor_rev);
+
+#define sdio_info_attr(num) \
+static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct mmc_card *card = mmc_dev_to_card(dev); \
+ \
+ if (num > card->num_info) \
+ return -ENODATA; \
+ if (!card->info[num - 1][0]) \
+ return 0; \
+ return sysfs_emit(buf, "%s\n", card->info[num - 1]); \
+} \
+static DEVICE_ATTR_RO(info##num)
+
+sdio_info_attr(1);
+sdio_info_attr(2);
+sdio_info_attr(3);
+sdio_info_attr(4);
static struct attribute *sd_std_attrs[] = {
+ &dev_attr_vendor.attr,
+ &dev_attr_device.attr,
+ &dev_attr_revision.attr,
+ &dev_attr_info1.attr,
+ &dev_attr_info2.attr,
+ &dev_attr_info3.attr,
+ &dev_attr_info4.attr,
&dev_attr_cid.attr,
&dev_attr_csd.attr,
&dev_attr_scr.attr,
@@ -709,12 +787,38 @@ static struct attribute *sd_std_attrs[] = {
&dev_attr_oemid.attr,
&dev_attr_serial.attr,
&dev_attr_ocr.attr,
+ &dev_attr_rca.attr,
&dev_attr_dsr.attr,
NULL,
};
-ATTRIBUTE_GROUPS(sd_std);
-struct device_type sd_type = {
+static umode_t sd_std_is_visible(struct kobject *kobj, struct attribute *attr,
+ int index)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
+ /* CIS vendor and device ids, revision and info string are available only for Combo cards */
+ if ((attr == &dev_attr_vendor.attr ||
+ attr == &dev_attr_device.attr ||
+ attr == &dev_attr_revision.attr ||
+ attr == &dev_attr_info1.attr ||
+ attr == &dev_attr_info2.attr ||
+ attr == &dev_attr_info3.attr ||
+ attr == &dev_attr_info4.attr
+ ) &&!mmc_card_sd_combo(card))
+ return 0;
+
+ return attr->mode;
+}
+
+static const struct attribute_group sd_std_group = {
+ .attrs = sd_std_attrs,
+ .is_visible = sd_std_is_visible,
+};
+__ATTRIBUTE_GROUPS(sd_std);
+
+const struct device_type sd_type = {
.groups = sd_std_groups,
};
@@ -749,15 +853,18 @@ try_again:
* block-addressed SDHC cards.
*/
err = mmc_send_if_cond(host, ocr);
- if (!err)
+ if (!err) {
ocr |= SD_OCR_CCS;
+ /* Set HO2T as well - SDUC card won't respond otherwise */
+ ocr |= SD_OCR_2T;
+ }
/*
* If the host supports one of UHS-I modes, request the card
* to switch to 1.8V signaling level. If the card has failed
* repeatedly to switch however, skip this.
*/
- if (retries && mmc_host_uhs(host))
+ if (retries && mmc_host_can_uhs(host))
ocr |= SD_OCR_S18R;
/*
@@ -773,11 +880,14 @@ try_again:
return err;
/*
- * In case CCS and S18A in the response is set, start Signal Voltage
- * Switch procedure. SPI mode doesn't support CMD11.
+ * In case the S18A bit is set in the response, let's start the signal
+ * voltage switch procedure. SPI mode doesn't support CMD11.
+ * Note that, according to the spec, the S18A bit is not valid unless
+ * the CCS bit is set as well. We deliberately deviate from the spec in
+ * regards to this, which allows UHS-I to be supported for SDSC cards.
*/
- if (!mmc_host_is_spi(host) && rocr &&
- ((*rocr & 0x41000000) == 0x41000000)) {
+ if (!mmc_host_is_spi(host) && (ocr & SD_OCR_S18R) &&
+ rocr && (*rocr & SD_ROCR_S18A)) {
err = mmc_set_uhs_voltage(host, pocr);
if (err == -EAGAIN) {
retries--;
@@ -792,7 +902,7 @@ try_again:
return err;
}
-int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card)
+int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc)
{
int err;
@@ -803,14 +913,14 @@ int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card)
if (err)
return err;
- err = mmc_decode_csd(card);
+ err = mmc_decode_csd(card, is_sduc);
if (err)
return err;
return 0;
}
-static int mmc_sd_get_ro(struct mmc_host *host)
+int mmc_sd_get_ro(struct mmc_host *host)
{
int ro;
@@ -856,16 +966,17 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
/* Erase init depends on CSD and SSR */
mmc_init_erase(card);
-
- /*
- * Fetch switch information from card.
- */
- err = mmc_read_switch(card);
- if (err)
- return err;
}
/*
+ * Fetch switch information from card. Note, sd3_bus_mode can change if
+ * voltage switch outcome changes, so do this always.
+ */
+ err = mmc_read_switch(card);
+ if (err)
+ return err;
+
+ /*
* For SPI, enable CRC as appropriate.
* This CRC enable is located AFTER the reading of the
* card registers because some SDHC cards are not able
@@ -908,6 +1019,397 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
return max_dtr;
}
+static bool mmc_sd_card_using_v18(struct mmc_card *card)
+{
+ /*
+ * According to the SD spec., the Bus Speed Mode (function group 1) bits
+ * 2 to 4 are zero if the card is initialized at 3.3V signal level. Thus
+ * they can be used to determine if the card has already switched to
+ * 1.8V signaling.
+ */
+ return card->sw_caps.sd3_bus_mode &
+ (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
+}
+
+static int sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
+ u8 reg_data)
+{
+ struct mmc_host *host = card->host;
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
+ struct scatterlist sg;
+ u8 *reg_buf;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ /*
+ * Arguments of CMD49:
+ * [31:31] MIO (0 = memory).
+ * [30:27] FNO (function number).
+ * [26:26] MW - mask write mode (0 = disable).
+ * [25:18] page number.
+ * [17:9] offset address.
+ * [8:0] length (0 = 1 byte).
+ */
+ cmd.arg = fno << 27 | page << 18 | offset << 9;
+
+ /* The first byte in the buffer is the data to be written. */
+ reg_buf[0] = reg_data;
+
+ data.flags = MMC_DATA_WRITE;
+ data.blksz = 512;
+ data.blocks = 1;
+ data.sg = &sg;
+ data.sg_len = 1;
+ sg_init_one(&sg, reg_buf, 512);
+
+ cmd.opcode = SD_WRITE_EXTR_SINGLE;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ mmc_set_data_timeout(&data, card);
+ mmc_wait_for_req(host, &mrq);
+
+ kfree(reg_buf);
+
+ /*
+ * Note that, the SD card is allowed to signal busy on DAT0 up to 1s
+ * after the CMD49. Although, let's leave this to be managed by the
+ * caller.
+ */
+
+ if (cmd.error)
+ return cmd.error;
+ if (data.error)
+ return data.error;
+
+ return 0;
+}
+
+static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
+ u16 offset, u16 len, u8 *reg_buf)
+{
+ u32 cmd_args;
+
+ /*
+ * Command arguments of CMD48:
+ * [31:31] MIO (0 = memory).
+ * [30:27] FNO (function number).
+ * [26:26] reserved (0).
+ * [25:18] page number.
+ * [17:9] offset address.
+ * [8:0] length (0 = 1 byte, 1ff = 512 bytes).
+ */
+ cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1);
+
+ return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
+ cmd_args, reg_buf, 512);
+}
+
+static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
+ u16 offset)
+{
+ int err;
+ u8 *reg_buf;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ /* Read the extension register for power management function. */
+ err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+ if (err) {
+ pr_warn("%s: error %d reading PM func of ext reg\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* PM revision consists of 4 bits. */
+ card->ext_power.rev = reg_buf[0] & 0xf;
+
+ /* Power Off Notification support at bit 4. */
+ if ((reg_buf[1] & BIT(4)) && !mmc_card_broken_sd_poweroff_notify(card))
+ card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
+
+ /* Power Sustenance support at bit 5. */
+ if (reg_buf[1] & BIT(5))
+ card->ext_power.feature_support |= SD_EXT_POWER_SUSTENANCE;
+
+ /* Power Down Mode support at bit 6. */
+ if (reg_buf[1] & BIT(6))
+ card->ext_power.feature_support |= SD_EXT_POWER_DOWN_MODE;
+
+ card->ext_power.fno = fno;
+ card->ext_power.page = page;
+ card->ext_power.offset = offset;
+
+out:
+ kfree(reg_buf);
+ return err;
+}
+
+static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page,
+ u16 offset)
+{
+ int err;
+ u8 *reg_buf;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+ if (err) {
+ pr_warn("%s: error %d reading PERF func of ext reg\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* PERF revision. */
+ card->ext_perf.rev = reg_buf[0];
+
+ /* FX_EVENT support at bit 0. */
+ if (reg_buf[1] & BIT(0))
+ card->ext_perf.feature_support |= SD_EXT_PERF_FX_EVENT;
+
+ /* Card initiated self-maintenance support at bit 0. */
+ if (reg_buf[2] & BIT(0))
+ card->ext_perf.feature_support |= SD_EXT_PERF_CARD_MAINT;
+
+ /* Host initiated self-maintenance support at bit 1. */
+ if (reg_buf[2] & BIT(1))
+ card->ext_perf.feature_support |= SD_EXT_PERF_HOST_MAINT;
+
+ /* Cache support at bit 0. */
+ if ((reg_buf[4] & BIT(0)) && !mmc_card_broken_sd_cache(card))
+ card->ext_perf.feature_support |= SD_EXT_PERF_CACHE;
+
+ /* Command queue support indicated via queue depth bits (0 to 4). */
+ if (reg_buf[6] & 0x1f)
+ card->ext_perf.feature_support |= SD_EXT_PERF_CMD_QUEUE;
+
+ card->ext_perf.fno = fno;
+ card->ext_perf.page = page;
+ card->ext_perf.offset = offset;
+
+out:
+ kfree(reg_buf);
+ return err;
+}
+
+static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
+ u16 *next_ext_addr)
+{
+ u8 num_regs, fno, page;
+ u16 sfc, offset, ext = *next_ext_addr;
+ u32 reg_addr;
+
+ /*
+ * Parse only one register set per extension, as that is sufficient to
+ * support the standard functions. This means another 48 bytes in the
+ * buffer must be available.
+ */
+ if (ext + 48 > 512)
+ return -EFAULT;
+
+ /* Standard Function Code */
+ memcpy(&sfc, &gen_info_buf[ext], 2);
+
+ /* Address to the next extension. */
+ memcpy(next_ext_addr, &gen_info_buf[ext + 40], 2);
+
+ /* Number of registers for this extension. */
+ num_regs = gen_info_buf[ext + 42];
+
+ /* We support only one register per extension. */
+ if (num_regs != 1)
+ return 0;
+
+ /* Extension register address. */
+ memcpy(&reg_addr, &gen_info_buf[ext + 44], 4);
+
+ /* 9 bits (0 to 8) contains the offset address. */
+ offset = reg_addr & 0x1ff;
+
+ /* 8 bits (9 to 16) contains the page number. */
+ page = reg_addr >> 9 & 0xff ;
+
+ /* 4 bits (18 to 21) contains the function number. */
+ fno = reg_addr >> 18 & 0xf;
+
+ /* Standard Function Code for power management. */
+ if (sfc == 0x1)
+ return sd_parse_ext_reg_power(card, fno, page, offset);
+
+ /* Standard Function Code for performance enhancement. */
+ if (sfc == 0x2)
+ return sd_parse_ext_reg_perf(card, fno, page, offset);
+
+ return 0;
+}
+
+static int sd_read_ext_regs(struct mmc_card *card)
+{
+ int err, i;
+ u8 num_ext, *gen_info_buf;
+ u16 rev, len, next_ext_addr;
+
+ if (mmc_host_is_spi(card->host))
+ return 0;
+
+ if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT))
+ return 0;
+
+ gen_info_buf = kzalloc(512, GFP_KERNEL);
+ if (!gen_info_buf)
+ return -ENOMEM;
+
+ /*
+ * Read 512 bytes of general info, which is found at function number 0,
+ * at page 0 and with no offset.
+ */
+ err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
+ if (err) {
+ pr_err("%s: error %d reading general info of SD ext reg\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* General info structure revision. */
+ memcpy(&rev, &gen_info_buf[0], 2);
+
+ /* Length of general info in bytes. */
+ memcpy(&len, &gen_info_buf[2], 2);
+
+ /* Number of extensions to be find. */
+ num_ext = gen_info_buf[4];
+
+ /*
+ * We only support revision 0 and limit it to 512 bytes for simplicity.
+ * No matter what, let's return zero to allow us to continue using the
+ * card, even if we can't support the features from the SD function
+ * extensions registers.
+ */
+ if (rev != 0 || len > 512) {
+ pr_warn("%s: non-supported SD ext reg layout\n",
+ mmc_hostname(card->host));
+ goto out;
+ }
+
+ /*
+ * Parse the extension registers. The first extension should start
+ * immediately after the general info header (16 bytes).
+ */
+ next_ext_addr = 16;
+ for (i = 0; i < num_ext; i++) {
+ err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr);
+ if (err) {
+ pr_err("%s: error %d parsing SD ext reg\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+ }
+
+out:
+ kfree(gen_info_buf);
+ return err;
+}
+
+static bool sd_cache_enabled(struct mmc_host *host)
+{
+ return host->card->ext_perf.feature_enabled & SD_EXT_PERF_CACHE;
+}
+
+static int sd_flush_cache(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+ u8 *reg_buf, fno, page;
+ u16 offset;
+ int err;
+
+ if (!sd_cache_enabled(host))
+ return 0;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ /*
+ * Set Flush Cache at bit 0 in the performance enhancement register at
+ * 261 bytes offset.
+ */
+ fno = card->ext_perf.fno;
+ page = card->ext_perf.page;
+ offset = card->ext_perf.offset + 261;
+
+ err = sd_write_ext_reg(card, fno, page, offset, BIT(0));
+ if (err) {
+ pr_warn("%s: error %d writing Cache Flush bit\n",
+ mmc_hostname(host), err);
+ goto out;
+ }
+
+ err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+ MMC_BUSY_EXTR_SINGLE);
+ if (err)
+ goto out;
+
+ /*
+ * Read the Flush Cache bit. The card shall reset it, to confirm that
+ * it's has completed the flushing of the cache.
+ */
+ err = sd_read_ext_reg(card, fno, page, offset, 1, reg_buf);
+ if (err) {
+ pr_warn("%s: error %d reading Cache Flush bit\n",
+ mmc_hostname(host), err);
+ goto out;
+ }
+
+ if (reg_buf[0] & BIT(0))
+ err = -ETIMEDOUT;
+out:
+ kfree(reg_buf);
+ return err;
+}
+
+static int sd_enable_cache(struct mmc_card *card)
+{
+ u8 *reg_buf;
+ int err;
+
+ card->ext_perf.feature_enabled &= ~SD_EXT_PERF_CACHE;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ /*
+ * Set Cache Enable at bit 0 in the performance enhancement register at
+ * 260 bytes offset.
+ */
+ err = sd_write_ext_reg(card, card->ext_perf.fno, card->ext_perf.page,
+ card->ext_perf.offset + 260, BIT(0));
+ if (err) {
+ pr_warn("%s: error %d writing Cache Enable bit\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+ MMC_BUSY_EXTR_SINGLE);
+ if (!err)
+ card->ext_perf.feature_enabled |= SD_EXT_PERF_CACHE;
+
+out:
+ kfree(reg_buf);
+ return err;
+}
+
/*
* Handle the detection and initialisation of a card.
*
@@ -921,16 +1423,20 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
int err;
u32 cid[4];
u32 rocr = 0;
+ bool v18_fixup_failed = false;
WARN_ON(!host->claimed);
-
+retry:
err = mmc_sd_get_cid(host, ocr, cid, &rocr);
if (err)
return err;
if (oldcard) {
- if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+ if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
+ pr_debug("%s: Perhaps the card was replaced\n",
+ mmc_hostname(host));
return -ENOENT;
+ }
card = oldcard;
} else {
@@ -962,7 +1468,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
}
if (!oldcard) {
- err = mmc_sd_get_csd(host, card);
+ u32 sduc_arg = SD_OCR_CCS | SD_OCR_2T;
+ bool is_sduc = (rocr & sduc_arg) == sduc_arg;
+
+ err = mmc_sd_get_csd(card, is_sduc);
if (err)
goto free_card;
@@ -985,12 +1494,34 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
goto free_card;
}
+ /* Apply quirks prior to card setup */
+ mmc_fixup_device(card, mmc_sd_fixups);
+
err = mmc_sd_setup_card(host, card, oldcard != NULL);
if (err)
goto free_card;
+ /*
+ * If the card has not been power cycled, it may still be using 1.8V
+ * signaling. Detect that situation and try to initialize a UHS-I (1.8V)
+ * transfer mode.
+ */
+ if (!v18_fixup_failed && !mmc_host_is_spi(host) && mmc_host_can_uhs(host) &&
+ mmc_sd_card_using_v18(card) &&
+ host->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
+ if (mmc_host_set_uhs_voltage(host) ||
+ mmc_sd_init_uhs_card(card)) {
+ v18_fixup_failed = true;
+ mmc_power_cycle(host, ocr);
+ if (!oldcard)
+ mmc_remove_card(card);
+ goto retry;
+ }
+ goto cont;
+ }
+
/* Initialization sequence for UHS-I cards */
- if (rocr & SD_ROCR_S18A) {
+ if (rocr & SD_ROCR_S18A && mmc_host_can_uhs(host)) {
err = mmc_sd_init_uhs_card(card);
if (err)
goto free_card;
@@ -1009,6 +1540,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
*/
mmc_set_clock(host, mmc_sd_get_max_clock(card));
+ if (host->ios.timing == MMC_TIMING_SD_HS &&
+ host->ops->prepare_sd_hs_tuning) {
+ err = host->ops->prepare_sd_hs_tuning(host, card);
+ if (err)
+ goto free_card;
+ }
+
/*
* Switch to wider bus (if supported).
*/
@@ -1020,6 +1558,45 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
}
+
+ if (host->ios.timing == MMC_TIMING_SD_HS &&
+ host->ops->execute_sd_hs_tuning) {
+ err = host->ops->execute_sd_hs_tuning(host, card);
+ if (err)
+ goto free_card;
+ }
+ }
+cont:
+ if (!oldcard) {
+ /* Read/parse the extension registers. */
+ err = sd_read_ext_regs(card);
+ if (err)
+ goto free_card;
+ }
+
+ /* Enable internal SD cache if supported. */
+ if (card->ext_perf.feature_support & SD_EXT_PERF_CACHE) {
+ err = sd_enable_cache(card);
+ if (err)
+ goto free_card;
+ }
+
+ if (!mmc_card_ult_capacity(card) && host->cqe_ops && !host->cqe_enabled) {
+ err = host->cqe_ops->cqe_enable(host, card);
+ if (!err) {
+ host->cqe_enabled = true;
+ host->hsq_enabled = true;
+ pr_info("%s: Host Software Queue enabled\n",
+ mmc_hostname(host));
+ }
+ }
+
+ if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
+ host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+ pr_err("%s: Host failed to negotiate down from 3.3V\n",
+ mmc_hostname(host));
+ err = -EINVAL;
+ goto free_card;
}
host->card = card;
@@ -1033,15 +1610,6 @@ free_card:
}
/*
- * Host is being removed. Free up the current card.
- */
-static void mmc_sd_remove(struct mmc_host *host)
-{
- mmc_remove_card(host->card);
- host->card = NULL;
-}
-
-/*
* Card detection - card is alive.
*/
static int mmc_sd_alive(struct mmc_host *host)
@@ -1056,17 +1624,18 @@ static void mmc_sd_detect(struct mmc_host *host)
{
int err;
- mmc_get_card(host->card);
+ mmc_get_card(host->card, NULL);
/*
* Just check if our card has been removed.
*/
err = _mmc_detect_card_removed(host);
- mmc_put_card(host->card);
+ mmc_put_card(host->card, NULL);
if (err) {
- mmc_sd_remove(host);
+ mmc_remove_card(host->card);
+ host->card = NULL;
mmc_claim_host(host);
mmc_detach_bus(host);
@@ -1075,21 +1644,90 @@ static void mmc_sd_detect(struct mmc_host *host)
}
}
+static int sd_can_poweroff_notify(struct mmc_card *card)
+{
+ return card->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY;
+}
+
+static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy)
+{
+ struct sd_busy_data *data = cb_data;
+ struct mmc_card *card = data->card;
+ int err;
+
+ /*
+ * Read the status register for the power management function. It's at
+ * one byte offset and is one byte long. The Power Off Notification
+ * Ready is bit 0.
+ */
+ err = sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+ card->ext_power.offset + 1, 1, data->reg_buf);
+ if (err) {
+ pr_warn("%s: error %d reading status reg of PM func\n",
+ mmc_hostname(card->host), err);
+ return err;
+ }
+
+ *busy = !(data->reg_buf[0] & BIT(0));
+ return 0;
+}
+
+static int sd_poweroff_notify(struct mmc_card *card)
+{
+ struct sd_busy_data cb_data;
+ u8 *reg_buf;
+ int err;
+
+ reg_buf = kzalloc(512, GFP_KERNEL);
+ if (!reg_buf)
+ return -ENOMEM;
+
+ /*
+ * Set the Power Off Notification bit in the power management settings
+ * register at 2 bytes offset.
+ */
+ err = sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+ card->ext_power.offset + 2, BIT(0));
+ if (err) {
+ pr_warn("%s: error %d writing Power Off Notify bit\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /* Find out when the command is completed. */
+ err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+ MMC_BUSY_EXTR_SINGLE);
+ if (err)
+ goto out;
+
+ cb_data.card = card;
+ cb_data.reg_buf = reg_buf;
+ err = __mmc_poll_for_busy(card->host, 0, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
+ &sd_busy_poweroff_notify_cb, &cb_data);
+
+out:
+ kfree(reg_buf);
+ return err;
+}
+
static int _mmc_sd_suspend(struct mmc_host *host)
{
+ struct mmc_card *card = host->card;
int err = 0;
mmc_claim_host(host);
- if (mmc_card_suspended(host->card))
+ if (mmc_card_suspended(card))
goto out;
- if (!mmc_host_is_spi(host))
+ if (sd_can_poweroff_notify(card))
+ err = sd_poweroff_notify(card);
+ else if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
if (!err) {
mmc_power_off(host);
- mmc_card_set_suspended(host->card);
+ mmc_card_set_suspended(card);
}
out:
@@ -1098,6 +1736,19 @@ out:
}
/*
+ * Host is being removed. Free up the current card and do a graceful power-off.
+ */
+static void mmc_sd_remove(struct mmc_host *host)
+{
+ get_device(&host->card->dev);
+ mmc_remove_card(host->card);
+
+ _mmc_sd_suspend(host);
+
+ put_device(&host->card->dev);
+ host->card = NULL;
+}
+/*
* Callback for suspend
*/
static int mmc_sd_suspend(struct mmc_host *host)
@@ -1177,7 +1828,7 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
return 0;
}
-static int mmc_sd_reset(struct mmc_host *host)
+static int mmc_sd_hw_reset(struct mmc_host *host)
{
mmc_power_cycle(host, host->card->ocr);
return mmc_sd_init_card(host, host->card->ocr, host->card);
@@ -1192,7 +1843,9 @@ static const struct mmc_bus_ops mmc_sd_ops = {
.resume = mmc_sd_resume,
.alive = mmc_sd_alive,
.shutdown = mmc_sd_suspend,
- .reset = mmc_sd_reset,
+ .hw_reset = mmc_sd_hw_reset,
+ .cache_enabled = sd_cache_enabled,
+ .flush_cache = sd_flush_cache,
};
/*
@@ -1224,6 +1877,12 @@ int mmc_attach_sd(struct mmc_host *host)
goto err;
}
+ /*
+ * Some SD cards claims an out of spec VDD voltage range. Let's treat
+ * these bits as being in-valid and especially also bit7.
+ */
+ ocr &= ~0x7FFF;
+
rocr = mmc_select_voltage(host, ocr);
/*
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 1ada9808c329..301dc34b8b63 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -1,15 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _MMC_CORE_SD_H
#define _MMC_CORE_SD_H
#include <linux/types.h>
-extern struct device_type sd_type;
+extern const struct device_type sd_type;
struct mmc_host;
struct mmc_card;
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
-int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card);
+int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc);
+int mmc_decode_scr(struct mmc_card *card);
+int mmc_sd_get_ro(struct mmc_host *host);
void mmc_decode_cid(struct mmc_card *card);
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
bool reinit);
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 47056d8d1bac..cd86463dd306 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/core/sd_ops.h
*
* Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#include <linux/slab.h>
@@ -20,7 +16,23 @@
#include <linux/mmc/sd.h>
#include "core.h"
+#include "card.h"
#include "sd_ops.h"
+#include "mmc_ops.h"
+
+/*
+ * Extensive testing has shown that some specific SD cards
+ * require an increased command timeout to be successfully
+ * initialized.
+ */
+#define SD_APP_OP_COND_PERIOD_US (10 * 1000) /* 10ms */
+#define SD_APP_OP_COND_TIMEOUT_MS 2000 /* 2s */
+
+struct sd_app_op_cond_busy_data {
+ struct mmc_host *host;
+ u32 ocr;
+ struct mmc_command *cmd;
+};
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
@@ -30,6 +42,15 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
if (WARN_ON(card && card->host != host))
return -EINVAL;
+ /*
+ * UHS2 packet has APP bit so only set APP_CMD flag here.
+ * Will set the APP bit when assembling UHS2 packet.
+ */
+ if (host->uhs2_sd_tran) {
+ host->uhs2_app_cmd = true;
+ return 0;
+ }
+
cmd.opcode = MMC_APP_CMD;
if (card) {
@@ -52,36 +73,17 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
}
EXPORT_SYMBOL_GPL(mmc_app_cmd);
-/**
- * mmc_wait_for_app_cmd - start an application command and wait for
- completion
- * @host: MMC host to start command
- * @card: Card to send MMC_APP_CMD to
- * @cmd: MMC command to start
- * @retries: maximum number of retries
- *
- * Sends a MMC_APP_CMD, checks the card response, sends the command
- * in the parameter and waits for it to complete. Return any error
- * that occurred while the command was executing. Do not attempt to
- * parse the response.
- */
-int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
- struct mmc_command *cmd, int retries)
+static int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
+ struct mmc_command *cmd)
{
struct mmc_request mrq = {};
-
- int i, err;
-
- if (retries < 0)
- retries = MMC_CMD_RETRIES;
-
- err = -EIO;
+ int i, err = -EIO;
/*
* We have to resend MMC_APP_CMD for each attempt so
* we cannot use the retries field in mmc_command.
*/
- for (i = 0;i <= retries;i++) {
+ for (i = 0; i <= MMC_CMD_RETRIES; i++) {
err = mmc_app_cmd(host, card);
if (err) {
/* no point in retrying; no APP commands allowed */
@@ -116,8 +118,6 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
return err;
}
-EXPORT_SYMBOL(mmc_wait_for_app_cmd);
-
int mmc_app_set_bus_width(struct mmc_card *card, int width)
{
struct mmc_command cmd = {};
@@ -136,13 +136,48 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
return -EINVAL;
}
- return mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
+ return mmc_wait_for_app_cmd(card->host, card, &cmd);
+}
+
+static int sd_app_op_cond_cb(void *cb_data, bool *busy)
+{
+ struct sd_app_op_cond_busy_data *data = cb_data;
+ struct mmc_host *host = data->host;
+ struct mmc_command *cmd = data->cmd;
+ u32 ocr = data->ocr;
+ int err;
+
+ *busy = false;
+
+ err = mmc_wait_for_app_cmd(host, NULL, cmd);
+ if (err)
+ return err;
+
+ /* If we're just probing, do a single pass. */
+ if (ocr == 0)
+ return 0;
+
+ /* Wait until reset completes. */
+ if (mmc_host_is_spi(host)) {
+ if (!(cmd->resp[0] & R1_SPI_IDLE))
+ return 0;
+ } else if (cmd->resp[0] & MMC_CARD_BUSY) {
+ return 0;
+ }
+
+ *busy = true;
+ return 0;
}
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
struct mmc_command cmd = {};
- int i, err = 0;
+ struct sd_app_op_cond_busy_data cb_data = {
+ .host = host,
+ .ocr = ocr,
+ .cmd = &cmd
+ };
+ int err;
cmd.opcode = SD_APP_OP_COND;
if (mmc_host_is_spi(host))
@@ -151,39 +186,34 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
cmd.arg = ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
- for (i = 100; i; i--) {
- err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
- if (err)
- break;
-
- /* if we're just probing, do a single pass */
- if (ocr == 0)
- break;
-
- /* otherwise wait until reset completes */
- if (mmc_host_is_spi(host)) {
- if (!(cmd.resp[0] & R1_SPI_IDLE))
- break;
- } else {
- if (cmd.resp[0] & MMC_CARD_BUSY)
- break;
- }
+ err = __mmc_poll_for_busy(host, SD_APP_OP_COND_PERIOD_US,
+ SD_APP_OP_COND_TIMEOUT_MS, &sd_app_op_cond_cb,
+ &cb_data);
+ if (err)
+ return err;
- err = -ETIMEDOUT;
+ if (rocr && !mmc_host_is_spi(host))
+ *rocr = cmd.resp[0];
- mmc_delay(10);
- }
+ return 0;
+}
- if (!i)
- pr_err("%s: card never left busy state\n", mmc_hostname(host));
+int mmc_send_ext_addr(struct mmc_host *host, u32 addr)
+{
+ struct mmc_command cmd = {
+ .opcode = SD_ADDR_EXT,
+ .arg = addr,
+ .flags = MMC_RSP_R1 | MMC_CMD_AC,
+ };
- if (rocr && !mmc_host_is_spi(host))
- *rocr = cmd.resp[0];
+ if (!mmc_card_ult_capacity(host->card))
+ return 0;
- return err;
+ return mmc_wait_for_cmd(host, &cmd, 0);
}
-int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits,
+ u32 *resp)
{
struct mmc_command cmd = {};
int err;
@@ -196,7 +226,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
* SD 1.0 cards.
*/
cmd.opcode = SD_SEND_IF_COND;
- cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | pcie_bits << 8 | test_pattern;
cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, 0);
@@ -211,6 +241,50 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
if (result_pattern != test_pattern)
return -EIO;
+ if (resp)
+ *resp = cmd.resp[0];
+
+ return 0;
+}
+
+int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+{
+ return __mmc_send_if_cond(host, ocr, 0, NULL);
+}
+
+int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr)
+{
+ u32 resp = 0;
+ u8 pcie_bits = 0;
+ int ret;
+
+ if (host->caps2 & MMC_CAP2_SD_EXP) {
+ /* Probe card for SD express support via PCIe. */
+ pcie_bits = 0x10;
+ if (host->caps2 & MMC_CAP2_SD_EXP_1_2V)
+ /* Probe also for 1.2V support. */
+ pcie_bits = 0x30;
+ }
+
+ ret = __mmc_send_if_cond(host, ocr, pcie_bits, &resp);
+ if (ret)
+ return 0;
+
+ /* Continue with the SD express init, if the card supports it. */
+ resp &= 0x3000;
+ if (pcie_bits && resp) {
+ if (resp == 0x3000)
+ host->ios.timing = MMC_TIMING_SD_EXP_1_2V;
+ else
+ host->ios.timing = MMC_TIMING_SD_EXP;
+
+ /*
+ * According to the spec the clock shall also be gated, but
+ * let's leave this to the host driver for more flexibility.
+ */
+ return host->ops->init_sd_express(host, &host->ios);
+ }
+
return 0;
}
@@ -286,47 +360,22 @@ int mmc_app_send_scr(struct mmc_card *card)
return 0;
}
-int mmc_sd_switch(struct mmc_card *card, int mode, int group,
+int mmc_sd_switch(struct mmc_card *card, bool mode, int group,
u8 value, u8 *resp)
{
- struct mmc_request mrq = {};
- struct mmc_command cmd = {};
- struct mmc_data data = {};
- struct scatterlist sg;
+ u32 cmd_args;
/* NOTE: caller guarantees resp is heap-allocated */
- mode = !!mode;
value &= 0xF;
+ cmd_args = mode << 31 | 0x00FFFFFF;
+ cmd_args &= ~(0xF << (group * 4));
+ cmd_args |= value << (group * 4);
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = SD_SWITCH;
- cmd.arg = mode << 31 | 0x00FFFFFF;
- cmd.arg &= ~(0xF << (group * 4));
- cmd.arg |= value << (group * 4);
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, resp, 64);
-
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(card->host, &mrq);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
+ return mmc_send_adtc_data(card, card->host, SD_SWITCH, cmd_args, resp,
+ 64);
}
+EXPORT_SYMBOL_GPL(mmc_sd_switch);
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
{
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index 0e6c3d51e66d..8fffc1b29757 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* linux/drivers/mmc/core/sd_ops.h
*
* Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#ifndef _MMC_SD_OPS_H
@@ -16,19 +12,18 @@
struct mmc_card;
struct mmc_host;
-struct mmc_command;
+struct mmc_request;
int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
+int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr);
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
int mmc_app_send_scr(struct mmc_card *card);
-int mmc_sd_switch(struct mmc_card *card, int mode, int group,
- u8 value, u8 *resp);
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
-int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
- struct mmc_command *cmd, int retries);
+int mmc_send_ext_addr(struct mmc_host *host, u32 addr);
+void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq);
#endif
diff --git a/drivers/mmc/core/sd_uhs2.c b/drivers/mmc/core/sd_uhs2.c
new file mode 100644
index 000000000000..de17d1611290
--- /dev/null
+++ b/drivers/mmc/core/sd_uhs2.c
@@ -0,0 +1,1304 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Linaro Ltd
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ * Author: Yi Sun <yi.y.sun@intel.com>
+ *
+ * Copyright (C) 2020 Genesys Logic, Inc.
+ * Authors: Ben Chuang <ben.chuang@genesyslogic.com.tw>
+ *
+ * Copyright (C) 2020 Linaro Limited
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *
+ * Copyright (C) 2022 Genesys Logic, Inc.
+ * Authors: Jason Lai <jason.lai@genesyslogic.com.tw>
+ *
+ * Copyright (C) 2023 Genesys Logic, Inc.
+ * Authors: Victor Shih <victor.shih@genesyslogic.com.tw>
+ *
+ * Support for SD UHS-II cards
+ */
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sd_uhs2.h>
+
+#include "card.h"
+#include "core.h"
+#include "bus.h"
+#include "sd.h"
+#include "sd_ops.h"
+#include "mmc_ops.h"
+
+#define UHS2_WAIT_CFG_COMPLETE_PERIOD_US (1 * 1000)
+#define UHS2_WAIT_CFG_COMPLETE_TIMEOUT_MS 100
+
+static const unsigned int sd_uhs2_freqs[] = { 52000000, 26000000 };
+
+struct sd_uhs2_wait_active_state_data {
+ struct mmc_host *host;
+ struct mmc_command *cmd;
+};
+
+static int sd_uhs2_power_up(struct mmc_host *host)
+{
+ if (host->ios.power_mode == MMC_POWER_ON)
+ return 0;
+
+ host->ios.vdd = fls(host->ocr_avail) - 1;
+ host->ios.clock = host->f_init;
+ host->ios.timing = MMC_TIMING_UHS2_SPEED_A;
+ host->ios.power_mode = MMC_POWER_ON;
+
+ return host->ops->uhs2_control(host, UHS2_SET_IOS);
+}
+
+static int sd_uhs2_power_off(struct mmc_host *host)
+{
+ int err;
+
+ if (host->ios.power_mode == MMC_POWER_OFF)
+ return 0;
+
+ host->ios.vdd = 0;
+ host->ios.clock = 0;
+ host->ios.power_mode = MMC_POWER_OFF;
+ host->uhs2_sd_tran = false;
+
+ err = host->ops->uhs2_control(host, UHS2_SET_IOS);
+ if (err)
+ return err;
+
+ /* For consistency, let's restore the initial timing. */
+ host->ios.timing = MMC_TIMING_LEGACY;
+ return 0;
+}
+
+/*
+ * Run the phy initialization sequence, which mainly relies on the UHS-II host
+ * to check that we reach the expected electrical state, between the host and
+ * the card.
+ */
+static int sd_uhs2_phy_init(struct mmc_host *host)
+{
+ int err;
+
+ err = host->ops->uhs2_control(host, UHS2_PHY_INIT);
+ if (err) {
+ pr_debug("%s: failed to initial phy for UHS-II!\n",
+ mmc_hostname(host));
+ }
+
+ return err;
+}
+
+/*
+ * sd_uhs2_cmd_assemble() - build up UHS-II command packet which is embedded in
+ * mmc_command structure
+ * @cmd: MMC command to executed
+ * @uhs2_cmd: UHS2 command corresponded to MMC command
+ * @header: Header field of UHS-II command cxpacket
+ * @arg: Argument field of UHS-II command packet
+ * @payload: Payload field of UHS-II command packet
+ * @plen: Payload length
+ * @resp: Response buffer is allocated by caller and it is used to keep
+ * the response of CM-TRAN command. For SD-TRAN command, uhs2_resp
+ * should be null and SD-TRAN command response should be stored in
+ * resp of mmc_command.
+ * @resp_len: Response buffer length
+ *
+ * The uhs2_command structure contains message packets which are transmited/
+ * received on UHS-II bus. This function fills in the contents of uhs2_command
+ * structure and embededs UHS2 command into mmc_command structure, which is used
+ * in legacy SD operation functions.
+ *
+ */
+static void sd_uhs2_cmd_assemble(struct mmc_command *cmd,
+ struct uhs2_command *uhs2_cmd,
+ u8 plen, u8 resp_len)
+{
+ uhs2_cmd->payload_len = plen * sizeof(u32);
+ uhs2_cmd->packet_len = uhs2_cmd->payload_len + 4;
+
+ cmd->uhs2_cmd = uhs2_cmd;
+ cmd->uhs2_cmd->uhs2_resp_len = resp_len;
+}
+
+/*
+ * Do the early initialization of the card, by sending the device init broadcast
+ * command and wait for the process to be completed.
+ */
+static int sd_uhs2_dev_init(struct mmc_host *host)
+{
+ struct mmc_command cmd = {0};
+ struct uhs2_command uhs2_cmd = {};
+ u32 cnt;
+ u32 dap, gap, resp_gap;
+ u32 payload0;
+ u8 gd = 0;
+ int err;
+
+ dap = host->uhs2_caps.dap;
+ gap = host->uhs2_caps.gap;
+
+ /*
+ * Refer to UHS-II Addendum Version 1.02 Figure 6-21 to see DEVICE_INIT CCMD format.
+ * Head:
+ * - Control Write(R/W=1) with 4-Byte payload(PLEN=01b).
+ * - IOADR = CMD_BASE + 002h
+ * Payload:
+ * - bit [3:0] : GAP(Group Allocated Power)
+ * - bit [7:4] : GD(Group Descriptor)
+ * - bit [11] : Complete Flag
+ * - bit [15:12]: DAP(Device Allocated Power)
+ */
+ uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD;
+ uhs2_cmd.arg = ((UHS2_DEV_CMD_DEVICE_INIT & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_WRITE |
+ UHS2_NATIVE_CMD_PLEN_4B |
+ (UHS2_DEV_CMD_DEVICE_INIT >> 8);
+
+ /*
+ * Refer to UHS-II Addendum Version 1.02 section 6.3.1.
+ * Max. time from DEVICE_INIT CCMD EOP reception on Device
+ * Rx to its SOP transmission on Device Tx(Tfwd_init_cmd) is
+ * 1 second.
+ */
+ cmd.busy_timeout = 1000;
+
+ /*
+ * Refer to UHS-II Addendum Version 1.02 section 6.2.6.3.
+ * Let's retry the DEVICE_INIT command no more than 30 times.
+ */
+ for (cnt = 0; cnt < 30; cnt++) {
+ payload0 = ((dap & 0xF) << 12) |
+ UHS2_DEV_INIT_COMPLETE_FLAG |
+ ((gd & 0xF) << 4) |
+ (gap & 0xF);
+ uhs2_cmd.payload[0] = (__force __be32)payload0;
+
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_DEV_INIT_PAYLOAD_LEN,
+ UHS2_DEV_INIT_RESP_LEN);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ continue;
+ }
+
+ if (uhs2_cmd.uhs2_resp[3] != (UHS2_DEV_CMD_DEVICE_INIT & 0xFF)) {
+ pr_err("%s: DEVICE_INIT response is wrong!\n",
+ mmc_hostname(host));
+ return -EIO;
+ }
+
+ if (uhs2_cmd.uhs2_resp[5] & 0x8) {
+ host->uhs2_caps.group_desc = gd;
+ return 0;
+ }
+ resp_gap = uhs2_cmd.uhs2_resp[4] & 0x0F;
+ if (gap == resp_gap)
+ gd++;
+ }
+
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ return 0;
+}
+
+/*
+ * Run the enumeration process by sending the enumerate command to the card.
+ * Note that, we currently support only the point to point connection, which
+ * means only one card can be attached per host/slot.
+ */
+static int sd_uhs2_enum(struct mmc_host *host, u32 *node_id)
+{
+ struct mmc_command cmd = {0};
+ struct uhs2_command uhs2_cmd = {};
+ u32 payload0;
+ u8 id_f = 0xF, id_l = 0x0;
+ int err;
+
+ /*
+ * Refer to UHS-II Addendum Version 1.02 Figure 6-28 to see ENUMERATE CCMD format.
+ * Header:
+ * - Control Write(R/W=1) with 4-Byte payload(PLEN=01b).
+ * - IOADR = CMD_BASE + 003h
+ * Payload:
+ * - bit [3:0]: ID_L(Last Node ID)
+ * - bit [7:4]: ID_F(First Node ID)
+ */
+ uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD;
+ uhs2_cmd.arg = ((UHS2_DEV_CMD_ENUMERATE & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_WRITE |
+ UHS2_NATIVE_CMD_PLEN_4B |
+ (UHS2_DEV_CMD_ENUMERATE >> 8);
+
+ payload0 = (id_f << 4) | id_l;
+ uhs2_cmd.payload[0] = cpu_to_be32(payload0);
+
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_DEV_ENUM_PAYLOAD_LEN, UHS2_DEV_ENUM_RESP_LEN);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ if (uhs2_cmd.uhs2_resp[3] != (UHS2_DEV_CMD_ENUMERATE & 0xFF)) {
+ pr_err("%s: ENUMERATE response is wrong!\n",
+ mmc_hostname(host));
+ return -EIO;
+ }
+
+ id_f = (uhs2_cmd.uhs2_resp[4] >> 4) & 0xF;
+ id_l = uhs2_cmd.uhs2_resp[4] & 0xF;
+ *node_id = id_f;
+
+ return 0;
+}
+
+/*
+ * Read the UHS-II configuration registers (CFG_REG) of the card, by sending it
+ * commands and by parsing the responses. Store a copy of the relevant data in
+ * card->uhs2_config.
+ */
+static int sd_uhs2_config_read(struct mmc_host *host, struct mmc_card *card)
+{
+ struct mmc_command cmd = {0};
+ struct uhs2_command uhs2_cmd = {};
+ u32 cap;
+ int err;
+
+ /*
+ * Use Control Read CCMD to read Generic Capability from Configuration Register.
+ * - Control Write(R/W=1) with 4-Byte payload(PLEN=01b).
+ * - IOADR = Generic Capability Register(CFG_BASE + 000h)
+ */
+ uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | card->uhs2_config.node_id;
+ uhs2_cmd.arg = ((UHS2_DEV_CONFIG_GEN_CAPS & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_READ |
+ UHS2_NATIVE_CMD_PLEN_4B |
+ (UHS2_DEV_CONFIG_GEN_CAPS >> 8);
+
+ /*
+ * There is no payload because per spec, there should be
+ * no payload field for read CCMD.
+ * Plen is set in arg. Per spec, plen for read CCMD
+ * represents the len of read data which is assigned in payload
+ * of following RES (p136).
+ */
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, 0, 0);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ /*
+ * Generic Capability Register:
+ * bit [7:0] : Reserved
+ * bit [13:8] : Device-Specific Number of Lanes and Functionality
+ * bit 8: 2L-HD
+ * bit 9: 2D-1U FD
+ * bit 10: 1D-2U FD
+ * bit 11: 2D-2U FD
+ * Others: Reserved
+ * bit [14] : DADR Length
+ * 0: 4 bytes
+ * 1: Reserved
+ * bit [23:16]: Application Type
+ * bit 16: 0=Non-SD memory, 1=SD memory
+ * bit 17: 0=Non-SDIO, 1=SDIO
+ * bit 18: 0=Card, 1=Embedded
+ * bit [63:24]: Reserved
+ */
+ cap = cmd.resp[0];
+ card->uhs2_config.n_lanes =
+ (cap >> UHS2_DEV_CONFIG_N_LANES_POS) &
+ UHS2_DEV_CONFIG_N_LANES_MASK;
+ card->uhs2_config.dadr_len =
+ (cap >> UHS2_DEV_CONFIG_DADR_POS) &
+ UHS2_DEV_CONFIG_DADR_MASK;
+ card->uhs2_config.app_type =
+ (cap >> UHS2_DEV_CONFIG_APP_POS) &
+ UHS2_DEV_CONFIG_APP_MASK;
+
+ /*
+ * Use Control Read CCMD to read PHY Capability from Configuration Register.
+ * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+ * - IOADR = PHY Capability Register(CFG_BASE + 002h)
+ */
+ uhs2_cmd.arg = ((UHS2_DEV_CONFIG_PHY_CAPS & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_READ |
+ UHS2_NATIVE_CMD_PLEN_8B |
+ (UHS2_DEV_CONFIG_PHY_CAPS >> 8);
+
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, 0, 0);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ /*
+ * PHY Capability Register:
+ * bit [3:0] : PHY Minor Revision
+ * bit [5:4] : PHY Major Revision
+ * bit [15] : Support Hibernate Mode
+ * 0: Not support Hibernate Mode
+ * 1: Support Hibernate Mode
+ * bit [31:16]: Reserved
+ * bit [35:32]: Device-Specific N_LSS_SYN
+ * bit [39:36]: Device-Specific N_LSS_DIR
+ * bit [63:40]: Reserved
+ */
+ cap = cmd.resp[0];
+ card->uhs2_config.phy_minor_rev =
+ cap & UHS2_DEV_CONFIG_PHY_MINOR_MASK;
+ card->uhs2_config.phy_major_rev =
+ (cap >> UHS2_DEV_CONFIG_PHY_MAJOR_POS) &
+ UHS2_DEV_CONFIG_PHY_MAJOR_MASK;
+ card->uhs2_config.can_hibernate =
+ (cap >> UHS2_DEV_CONFIG_CAN_HIBER_POS) &
+ UHS2_DEV_CONFIG_CAN_HIBER_MASK;
+
+ cap = cmd.resp[1];
+ card->uhs2_config.n_lss_sync =
+ cap & UHS2_DEV_CONFIG_N_LSS_SYN_MASK;
+ card->uhs2_config.n_lss_dir =
+ (cap >> UHS2_DEV_CONFIG_N_LSS_DIR_POS) &
+ UHS2_DEV_CONFIG_N_LSS_DIR_MASK;
+ if (card->uhs2_config.n_lss_sync == 0)
+ card->uhs2_config.n_lss_sync = 16 << 2;
+ else
+ card->uhs2_config.n_lss_sync <<= 2;
+
+ if (card->uhs2_config.n_lss_dir == 0)
+ card->uhs2_config.n_lss_dir = 16 << 3;
+ else
+ card->uhs2_config.n_lss_dir <<= 3;
+
+ /*
+ * Use Control Read CCMD to read LINK/TRAN Capability from Configuration Register.
+ * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+ * - IOADR = LINK/TRAN Capability Register(CFG_BASE + 004h)
+ */
+ uhs2_cmd.arg = ((UHS2_DEV_CONFIG_LINK_TRAN_CAPS & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_READ |
+ UHS2_NATIVE_CMD_PLEN_8B |
+ (UHS2_DEV_CONFIG_LINK_TRAN_CAPS >> 8);
+
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, 0, 0);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ /*
+ * LINK/TRAN Capability Register:
+ * bit [3:0] : LINK_TRAN Minor Revision
+ * bit [5:4] : LINK/TRAN Major Revision
+ * bit [7:6] : Reserved
+ * bit [15:8] : Device-Specific N_FCU
+ * bit [18:16]: Device Type
+ * 001b=Host
+ * 010b=Device
+ * 011b=Reserved for CMD issuable Device
+ * bit [19] : Reserved
+ * bit [31:20]: Device-Specific MAX_BLKLEN
+ * bit [39:32]: Device-Specific N_DATA_GAP
+ * bit [63:40]: Reserved
+ */
+ cap = cmd.resp[0];
+ card->uhs2_config.link_minor_rev =
+ cap & UHS2_DEV_CONFIG_LT_MINOR_MASK;
+ card->uhs2_config.link_major_rev =
+ (cap >> UHS2_DEV_CONFIG_LT_MAJOR_POS) &
+ UHS2_DEV_CONFIG_LT_MAJOR_MASK;
+ card->uhs2_config.n_fcu =
+ (cap >> UHS2_DEV_CONFIG_N_FCU_POS) &
+ UHS2_DEV_CONFIG_N_FCU_MASK;
+ card->uhs2_config.dev_type =
+ (cap >> UHS2_DEV_CONFIG_DEV_TYPE_POS) &
+ UHS2_DEV_CONFIG_DEV_TYPE_MASK;
+ card->uhs2_config.maxblk_len =
+ (cap >> UHS2_DEV_CONFIG_MAX_BLK_LEN_POS) &
+ UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK;
+
+ cap = cmd.resp[1];
+ card->uhs2_config.n_data_gap =
+ cap & UHS2_DEV_CONFIG_N_DATA_GAP_MASK;
+ if (card->uhs2_config.n_fcu == 0)
+ card->uhs2_config.n_fcu = 256;
+
+ return 0;
+}
+
+/*
+ * Based on the card's and host's UHS-II capabilities, let's update the
+ * configuration of the card and the host. This may also include to move to a
+ * greater speed range/mode. Depending on the updated configuration, we may need
+ * to do a soft reset of the card via sending it a GO_DORMANT_STATE command.
+ *
+ * In the final step, let's check if the card signals "config completion", which
+ * indicates that the card has moved from config state into active state.
+ */
+static int sd_uhs2_config_write(struct mmc_host *host, struct mmc_card *card)
+{
+ struct mmc_command cmd = {0};
+ struct uhs2_command uhs2_cmd = {};
+ u32 payload0, payload1;
+ u8 nMinDataGap;
+ int err;
+
+ /*
+ * Use Control Write CCMD to set Generic Setting in Configuration Register.
+ * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+ * - IOADR = Generic Setting Register(CFG_BASE + 008h)
+ * - Payload = New contents to be written to Generic Setting Register
+ */
+ uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | card->uhs2_config.node_id;
+ uhs2_cmd.arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_WRITE |
+ UHS2_NATIVE_CMD_PLEN_8B |
+ (UHS2_DEV_CONFIG_GEN_SET >> 8);
+
+ /*
+ * Most UHS-II cards only support FD and 2L-HD mode. Other lane numbers
+ * defined in UHS-II addendem Ver1.01 are optional.
+ */
+ host->uhs2_caps.n_lanes_set = UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD;
+ card->uhs2_config.n_lanes_set = UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD;
+
+ payload0 = card->uhs2_config.n_lanes_set << UHS2_DEV_CONFIG_N_LANES_POS;
+ payload1 = 0;
+ uhs2_cmd.payload[0] = cpu_to_be32(payload0);
+ uhs2_cmd.payload[1] = cpu_to_be32(payload1);
+
+ /*
+ * There is no payload because per spec, there should be
+ * no payload field for read CCMD.
+ * Plen is set in arg. Per spec, plen for read CCMD
+ * represents the len of read data which is assigned in payload
+ * of following RES (p136).
+ */
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_CFG_WRITE_PAYLOAD_LEN, 0);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ /*
+ * Use Control Write CCMD to set PHY Setting in Configuration Register.
+ * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+ * - IOADR = PHY Setting Register(CFG_BASE + 00Ah)
+ * - Payload = New contents to be written to PHY Setting Register
+ */
+ uhs2_cmd.arg = ((UHS2_DEV_CONFIG_PHY_SET & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_WRITE |
+ UHS2_NATIVE_CMD_PLEN_8B |
+ (UHS2_DEV_CONFIG_PHY_SET >> 8);
+
+ if (host->uhs2_caps.speed_range == UHS2_DEV_CONFIG_PHY_SET_SPEED_B) {
+ if (card->uhs2_config.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD &&
+ host->uhs2_caps.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD) {
+ /* Support HD */
+ host->ios.timing = MMC_TIMING_UHS2_SPEED_B_HD;
+ nMinDataGap = 1;
+ } else {
+ /* Only support 2L-FD so far */
+ host->ios.timing = MMC_TIMING_UHS2_SPEED_B;
+ nMinDataGap = 3;
+ }
+ card->uhs2_config.speed_range_set = UHS2_DEV_CONFIG_PHY_SET_SPEED_B;
+ } else {
+ if (card->uhs2_config.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD &&
+ host->uhs2_caps.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD) {
+ /* Support HD */
+ host->ios.timing = MMC_TIMING_UHS2_SPEED_A_HD;
+ nMinDataGap = 1;
+ } else {
+ /* Only support 2L-FD so far */
+ host->ios.timing = MMC_TIMING_UHS2_SPEED_A;
+ nMinDataGap = 3;
+ }
+ card->uhs2_config.speed_range_set = UHS2_DEV_CONFIG_PHY_SET_SPEED_A;
+ }
+
+ payload0 = card->uhs2_config.speed_range_set << UHS2_DEV_CONFIG_PHY_SET_SPEED_POS;
+
+ card->uhs2_config.n_lss_sync_set = (max(card->uhs2_config.n_lss_sync,
+ host->uhs2_caps.n_lss_sync) >> 2) &
+ UHS2_DEV_CONFIG_N_LSS_SYN_MASK;
+ host->uhs2_caps.n_lss_sync_set = card->uhs2_config.n_lss_sync_set;
+
+ card->uhs2_config.n_lss_dir_set = (max(card->uhs2_config.n_lss_dir,
+ host->uhs2_caps.n_lss_dir) >> 3) &
+ UHS2_DEV_CONFIG_N_LSS_DIR_MASK;
+ host->uhs2_caps.n_lss_dir_set = card->uhs2_config.n_lss_dir_set;
+
+ payload1 = (card->uhs2_config.n_lss_dir_set << UHS2_DEV_CONFIG_N_LSS_DIR_POS) |
+ card->uhs2_config.n_lss_sync_set;
+ uhs2_cmd.payload[0] = cpu_to_be32(payload0);
+ uhs2_cmd.payload[1] = cpu_to_be32(payload1);
+
+ memset(uhs2_cmd.uhs2_resp, 0, sizeof(uhs2_cmd.uhs2_resp));
+
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_CFG_WRITE_PAYLOAD_LEN,
+ UHS2_CFG_WRITE_PHY_SET_RESP_LEN);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ if ((uhs2_cmd.uhs2_resp[2] & 0x80)) {
+ pr_err("%s: %s: UHS2 CMD not accepted, resp= 0x%x!\n",
+ mmc_hostname(host), __func__, uhs2_cmd.uhs2_resp[2]);
+ return -EIO;
+ }
+
+ /*
+ * Use Control Write CCMD to set LINK/TRAN Setting in Configuration Register.
+ * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+ * - IOADR = LINK/TRAN Setting Register(CFG_BASE + 00Ch)
+ * - Payload = New contents to be written to LINK/TRAN Setting Register
+ */
+ uhs2_cmd.arg = ((UHS2_DEV_CONFIG_LINK_TRAN_SET & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_WRITE |
+ UHS2_NATIVE_CMD_PLEN_8B |
+ (UHS2_DEV_CONFIG_LINK_TRAN_SET >> 8);
+
+ if (card->uhs2_config.app_type == UHS2_DEV_CONFIG_APP_SD_MEM)
+ card->uhs2_config.maxblk_len_set = UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN;
+ else
+ card->uhs2_config.maxblk_len_set = min(card->uhs2_config.maxblk_len,
+ host->uhs2_caps.maxblk_len);
+ host->uhs2_caps.maxblk_len_set = card->uhs2_config.maxblk_len_set;
+
+ card->uhs2_config.n_fcu_set = min(card->uhs2_config.n_fcu, host->uhs2_caps.n_fcu);
+ host->uhs2_caps.n_fcu_set = card->uhs2_config.n_fcu_set;
+
+ card->uhs2_config.n_data_gap_set = max(nMinDataGap, card->uhs2_config.n_data_gap);
+ host->uhs2_caps.n_data_gap_set = card->uhs2_config.n_data_gap_set;
+
+ host->uhs2_caps.max_retry_set = 3;
+ card->uhs2_config.max_retry_set = host->uhs2_caps.max_retry_set;
+
+ payload0 = (card->uhs2_config.maxblk_len_set << UHS2_DEV_CONFIG_MAX_BLK_LEN_POS) |
+ (card->uhs2_config.max_retry_set << UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS) |
+ (card->uhs2_config.n_fcu_set << UHS2_DEV_CONFIG_N_FCU_POS);
+ payload1 = card->uhs2_config.n_data_gap_set;
+ uhs2_cmd.payload[0] = cpu_to_be32(payload0);
+ uhs2_cmd.payload[1] = cpu_to_be32(payload1);
+
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_CFG_WRITE_PAYLOAD_LEN, 0);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ /*
+ * Use Control Write CCMD to set Config Completion(payload bit 63) in Generic Setting
+ * Register.
+ * Header:
+ * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b).
+ * - IOADR = PGeneric Setting Register(CFG_BASE + 008h)
+ * Payload:
+ * - bit [63]: Config Completion
+ *
+ * DLSM transits to Active state immediately when Config Completion is set to 1.
+ */
+ uhs2_cmd.arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_WRITE |
+ UHS2_NATIVE_CMD_PLEN_8B |
+ (UHS2_DEV_CONFIG_GEN_SET >> 8);
+
+ payload0 = 0;
+ payload1 = UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE;
+ uhs2_cmd.payload[0] = cpu_to_be32(payload0);
+ uhs2_cmd.payload[1] = cpu_to_be32(payload1);
+
+ memset(uhs2_cmd.uhs2_resp, 0, sizeof(uhs2_cmd.uhs2_resp));
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_CFG_WRITE_PAYLOAD_LEN,
+ UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ /* Set host Config Setting registers */
+ err = host->ops->uhs2_control(host, UHS2_SET_CONFIG);
+ if (err) {
+ pr_err("%s: %s: UHS2 SET_CONFIG fail!\n", mmc_hostname(host), __func__);
+ return err;
+ }
+
+ return 0;
+}
+
+static int sd_uhs2_go_dormant(struct mmc_host *host, u32 node_id)
+{
+ struct mmc_command cmd = {0};
+ struct uhs2_command uhs2_cmd = {};
+ int err;
+
+ /* Disable Normal INT */
+ err = host->ops->uhs2_control(host, UHS2_DISABLE_INT);
+ if (err) {
+ pr_err("%s: %s: UHS2 DISABLE_INT fail!\n",
+ mmc_hostname(host), __func__);
+ return err;
+ }
+
+ /*
+ * Refer to UHS-II Addendum Version 1.02 Figure 6-17 to see GO_DORMANT_STATE CCMD format.
+ * Header:
+ * - Control Write(R/W=1) with 4-Byte payload(PLEN=01b).
+ * - IOADR = CMD_BASE + 001h
+ * Payload:
+ * - bit [7]: HBR(Entry to Hibernate Mode)
+ * 1: Host intends to enter Hibernate mode during Dormant state.
+ * The default setting is 0 because hibernate is currently not supported.
+ */
+ uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | node_id;
+ uhs2_cmd.arg = ((UHS2_DEV_CMD_GO_DORMANT_STATE & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_WRITE |
+ UHS2_NATIVE_CMD_PLEN_4B |
+ (UHS2_DEV_CMD_GO_DORMANT_STATE >> 8);
+
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_GO_DORMANT_PAYLOAD_LEN, 0);
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err) {
+ pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ /* Check Dormant State in Present */
+ err = host->ops->uhs2_control(host, UHS2_CHECK_DORMANT);
+ if (err)
+ return err;
+
+ /* Disable UHS2 card clock */
+ err = host->ops->uhs2_control(host, UHS2_DISABLE_CLK);
+ if (err)
+ return err;
+
+ /* Restore sd clock */
+ mmc_delay(5);
+ err = host->ops->uhs2_control(host, UHS2_ENABLE_CLK);
+ if (err)
+ return err;
+
+ /* Enable Normal INT */
+ err = host->ops->uhs2_control(host, UHS2_ENABLE_INT);
+ if (err)
+ return err;
+
+ /* Detect UHS2 */
+ err = host->ops->uhs2_control(host, UHS2_PHY_INIT);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int sd_uhs2_wait_active_state_cb(void *cb_data, bool *busy)
+{
+ struct sd_uhs2_wait_active_state_data *data = cb_data;
+ struct mmc_host *host = data->host;
+ struct mmc_command *cmd = data->cmd;
+ int err;
+
+ err = mmc_wait_for_cmd(host, cmd, 0);
+ if (err)
+ return err;
+
+ if (cmd->resp[1] & UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE)
+ *busy = false;
+ else
+ *busy = true;
+
+ return 0;
+}
+
+static int sd_uhs2_go_dormant_state(struct mmc_host *host, u32 node_id)
+{
+ struct mmc_command cmd = {0};
+ struct uhs2_command uhs2_cmd = {};
+ int err;
+ struct sd_uhs2_wait_active_state_data cb_data = {
+ .host = host,
+ .cmd = &cmd
+ };
+
+ err = sd_uhs2_go_dormant(host, node_id);
+ if (err) {
+ pr_err("%s: %s: UHS2 GO_DORMANT_STATE fail, err= 0x%x!\n",
+ mmc_hostname(host), __func__, err);
+ return err;
+ }
+
+ /*
+ * Use Control Read CCMD to check Config Completion(bit 63) in Generic Setting Register.
+ * - Control Read(R/W=0) with 8-Byte payload(PLEN=10b).
+ * - IOADR = Generic Setting Register(CFG_BASE + 008h)
+ *
+ * When UHS-II card been switched to new speed mode, it will set Config Completion to 1.
+ */
+ uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | node_id;
+ uhs2_cmd.arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) |
+ UHS2_NATIVE_CMD_READ |
+ UHS2_NATIVE_CMD_PLEN_8B |
+ (UHS2_DEV_CONFIG_GEN_SET >> 8);
+
+ sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, 0, 0);
+ err = __mmc_poll_for_busy(host, UHS2_WAIT_CFG_COMPLETE_PERIOD_US,
+ UHS2_WAIT_CFG_COMPLETE_TIMEOUT_MS,
+ &sd_uhs2_wait_active_state_cb, &cb_data);
+ if (err) {
+ pr_err("%s: %s: Not switch to Active in 100 ms\n", mmc_hostname(host), __func__);
+ return err;
+ }
+
+ return 0;
+}
+
+/*
+ * Allocate the data structure for the mmc_card and run the UHS-II specific
+ * initialization sequence.
+ */
+static int sd_uhs2_init_card(struct mmc_host *host, struct mmc_card *oldcard)
+{
+ struct mmc_card *card;
+ u32 node_id = 0;
+ int err;
+
+ err = sd_uhs2_dev_init(host);
+ if (err)
+ return err;
+
+ err = sd_uhs2_enum(host, &node_id);
+ if (err)
+ return err;
+
+ if (oldcard) {
+ card = oldcard;
+ } else {
+ card = mmc_alloc_card(host, &sd_type);
+ if (IS_ERR(card))
+ return PTR_ERR(card);
+ }
+
+ card->uhs2_config.node_id = node_id;
+ card->type = MMC_TYPE_SD;
+
+ err = sd_uhs2_config_read(host, card);
+ if (err)
+ goto err;
+
+ err = sd_uhs2_config_write(host, card);
+ if (err)
+ goto err;
+
+ /* If change speed to Range B, need to GO_DORMANT_STATE */
+ if (host->ios.timing == MMC_TIMING_UHS2_SPEED_B ||
+ host->ios.timing == MMC_TIMING_UHS2_SPEED_B_HD) {
+ err = sd_uhs2_go_dormant_state(host, node_id);
+ if (err)
+ goto err;
+ }
+
+ host->uhs2_sd_tran = true;
+ host->card = card;
+ return 0;
+
+err:
+ if (!oldcard)
+ mmc_remove_card(card);
+ return err;
+}
+
+/*
+ * Initialize the UHS-II card through the SD-TRAN transport layer. This enables
+ * commands/requests to be backwards compatible through the legacy SD protocol.
+ * UHS-II cards has a specific power limit specified for VDD1/VDD2, that should
+ * be set through a legacy CMD6. Note that, the power limit that becomes set,
+ * survives a soft reset through the GO_DORMANT_STATE command.
+ */
+static int sd_uhs2_legacy_init(struct mmc_host *host, struct mmc_card *card,
+ bool reinit)
+{
+ int err;
+ u32 cid[4];
+ u32 ocr;
+ u32 rocr;
+ u8 *status;
+ int ro;
+
+ /* Send CMD0 to reset SD card */
+ err = __mmc_go_idle(host);
+ if (err)
+ return err;
+
+ mmc_delay(1);
+
+ /* Send CMD8 to communicate SD interface operation condition */
+ err = mmc_send_if_cond(host, host->ocr_avail);
+ if (err)
+ return err;
+
+ /*
+ * Probe SD card working voltage.
+ */
+ err = mmc_send_app_op_cond(host, 0, &ocr);
+ if (err)
+ return err;
+
+ card->ocr = ocr;
+
+ /*
+ * Some SD cards claims an out of spec VDD voltage range. Let's treat
+ * these bits as being in-valid and especially also bit7.
+ */
+ ocr &= ~0x7FFF;
+ rocr = mmc_select_voltage(host, ocr);
+ /*
+ * Some cards have zero value of rocr in UHS-II mode. Assign host's
+ * ocr value to rocr.
+ */
+ if (!rocr)
+ rocr = host->ocr_avail;
+
+ rocr |= (SD_OCR_CCS | SD_OCR_XPC);
+
+ /* Wait SD power on ready */
+ ocr = rocr;
+
+ err = mmc_send_app_op_cond(host, ocr, &rocr);
+ if (err)
+ return err;
+
+ err = mmc_send_cid(host, cid);
+ if (err)
+ return err;
+
+ if (reinit) {
+ if (memcmp(cid, card->raw_cid, sizeof(cid)) != 0) {
+ pr_debug("%s: Perhaps the card was replaced\n",
+ mmc_hostname(host));
+ return -ENOENT;
+ }
+ } else {
+ memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+ mmc_decode_cid(card);
+ }
+
+ /*
+ * For native busses: get card RCA and quit open drain mode.
+ */
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err)
+ return err;
+
+ err = mmc_sd_get_csd(card, false);
+ if (err)
+ return err;
+
+ /*
+ * Select card, as all following commands rely on that.
+ */
+ err = mmc_select_card(card);
+ if (err)
+ return err;
+
+ /*
+ * Fetch SCR from card.
+ */
+ err = mmc_app_send_scr(card);
+ if (err)
+ return err;
+
+ err = mmc_decode_scr(card);
+ if (err)
+ return err;
+
+ /*
+ * Switch to high power consumption mode.
+ * Even switch failed, sd card can still work at lower power consumption mode, but
+ * performance will be lower than high power consumption mode.
+ */
+ status = kmalloc(64, GFP_KERNEL);
+ if (!status)
+ return -ENOMEM;
+
+ if (!(card->csd.cmdclass & CCC_SWITCH)) {
+ pr_warn("%s: card lacks mandatory switch function, performance might suffer\n",
+ mmc_hostname(card->host));
+ } else {
+ /*
+ * Send CMD6 to set Maximum Power Consumption to get better
+ * performance. Ignore errors and continue.
+ */
+ err = mmc_sd_switch(card, 0, 3, SD4_SET_POWER_LIMIT_1_80W, status);
+ if (!err)
+ mmc_sd_switch(card, 1, 3, SD4_SET_POWER_LIMIT_1_80W, status);
+ }
+
+ /*
+ * Check if read-only switch is active.
+ */
+ ro = mmc_sd_get_ro(host);
+ if (ro < 0)
+ pr_warn("%s: host does not support read-only switch, assuming write-enable\n",
+ mmc_hostname(host));
+ else if (ro > 0)
+ mmc_card_set_readonly(card);
+
+ kfree(status);
+ return 0;
+}
+
+static int sd_uhs2_reinit(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+ int err;
+
+ err = sd_uhs2_power_up(host);
+ if (err)
+ return err;
+
+ err = sd_uhs2_phy_init(host);
+ if (err)
+ return err;
+
+ err = sd_uhs2_init_card(host, card);
+ if (err)
+ return err;
+
+ return sd_uhs2_legacy_init(host, card, true);
+}
+
+static void sd_uhs2_remove(struct mmc_host *host)
+{
+ mmc_remove_card(host->card);
+ host->card = NULL;
+}
+
+static int sd_uhs2_alive(struct mmc_host *host)
+{
+ return mmc_send_status(host->card, NULL);
+}
+
+static void sd_uhs2_detect(struct mmc_host *host)
+{
+ int err;
+
+ mmc_get_card(host->card, NULL);
+ err = _mmc_detect_card_removed(host);
+ mmc_put_card(host->card, NULL);
+
+ if (err) {
+ sd_uhs2_remove(host);
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ sd_uhs2_power_off(host);
+ mmc_release_host(host);
+ }
+}
+
+static int _sd_uhs2_suspend(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+
+ mmc_claim_host(host);
+
+ if (mmc_card_suspended(card))
+ goto out;
+
+ sd_uhs2_power_off(host);
+ mmc_card_set_suspended(card);
+
+out:
+ mmc_release_host(host);
+ return 0;
+}
+
+/*
+ * Callback for suspend
+ */
+static int sd_uhs2_suspend(struct mmc_host *host)
+{
+ int err;
+
+ err = _sd_uhs2_suspend(host);
+ if (!err) {
+ pm_runtime_disable(&host->card->dev);
+ pm_runtime_set_suspended(&host->card->dev);
+ }
+
+ return err;
+}
+
+/*
+ * This function tries to determine if the same card is still present
+ * and, if so, restore all state to it.
+ */
+static int _mmc_sd_uhs2_resume(struct mmc_host *host)
+{
+ int err = 0;
+
+ mmc_claim_host(host);
+
+ if (!mmc_card_suspended(host->card))
+ goto out;
+
+ /* Power up UHS2 SD card and re-initialize it. */
+ err = sd_uhs2_reinit(host);
+ mmc_card_clr_suspended(host->card);
+
+out:
+ mmc_release_host(host);
+ return err;
+}
+
+/*
+ * Callback for resume
+ */
+static int sd_uhs2_resume(struct mmc_host *host)
+{
+ pm_runtime_enable(&host->card->dev);
+ return 0;
+}
+
+/*
+ * Callback for runtime_suspend.
+ */
+static int sd_uhs2_runtime_suspend(struct mmc_host *host)
+{
+ int err;
+
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ return 0;
+
+ err = _sd_uhs2_suspend(host);
+ if (err)
+ pr_err("%s: error %d doing aggressive suspend\n", mmc_hostname(host), err);
+
+ return err;
+}
+
+static int sd_uhs2_runtime_resume(struct mmc_host *host)
+{
+ int err;
+
+ err = _mmc_sd_uhs2_resume(host);
+ if (err && err != -ENOMEDIUM)
+ pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err);
+
+ return err;
+}
+
+static int sd_uhs2_hw_reset(struct mmc_host *host)
+{
+ sd_uhs2_power_off(host);
+ /* Wait at least 1 ms according to SD spec */
+ mmc_delay(1);
+
+ return sd_uhs2_reinit(host);
+}
+
+static const struct mmc_bus_ops sd_uhs2_ops = {
+ .remove = sd_uhs2_remove,
+ .alive = sd_uhs2_alive,
+ .detect = sd_uhs2_detect,
+ .suspend = sd_uhs2_suspend,
+ .resume = sd_uhs2_resume,
+ .runtime_suspend = sd_uhs2_runtime_suspend,
+ .runtime_resume = sd_uhs2_runtime_resume,
+ .shutdown = sd_uhs2_suspend,
+ .hw_reset = sd_uhs2_hw_reset,
+};
+
+static int sd_uhs2_attach(struct mmc_host *host)
+{
+ int err;
+
+ err = sd_uhs2_power_up(host);
+ if (err)
+ goto err;
+
+ err = sd_uhs2_phy_init(host);
+ if (err)
+ goto err;
+
+ err = sd_uhs2_init_card(host, NULL);
+ if (err)
+ goto err;
+
+ err = sd_uhs2_legacy_init(host, host->card, false);
+ if (err)
+ goto remove_card;
+
+ mmc_attach_bus(host, &sd_uhs2_ops);
+
+ mmc_release_host(host);
+
+ err = mmc_add_card(host->card);
+ if (err)
+ goto remove_card;
+
+ mmc_claim_host(host);
+ return 0;
+
+remove_card:
+ sd_uhs2_remove(host);
+ mmc_claim_host(host);
+err:
+ mmc_detach_bus(host);
+ sd_uhs2_power_off(host);
+ return err;
+}
+
+/**
+ * mmc_attach_sd_uhs2 - select UHS2 interface
+ * @host: MMC host
+ *
+ * Try to select UHS2 interface and initialize the bus for a given
+ * frequency, @freq.
+ *
+ * Return: 0 on success, non-zero error on failure
+ */
+int mmc_attach_sd_uhs2(struct mmc_host *host)
+{
+ int i, err;
+
+ if (!(host->caps2 & MMC_CAP2_SD_UHS2))
+ return -EOPNOTSUPP;
+
+ /* Turn off the legacy SD interface before trying with UHS-II. */
+ mmc_power_off(host);
+
+ /*
+ * Start UHS-II initialization at 52MHz and possibly make a retry at
+ * 26MHz according to the spec. It's required that the host driver
+ * validates ios->clock, to set a rate within the correct range.
+ */
+ for (i = 0; i < ARRAY_SIZE(sd_uhs2_freqs); i++) {
+ host->f_init = sd_uhs2_freqs[i];
+ pr_debug("%s: %s: trying to init UHS-II card at %u Hz\n",
+ mmc_hostname(host), __func__, host->f_init);
+ err = sd_uhs2_attach(host);
+ if (!err)
+ break;
+ }
+
+ return err;
+}
+
+/*
+ * mmc_uhs2_prepare_cmd - prepare for SD command packet
+ * @host: MMC host
+ * @mrq: MMC request
+ *
+ * Initialize and fill in a header and a payload of SD command packet.
+ * The caller should allocate uhs2_command in host->cmd->uhs2_cmd in
+ * advance.
+ *
+ * Return: 0 on success, non-zero error on failure
+ */
+void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq)
+{
+ struct mmc_command *cmd;
+ struct uhs2_command *uhs2_cmd;
+ u8 plen;
+
+ cmd = mrq->cmd;
+ cmd->uhs2_cmd = &mrq->uhs2_cmd;
+ uhs2_cmd = cmd->uhs2_cmd;
+ uhs2_cmd->header = host->card->uhs2_config.node_id;
+ if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC)
+ uhs2_cmd->header |= UHS2_PACKET_TYPE_DCMD;
+ else
+ uhs2_cmd->header |= UHS2_PACKET_TYPE_CCMD;
+
+ uhs2_cmd->arg = cmd->opcode << UHS2_SD_CMD_INDEX_POS;
+ if (host->uhs2_app_cmd) {
+ uhs2_cmd->arg |= UHS2_SD_CMD_APP;
+ host->uhs2_app_cmd = false;
+ }
+
+ /*
+ * UHS-II Addendum 7.2.1.2
+ * Host may set DM to 1 for DCMD which supports multi-block read/write regardless of
+ * data transfer length (e.g., CMD18, CMD25). Otherwise, it shall not set DM to 1.
+ * (e.g., CMD6, CMD17, CMD24). These rules are also applied to other multi-block read/write
+ * commands defined in other Part of SD specifications (for example, Host may set DM to 1
+ * for ACMD18 or ACMD25).
+ */
+ if (mmc_op_multi(cmd->opcode))
+ cmd->uhs2_cmd->tmode_half_duplex = mmc_card_uhs2_hd_mode(host);
+ else
+ cmd->uhs2_cmd->tmode_half_duplex = 0;
+
+ uhs2_cmd = cmd->uhs2_cmd;
+ plen = 2; /* at the maximum */
+
+ if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC &&
+ cmd->uhs2_cmd->tmode_half_duplex) {
+ if (mmc_card_uhs2_hd_mode(host))
+ uhs2_cmd->arg |= UHS2_DCMD_2L_HD_MODE;
+
+ uhs2_cmd->arg |= UHS2_DCMD_LM_TLEN_EXIST;
+
+ if (cmd->data->blocks == 1 &&
+ cmd->data->blksz != 512 &&
+ cmd->opcode != MMC_READ_SINGLE_BLOCK &&
+ cmd->opcode != MMC_WRITE_BLOCK) {
+ uhs2_cmd->arg |= UHS2_DCMD_TLUM_BYTE_MODE;
+ uhs2_cmd->payload[1] = cpu_to_be32(cmd->data->blksz);
+ } else {
+ uhs2_cmd->payload[1] = cpu_to_be32(cmd->data->blocks);
+ }
+ } else {
+ plen = 1;
+ }
+
+ uhs2_cmd->payload[0] = cpu_to_be32(cmd->arg);
+ sd_uhs2_cmd_assemble(cmd, uhs2_cmd, plen, 0);
+}
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index cc43687ca241..83085e76486a 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -1,16 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/sdio.c
*
* Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#include <linux/err.h>
#include <linux/pm_runtime.h>
+#include <linux/sysfs.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@@ -31,6 +28,48 @@
#include "sdio_ops.h"
#include "sdio_cis.h"
+MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor);
+MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device);
+MMC_DEV_ATTR(revision, "%u.%u\n", card->major_rev, card->minor_rev);
+MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
+MMC_DEV_ATTR(rca, "0x%04x\n", card->rca);
+
+#define sdio_info_attr(num) \
+static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct mmc_card *card = mmc_dev_to_card(dev); \
+ \
+ if (num > card->num_info) \
+ return -ENODATA; \
+ if (!card->info[num - 1][0]) \
+ return 0; \
+ return sysfs_emit(buf, "%s\n", card->info[num - 1]); \
+} \
+static DEVICE_ATTR_RO(info##num)
+
+sdio_info_attr(1);
+sdio_info_attr(2);
+sdio_info_attr(3);
+sdio_info_attr(4);
+
+static struct attribute *sdio_std_attrs[] = {
+ &dev_attr_vendor.attr,
+ &dev_attr_device.attr,
+ &dev_attr_revision.attr,
+ &dev_attr_info1.attr,
+ &dev_attr_info2.attr,
+ &dev_attr_info3.attr,
+ &dev_attr_info4.attr,
+ &dev_attr_ocr.attr,
+ &dev_attr_rca.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(sdio_std);
+
+static const struct device_type sdio_type = {
+ .groups = sdio_std_groups,
+};
+
static int sdio_read_fbr(struct sdio_func *func)
{
int ret;
@@ -159,18 +198,21 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
if (ret)
goto out;
- if (mmc_host_uhs(card->host)) {
+ if (mmc_host_can_uhs(card->host)) {
if (data & SDIO_UHS_DDR50)
card->sw_caps.sd3_bus_mode
- |= SD_MODE_UHS_DDR50;
+ |= SD_MODE_UHS_DDR50 | SD_MODE_UHS_SDR50
+ | SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12;
if (data & SDIO_UHS_SDR50)
card->sw_caps.sd3_bus_mode
- |= SD_MODE_UHS_SDR50;
+ |= SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR25
+ | SD_MODE_UHS_SDR12;
if (data & SDIO_UHS_SDR104)
card->sw_caps.sd3_bus_mode
- |= SD_MODE_UHS_SDR104;
+ |= SD_MODE_UHS_SDR104 | SD_MODE_UHS_SDR50
+ | SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12;
}
ret = mmc_io_rw_direct(card, 0, 0,
@@ -184,6 +226,20 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
if (data & SDIO_DRIVE_SDTD)
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTERRUPT_EXT, 0, &data);
+ if (ret)
+ goto out;
+
+ if (data & SDIO_INTERRUPT_EXT_SAI) {
+ data |= SDIO_INTERRUPT_EXT_EAI;
+ ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_INTERRUPT_EXT,
+ data, NULL);
+ if (ret)
+ goto out;
+
+ card->cccr.enable_async_irq = 1;
+ }
}
/* if no uhs mode ensure we check for high speed */
@@ -289,30 +345,49 @@ static int sdio_disable_wide(struct mmc_card *card)
return 0;
}
+static int sdio_disable_4bit_bus(struct mmc_card *card)
+{
+ int err;
+
+ if (mmc_card_sdio(card))
+ goto out;
+
+ if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
+ return 0;
+
+ if (!(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4))
+ return 0;
+
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
+ if (err)
+ return err;
+
+out:
+ return sdio_disable_wide(card);
+}
+
static int sdio_enable_4bit_bus(struct mmc_card *card)
{
int err;
- if (card->type == MMC_TYPE_SDIO)
- err = sdio_enable_wide(card);
- else if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ err = sdio_enable_wide(card);
+ if (err <= 0)
+ return err;
+ if (mmc_card_sdio(card))
+ goto out;
+
+ if (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) {
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err)
+ if (err) {
+ sdio_disable_wide(card);
return err;
- err = sdio_enable_wide(card);
- if (err <= 0)
- mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
- } else
- return 0;
-
- if (err > 0) {
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- err = 0;
+ }
}
+out:
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- return err;
+ return 0;
}
@@ -354,7 +429,7 @@ static int sdio_enable_hs(struct mmc_card *card)
int ret;
ret = mmc_sdio_switch_hs(card, true);
- if (ret <= 0 || card->type == MMC_TYPE_SDIO)
+ if (ret <= 0 || mmc_card_sdio(card))
return ret;
ret = mmc_sd_switch_hs(card);
@@ -380,9 +455,11 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
max_dtr = card->cis.max_dtr;
}
- if (card->type == MMC_TYPE_SD_COMBO)
+ if (mmc_card_sd_combo(card))
max_dtr = min(max_dtr, mmc_sd_get_max_clock(card));
+ max_dtr = min_not_zero(max_dtr, card->quirk_max_rate);
+
return max_dtr;
}
@@ -444,12 +521,13 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
unsigned int bus_speed, timing;
int err;
unsigned char speed;
+ unsigned int max_rate;
/*
* If the host doesn't support any of the UHS-I modes, fallback on
* default speed.
*/
- if (!mmc_host_uhs(card->host))
+ if (!mmc_host_can_uhs(card->host))
return 0;
bus_speed = SDIO_SPEED_SDR12;
@@ -500,10 +578,11 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
if (err)
return err;
- if (bus_speed) {
- mmc_set_timing(card->host, timing);
- mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
- }
+ max_rate = min_not_zero(card->quirk_max_rate,
+ card->sw_caps.uhs_max_dtr);
+
+ mmc_set_timing(card->host, timing);
+ mmc_set_clock(card->host, max_rate);
return 0;
}
@@ -518,11 +597,10 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
if (!card->scr.sda_spec3)
return 0;
- /*
- * Switch to wider bus (if supported).
- */
- if (card->host->caps & MMC_CAP_4_BIT_DATA)
- err = sdio_enable_4bit_bus(card);
+ /* Switch to wider bus */
+ err = sdio_enable_4bit_bus(card);
+ if (err)
+ goto out;
/* Set the driver strength for the card */
sdio_select_driver_type(card);
@@ -544,13 +622,33 @@ out:
return err;
}
-static void mmc_sdio_resend_if_cond(struct mmc_host *host,
- struct mmc_card *card)
+static int mmc_sdio_pre_init(struct mmc_host *host, u32 ocr,
+ struct mmc_card *card)
{
+ if (card)
+ mmc_remove_card(card);
+
+ /*
+ * Reset the card by performing the same steps that are taken by
+ * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
+ *
+ * sdio_reset() is technically not needed. Having just powered up the
+ * hardware, it should already be in reset state. However, some
+ * platforms (such as SD8686 on OLPC) do not instantly cut power,
+ * meaning that a reset is required when restoring power soon after
+ * powering off. It is harmless in other cases.
+ *
+ * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
+ * is not necessary for non-removable cards. However, it is required
+ * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
+ * harmless in other situations.
+ *
+ */
+
sdio_reset(host);
mmc_go_idle(host);
- mmc_send_if_cond(host, host->ocr_avail);
- mmc_remove_card(card);
+ mmc_send_if_cond(host, ocr);
+ return mmc_send_io_op_cond(host, 0, NULL);
}
/*
@@ -560,7 +658,7 @@ static void mmc_sdio_resend_if_cond(struct mmc_host *host,
* we're trying to reinitialise.
*/
static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
- struct mmc_card *oldcard, int powered_resume)
+ struct mmc_card *oldcard)
{
struct mmc_card *card;
int err;
@@ -571,7 +669,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
WARN_ON(!host->claimed);
/* to query card if 1.8V signalling is supported */
- if (mmc_host_uhs(host))
+ if (mmc_host_can_uhs(host))
ocr |= R4_18V_PRESENT;
try_again:
@@ -583,11 +681,9 @@ try_again:
/*
* Inform the card of the voltage
*/
- if (!powered_resume) {
- err = mmc_send_io_op_cond(host, ocr, &rocr);
- if (err)
- goto err;
- }
+ err = mmc_send_io_op_cond(host, ocr, &rocr);
+ if (err)
+ return err;
/*
* For SPI, enable CRC as appropriate.
@@ -595,33 +691,31 @@ try_again:
if (mmc_host_is_spi(host)) {
err = mmc_spi_set_crc(host, use_spi_crc);
if (err)
- goto err;
+ return err;
}
/*
* Allocate card structure.
*/
- card = mmc_alloc_card(host, NULL);
- if (IS_ERR(card)) {
- err = PTR_ERR(card);
- goto err;
- }
+ card = mmc_alloc_card(host, &sdio_type);
+ if (IS_ERR(card))
+ return PTR_ERR(card);
if ((rocr & R4_MEMORY_PRESENT) &&
mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) {
card->type = MMC_TYPE_SD_COMBO;
- if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
+ if (oldcard && (!mmc_card_sd_combo(oldcard) ||
memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) {
- mmc_remove_card(card);
- return -ENOENT;
+ err = -ENOENT;
+ goto mismatch;
}
} else {
card->type = MMC_TYPE_SDIO;
- if (oldcard && oldcard->type != MMC_TYPE_SDIO) {
- mmc_remove_card(card);
- return -ENOENT;
+ if (oldcard && !mmc_card_sdio(oldcard)) {
+ err = -ENOENT;
+ goto mismatch;
}
}
@@ -630,6 +724,9 @@ try_again:
*/
if (host->ops->init_card)
host->ops->init_card(host, card);
+ mmc_fixup_device(card, sdio_card_init_methods);
+
+ card->ocr = ocr_card;
/*
* If the host and card support UHS-I mode request the card
@@ -642,10 +739,10 @@ try_again:
* try to init uhs card. sdio_read_cccr will take over this task
* to make sure which speed mode should work.
*/
- if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
+ if (rocr & ocr & R4_18V_PRESENT) {
err = mmc_set_uhs_voltage(host, ocr_card);
if (err == -EAGAIN) {
- mmc_sdio_resend_if_cond(host, card);
+ mmc_sdio_pre_init(host, ocr_card, card);
retries--;
goto try_again;
} else if (err) {
@@ -656,7 +753,7 @@ try_again:
/*
* For native busses: set card RCA and quit open drain mode.
*/
- if (!powered_resume && !mmc_host_is_spi(host)) {
+ if (!mmc_host_is_spi(host)) {
err = mmc_send_relative_addr(host, &card->rca);
if (err)
goto remove;
@@ -673,10 +770,10 @@ try_again:
/*
* Read CSD, before selecting the card
*/
- if (!oldcard && card->type == MMC_TYPE_SD_COMBO) {
- err = mmc_sd_get_csd(host, card);
+ if (!oldcard && mmc_card_sd_combo(card)) {
+ err = mmc_sd_get_csd(card, false);
if (err)
- return err;
+ goto remove;
mmc_decode_cid(card);
}
@@ -684,7 +781,7 @@ try_again:
/*
* Select card, as all following commands rely on that.
*/
- if (!powered_resume && !mmc_host_is_spi(host)) {
+ if (!mmc_host_is_spi(host)) {
err = mmc_select_card(card);
if (err)
goto remove;
@@ -703,7 +800,12 @@ try_again:
mmc_set_timing(card->host, MMC_TIMING_SD_HS);
}
- goto finish;
+ if (oldcard)
+ mmc_remove_card(card);
+ else
+ host->card = card;
+
+ return 0;
}
/*
@@ -712,14 +814,13 @@ try_again:
*/
err = sdio_read_cccr(card, ocr);
if (err) {
- mmc_sdio_resend_if_cond(host, card);
+ mmc_sdio_pre_init(host, ocr_card, card);
if (ocr & R4_18V_PRESENT) {
/* Retry init sequence, but without R4_18V_PRESENT. */
retries = 0;
goto try_again;
- } else {
- goto remove;
}
+ return err;
}
/*
@@ -730,18 +831,19 @@ try_again:
goto remove;
if (oldcard) {
- int same = (card->cis.vendor == oldcard->cis.vendor &&
- card->cis.device == oldcard->cis.device);
- mmc_remove_card(card);
- if (!same)
- return -ENOENT;
-
- card = oldcard;
+ if (card->cis.vendor == oldcard->cis.vendor &&
+ card->cis.device == oldcard->cis.device) {
+ mmc_remove_card(card);
+ card = oldcard;
+ } else {
+ err = -ENOENT;
+ goto mismatch;
+ }
}
- card->ocr = ocr_card;
+
mmc_fixup_device(card, sdio_fixup_methods);
- if (card->type == MMC_TYPE_SD_COMBO) {
+ if (mmc_card_sd_combo(card)) {
err = mmc_sd_setup_card(host, card, oldcard != NULL);
/* handle as SDIO-only card if memory init failed */
if (err) {
@@ -789,19 +891,37 @@ try_again:
if (err)
goto remove;
}
-finish:
- if (!oldcard)
- host->card = card;
+
+ if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
+ host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+ pr_err("%s: Host failed to negotiate down from 3.3V\n",
+ mmc_hostname(host));
+ err = -EINVAL;
+ goto remove;
+ }
+
+ host->card = card;
return 0;
+mismatch:
+ pr_debug("%s: Perhaps the card was replaced\n", mmc_hostname(host));
remove:
- if (!oldcard)
+ if (oldcard != card)
mmc_remove_card(card);
-
-err:
return err;
}
+static int mmc_sdio_reinit_card(struct mmc_host *host)
+{
+ int ret;
+
+ ret = mmc_sdio_pre_init(host, host->card->ocr, NULL);
+ if (ret)
+ return ret;
+
+ return mmc_sdio_init_card(host, host->card->ocr, host->card);
+}
+
/*
* Host is being removed. Free up the current card.
*/
@@ -825,7 +945,11 @@ static void mmc_sdio_remove(struct mmc_host *host)
*/
static int mmc_sdio_alive(struct mmc_host *host)
{
- return mmc_select_card(host->card);
+ if (!mmc_host_is_spi(host))
+ return mmc_select_card(host->card);
+ else
+ return mmc_io_rw_direct(host->card, 0, 0, SDIO_CCCR_CCCR, 0,
+ NULL);
}
/*
@@ -837,11 +961,9 @@ static void mmc_sdio_detect(struct mmc_host *host)
/* Make sure card is powered before detecting it */
if (host->caps & MMC_CAP_POWER_OFF_CARD) {
- err = pm_runtime_get_sync(&host->card->dev);
- if (err < 0) {
- pm_runtime_put_noidle(&host->card->dev);
+ err = pm_runtime_resume_and_get(&host->card->dev);
+ if (err < 0)
goto out;
- }
}
mmc_claim_host(host);
@@ -885,21 +1007,37 @@ out:
*/
static int mmc_sdio_pre_suspend(struct mmc_host *host)
{
- int i, err = 0;
+ int i;
for (i = 0; i < host->card->sdio_funcs; i++) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
- if (!pmops || !pmops->suspend || !pmops->resume) {
+ if (!pmops || !pmops->suspend || !pmops->resume)
/* force removal of entire card in that case */
- err = -ENOSYS;
- break;
- }
+ goto remove;
}
}
- return err;
+ return 0;
+
+remove:
+ if (!mmc_card_is_removable(host)) {
+ dev_warn(mmc_dev(host),
+ "missing suspend/resume ops for non-removable SDIO card\n");
+ /* Don't remove a non-removable card - we can't re-detect it. */
+ return 0;
+ }
+
+ /* Remove the SDIO card and let it be re-detected later on. */
+ mmc_sdio_remove(host);
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_power_off(host);
+ mmc_release_host(host);
+ host->pm_flags = 0;
+
+ return 0;
}
/*
@@ -907,10 +1045,16 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host)
*/
static int mmc_sdio_suspend(struct mmc_host *host)
{
+ WARN_ON(host->sdio_irqs && !mmc_card_keep_power(host));
+
+ /* Prevent processing of SDIO IRQs in suspended state. */
+ mmc_card_set_suspended(host->card);
+ cancel_work_sync(&host->sdio_irq_work);
+
mmc_claim_host(host);
if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host))
- sdio_disable_wide(host->card);
+ sdio_disable_4bit_bus(host->card);
if (!mmc_card_keep_power(host)) {
mmc_power_off(host);
@@ -931,7 +1075,11 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Basic card reinitialization. */
mmc_claim_host(host);
- /* Restore power if needed */
+ /*
+ * Restore power and reinitialize the card when needed. Note that a
+ * removable card is checked from a detect work later on in the resume
+ * process.
+ */
if (!mmc_card_keep_power(host)) {
mmc_power_up(host, host->card->ocr);
/*
@@ -945,78 +1093,38 @@ static int mmc_sdio_resume(struct mmc_host *host)
pm_runtime_set_active(&host->card->dev);
pm_runtime_enable(&host->card->dev);
}
- }
-
- /* No need to reinitialize powered-resumed nonremovable cards */
- if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
- sdio_reset(host);
- mmc_go_idle(host);
- mmc_send_if_cond(host, host->card->ocr);
- err = mmc_send_io_op_cond(host, 0, NULL);
- if (!err)
- err = mmc_sdio_init_card(host, host->card->ocr,
- host->card,
- mmc_card_keep_power(host));
- } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
- /* We may have switched to 1-bit mode during suspend */
+ err = mmc_sdio_reinit_card(host);
+ } else if (mmc_card_wake_sdio_irq(host)) {
+ /*
+ * We may have switched to 1-bit mode during suspend,
+ * need to hold retuning, because tuning only supprt
+ * 4-bit mode or 8 bit mode.
+ */
+ mmc_retune_hold_now(host);
err = sdio_enable_4bit_bus(host->card);
+ mmc_retune_release(host);
}
- if (!err && host->sdio_irqs) {
+ if (err)
+ goto out;
+
+ /* Allow SDIO IRQs to be processed again. */
+ mmc_card_clr_suspended(host->card);
+
+ if (host->sdio_irqs) {
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
wake_up_process(host->sdio_irq_thread);
else if (host->caps & MMC_CAP_SDIO_IRQ)
- host->ops->enable_sdio_irq(host, 1);
+ schedule_work(&host->sdio_irq_work);
}
+out:
mmc_release_host(host);
host->pm_flags &= ~MMC_PM_KEEP_POWER;
return err;
}
-static int mmc_sdio_power_restore(struct mmc_host *host)
-{
- int ret;
-
- mmc_claim_host(host);
-
- /*
- * Reset the card by performing the same steps that are taken by
- * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
- *
- * sdio_reset() is technically not needed. Having just powered up the
- * hardware, it should already be in reset state. However, some
- * platforms (such as SD8686 on OLPC) do not instantly cut power,
- * meaning that a reset is required when restoring power soon after
- * powering off. It is harmless in other cases.
- *
- * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
- * is not necessary for non-removable cards. However, it is required
- * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
- * harmless in other situations.
- *
- */
-
- sdio_reset(host);
- mmc_go_idle(host);
- mmc_send_if_cond(host, host->card->ocr);
-
- ret = mmc_send_io_op_cond(host, 0, NULL);
- if (ret)
- goto out;
-
- ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
- mmc_card_keep_power(host));
- if (!ret && host->sdio_irqs)
- mmc_signal_sdio_irq(host);
-
-out:
- mmc_release_host(host);
-
- return ret;
-}
-
static int mmc_sdio_runtime_suspend(struct mmc_host *host)
{
/* No references to the card, cut the power to it. */
@@ -1034,16 +1142,54 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
/* Restore power and re-initialize. */
mmc_claim_host(host);
mmc_power_up(host, host->card->ocr);
- ret = mmc_sdio_power_restore(host);
+ ret = mmc_sdio_reinit_card(host);
mmc_release_host(host);
return ret;
}
-static int mmc_sdio_reset(struct mmc_host *host)
+/*
+ * SDIO HW reset
+ *
+ * Returns 0 if the HW reset was executed synchronously, returns 1 if the HW
+ * reset was asynchronously scheduled, else a negative error code.
+ */
+static int mmc_sdio_hw_reset(struct mmc_host *host)
{
- mmc_power_cycle(host, host->card->ocr);
- return mmc_sdio_power_restore(host);
+ struct mmc_card *card = host->card;
+
+ /*
+ * In case the card is shared among multiple func drivers, reset the
+ * card through a rescan work. In this way it will be removed and
+ * re-detected, thus all func drivers becomes informed about it.
+ */
+ if (atomic_read(&card->sdio_funcs_probed) > 1) {
+ if (mmc_card_removed(card))
+ return 1;
+ host->rescan_entered = 0;
+ mmc_card_set_removed(card);
+ _mmc_detect_change(host, 0, false);
+ return 1;
+ }
+
+ /*
+ * A single func driver has been probed, then let's skip the heavy
+ * hotplug dance above and execute the reset immediately.
+ */
+ mmc_power_cycle(host, card->ocr);
+ return mmc_sdio_reinit_card(host);
+}
+
+static int mmc_sdio_sw_reset(struct mmc_host *host)
+{
+ mmc_set_clock(host, host->f_init);
+ sdio_reset(host);
+ mmc_go_idle(host);
+
+ mmc_set_initial_state(host);
+ mmc_set_initial_signal_voltage(host);
+
+ return mmc_sdio_reinit_card(host);
}
static const struct mmc_bus_ops mmc_sdio_ops = {
@@ -1054,9 +1200,9 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
.resume = mmc_sdio_resume,
.runtime_suspend = mmc_sdio_runtime_suspend,
.runtime_resume = mmc_sdio_runtime_resume,
- .power_restore = mmc_sdio_power_restore,
.alive = mmc_sdio_alive,
- .reset = mmc_sdio_reset,
+ .hw_reset = mmc_sdio_hw_reset,
+ .sw_reset = mmc_sdio_sw_reset,
};
@@ -1093,7 +1239,7 @@ int mmc_attach_sdio(struct mmc_host *host)
/*
* Detect and init the card.
*/
- err = mmc_sdio_init_card(host, rocr, NULL, 0);
+ err = mmc_sdio_init_card(host, rocr, NULL);
if (err)
goto err;
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 2b32b88949ba..10799772494a 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/core/sdio_bus.c
*
* Copyright 2007 Pierre Ossman
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
* SDIO function driver model
*/
@@ -18,6 +14,7 @@
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h>
#include <linux/acpi.h>
+#include <linux/sysfs.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -29,37 +26,53 @@
#include "sdio_cis.h"
#include "sdio_bus.h"
-#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
+#define to_sdio_driver(d) container_of_const(d, struct sdio_driver, drv)
/* show configuration fields */
-#define sdio_config_attr(field, format_string) \
+#define sdio_config_attr(field, format_string, args...) \
static ssize_t \
field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct sdio_func *func; \
\
func = dev_to_sdio_func (dev); \
- return sprintf (buf, format_string, func->field); \
+ return sysfs_emit(buf, format_string, args); \
} \
static DEVICE_ATTR_RO(field)
-sdio_config_attr(class, "0x%02x\n");
-sdio_config_attr(vendor, "0x%04x\n");
-sdio_config_attr(device, "0x%04x\n");
-
-static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct sdio_func *func = dev_to_sdio_func (dev);
-
- return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
- func->class, func->vendor, func->device);
-}
-static DEVICE_ATTR_RO(modalias);
+sdio_config_attr(class, "0x%02x\n", func->class);
+sdio_config_attr(vendor, "0x%04x\n", func->vendor);
+sdio_config_attr(device, "0x%04x\n", func->device);
+sdio_config_attr(revision, "%u.%u\n", func->major_rev, func->minor_rev);
+sdio_config_attr(modalias, "sdio:c%02Xv%04Xd%04X\n", func->class, func->vendor, func->device);
+
+#define sdio_info_attr(num) \
+static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct sdio_func *func = dev_to_sdio_func(dev); \
+ \
+ if (num > func->num_info) \
+ return -ENODATA; \
+ if (!func->info[num - 1][0]) \
+ return 0; \
+ return sysfs_emit(buf, "%s\n", func->info[num - 1]); \
+} \
+static DEVICE_ATTR_RO(info##num)
+
+sdio_info_attr(1);
+sdio_info_attr(2);
+sdio_info_attr(3);
+sdio_info_attr(4);
static struct attribute *sdio_dev_attrs[] = {
&dev_attr_class.attr,
&dev_attr_vendor.attr,
&dev_attr_device.attr,
+ &dev_attr_revision.attr,
+ &dev_attr_info1.attr,
+ &dev_attr_info2.attr,
+ &dev_attr_info3.attr,
+ &dev_attr_info4.attr,
&dev_attr_modalias.attr,
NULL,
};
@@ -78,7 +91,7 @@ static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
}
static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
- struct sdio_driver *sdrv)
+ const struct sdio_driver *sdrv)
{
const struct sdio_device_id *ids;
@@ -95,10 +108,10 @@ static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
return NULL;
}
-static int sdio_bus_match(struct device *dev, struct device_driver *drv)
+static int sdio_bus_match(struct device *dev, const struct device_driver *drv)
{
struct sdio_func *func = dev_to_sdio_func(dev);
- struct sdio_driver *sdrv = to_sdio_driver(drv);
+ const struct sdio_driver *sdrv = to_sdio_driver(drv);
if (sdio_match_device(func, sdrv))
return 1;
@@ -107,19 +120,29 @@ static int sdio_bus_match(struct device *dev, struct device_driver *drv)
}
static int
-sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+sdio_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct sdio_func *func = dev_to_sdio_func(dev);
+ const struct sdio_func *func = dev_to_sdio_func(dev);
+ unsigned int i;
if (add_uevent_var(env,
"SDIO_CLASS=%02X", func->class))
return -ENOMEM;
- if (add_uevent_var(env,
+ if (add_uevent_var(env,
"SDIO_ID=%04X:%04X", func->vendor, func->device))
return -ENOMEM;
if (add_uevent_var(env,
+ "SDIO_REVISION=%u.%u", func->major_rev, func->minor_rev))
+ return -ENOMEM;
+
+ for (i = 0; i < func->num_info; i++) {
+ if (add_uevent_var(env, "SDIO_INFO%u=%s", i+1, func->info[i]))
+ return -ENOMEM;
+ }
+
+ if (add_uevent_var(env,
"MODALIAS=sdio:c%02Xv%04Xd%04X",
func->class, func->vendor, func->device))
return -ENOMEM;
@@ -138,10 +161,12 @@ static int sdio_bus_probe(struct device *dev)
if (!id)
return -ENODEV;
- ret = dev_pm_domain_attach(dev, false);
- if (ret == -EPROBE_DEFER)
+ ret = dev_pm_domain_attach(dev, 0);
+ if (ret)
return ret;
+ atomic_inc(&func->card->sdio_funcs_probed);
+
/* Unbound SDIO functions are always suspended.
* During probe, the function is set active and the usage count
* is incremented. If the driver supports runtime PM,
@@ -157,7 +182,10 @@ static int sdio_bus_probe(struct device *dev)
/* Set the default block size so the driver is sure it's something
* sensible. */
sdio_claim_host(func);
- ret = sdio_set_block_size(func, 0);
+ if (mmc_card_removed(func->card))
+ ret = -ENOMEDIUM;
+ else
+ ret = sdio_set_block_size(func, 0);
sdio_release_host(func);
if (ret)
goto disable_runtimepm;
@@ -169,23 +197,23 @@ static int sdio_bus_probe(struct device *dev)
return 0;
disable_runtimepm:
+ atomic_dec(&func->card->sdio_funcs_probed);
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
pm_runtime_put_noidle(dev);
- dev_pm_domain_detach(dev, false);
return ret;
}
-static int sdio_bus_remove(struct device *dev)
+static void sdio_bus_remove(struct device *dev)
{
struct sdio_driver *drv = to_sdio_driver(dev->driver);
struct sdio_func *func = dev_to_sdio_func(dev);
- int ret = 0;
/* Make sure card is powered before invoking ->remove() */
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
pm_runtime_get_sync(dev);
drv->remove(func);
+ atomic_dec(&func->card->sdio_funcs_probed);
if (func->irq_handler) {
pr_warn("WARNING: driver %s did not remove its interrupt handler!\n",
@@ -202,10 +230,6 @@ static int sdio_bus_remove(struct device *dev)
/* Then undo the runtime PM settings in sdio_bus_probe() */
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
pm_runtime_put_sync(dev);
-
- dev_pm_domain_detach(dev, false);
-
- return ret;
}
static const struct dev_pm_ops sdio_bus_pm_ops = {
@@ -217,7 +241,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
)
};
-static struct bus_type sdio_bus_type = {
+static const struct bus_type sdio_bus_type = {
.name = "sdio",
.dev_groups = sdio_dev_groups,
.match = sdio_bus_match,
@@ -238,16 +262,19 @@ void sdio_unregister_bus(void)
}
/**
- * sdio_register_driver - register a function driver
+ * __sdio_register_driver - register a function driver
* @drv: SDIO function driver
+ * @owner: owning module/driver
*/
-int sdio_register_driver(struct sdio_driver *drv)
+int __sdio_register_driver(struct sdio_driver *drv, struct module *owner)
{
drv->drv.name = drv->name;
drv->drv.bus = &sdio_bus_type;
+ drv->drv.owner = owner;
+
return driver_register(&drv->drv);
}
-EXPORT_SYMBOL_GPL(sdio_register_driver);
+EXPORT_SYMBOL_GPL(__sdio_register_driver);
/**
* sdio_unregister_driver - unregister a function driver
@@ -264,7 +291,14 @@ static void sdio_release_func(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
- sdio_free_func_cis(func);
+ if (!(func->card->quirks & MMC_QUIRK_NONSTD_SDIO))
+ sdio_free_func_cis(func);
+
+ /*
+ * We have now removed the link to the tuples in the
+ * card structure, so remove the reference.
+ */
+ put_device(&func->card->dev);
kfree(func->info);
kfree(func->tmpbuf);
@@ -296,6 +330,12 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card)
device_initialize(&func->dev);
+ /*
+ * We may link to tuples in the card structure,
+ * we need make sure we have a reference to it.
+ */
+ get_device(&func->card->dev);
+
func->dev.parent = &card->dev;
func->dev.bus = &sdio_bus_type;
func->dev.release = sdio_release_func;
@@ -349,10 +389,9 @@ int sdio_add_func(struct sdio_func *func)
*/
void sdio_remove_func(struct sdio_func *func)
{
- if (!sdio_func_present(func))
- return;
+ if (sdio_func_present(func))
+ device_del(&func->dev);
- device_del(&func->dev);
of_node_put(func->dev.of_node);
put_device(&func->dev);
}
diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h
index b69a2540a076..27b8069a72ab 100644
--- a/drivers/mmc/core/sdio_bus.h
+++ b/drivers/mmc/core/sdio_bus.h
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* linux/drivers/mmc/core/sdio_bus.h
*
* Copyright 2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#ifndef _MMC_CORE_SDIO_BUS_H
#define _MMC_CORE_SDIO_BUS_H
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index f8c372839d24..afaa6cab1adc 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/core/sdio_cis.c
*
@@ -6,11 +7,6 @@
* Copyright: MontaVista Software Inc.
*
* Copyright 2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#include <linux/kernel.h>
@@ -24,12 +20,21 @@
#include "sdio_cis.h"
#include "sdio_ops.h"
+#define SDIO_READ_CIS_TIMEOUT_MS (10 * 1000) /* 10s */
+
static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
const unsigned char *buf, unsigned size)
{
+ u8 major_rev, minor_rev;
unsigned i, nr_strings;
char **buffer, *string;
+ if (size < 2)
+ return 0;
+
+ major_rev = buf[0];
+ minor_rev = buf[1];
+
/* Find all null-terminated (including zero length) strings in
the TPLLV1_INFO field. Trailing garbage is ignored. */
buf += 2;
@@ -61,9 +66,13 @@ static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
}
if (func) {
+ func->major_rev = major_rev;
+ func->minor_rev = minor_rev;
func->num_info = nr_strings;
func->info = (const char**)buffer;
} else {
+ card->major_rev = major_rev;
+ card->minor_rev = minor_rev;
card->num_info = nr_strings;
card->info = (const char**)buffer;
}
@@ -267,6 +276,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
do {
unsigned char tpl_code, tpl_link;
+ unsigned long timeout = jiffies +
+ msecs_to_jiffies(SDIO_READ_CIS_TIMEOUT_MS);
ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
if (ret)
@@ -319,11 +330,25 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
prev = &this->next;
if (ret == -ENOENT) {
- /* warn about unknown tuples */
- pr_warn_ratelimited("%s: queuing unknown"
- " CIS tuple 0x%02x (%u bytes)\n",
- mmc_hostname(card->host),
- tpl_code, tpl_link);
+
+ if (time_after(jiffies, timeout))
+ break;
+
+#define FMT(type) "%s: queuing " type " CIS tuple 0x%02x [%*ph] (%u bytes)\n"
+ /*
+ * Tuples in this range are reserved for
+ * vendors, so don't warn about them
+ */
+ if (tpl_code >= 0x80 && tpl_code <= 0x8f)
+ pr_debug_ratelimited(FMT("vendor"),
+ mmc_hostname(card->host),
+ tpl_code, tpl_link, this->data,
+ tpl_link);
+ else
+ pr_warn_ratelimited(FMT("unknown"),
+ mmc_hostname(card->host),
+ tpl_code, tpl_link, this->data,
+ tpl_link);
}
/* keep on analyzing tuples */
@@ -379,12 +404,6 @@ int sdio_read_func_cis(struct sdio_func *func)
return ret;
/*
- * Since we've linked to tuples in the card structure,
- * we must make sure we have a reference to it.
- */
- get_device(&func->card->dev);
-
- /*
* Vendor/device id is optional for function CIS, so
* copy it from the card structure as needed.
*/
@@ -409,11 +428,5 @@ void sdio_free_func_cis(struct sdio_func *func)
}
func->tuples = NULL;
-
- /*
- * We have now removed the link to the tuples in the
- * card structure, so remove the reference.
- */
- put_device(&func->card->dev);
}
diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h
index 16aa563faa00..6d76f6fa608c 100644
--- a/drivers/mmc/core/sdio_cis.h
+++ b/drivers/mmc/core/sdio_cis.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* linux/drivers/mmc/core/sdio_cis.h
*
* Author: Nicolas Pitre
* Created: June 11, 2007
* Copyright: MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#ifndef _MMC_SDIO_CIS_H
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index d40744bbafa9..b774bf51981d 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -1,15 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/core/sdio_io.c
*
* Copyright 2007-2008 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#include <linux/export.h>
+#include <linux/kernel.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
@@ -18,6 +15,7 @@
#include "sdio_ops.h"
#include "core.h"
#include "card.h"
+#include "host.h"
/**
* sdio_claim_host - exclusively claim a bus for a certain SDIO function
@@ -135,7 +133,7 @@ int sdio_disable_func(struct sdio_func *func)
err:
pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func));
- return -EIO;
+ return ret;
}
EXPORT_SYMBOL_GPL(sdio_disable_func);
@@ -203,6 +201,21 @@ static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
return min(mval, 512u); /* maximum size for byte mode */
}
+/*
+ * This is legacy code, which needs to be re-worked some day. Basically we need
+ * to take into account the properties of the host, as to enable the SDIO func
+ * driver layer to allocate optimal buffers.
+ */
+static inline unsigned int _sdio_align_size(unsigned int sz)
+{
+ /*
+ * FIXME: We don't have a system for the controller to tell
+ * the core about its problems yet, so for now we just 32-bit
+ * align the size.
+ */
+ return ALIGN(sz, 4);
+}
+
/**
* sdio_align_size - pads a transfer size to a more optimal value
* @func: SDIO function
@@ -230,7 +243,7 @@ unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz)
* wants to increase the size up to a point where it
* might need more than one block.
*/
- sz = mmc_align_data_size(func->card, sz);
+ sz = _sdio_align_size(sz);
/*
* If we can still do this with just a byte transfer, then
@@ -252,7 +265,7 @@ unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz)
*/
blk_sz = ((sz + func->cur_blksize - 1) /
func->cur_blksize) * func->cur_blksize;
- blk_sz = mmc_align_data_size(func->card, blk_sz);
+ blk_sz = _sdio_align_size(blk_sz);
/*
* This value is only good if it is still just
@@ -265,8 +278,7 @@ unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz)
* We failed to do one request, but at least try to
* pad the remainder properly.
*/
- byte_sz = mmc_align_data_size(func->card,
- sz % func->cur_blksize);
+ byte_sz = _sdio_align_size(sz % func->cur_blksize);
if (byte_sz <= sdio_max_byte_size(func)) {
blk_sz = sz / func->cur_blksize;
return blk_sz * func->cur_blksize + byte_sz;
@@ -276,16 +288,14 @@ unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz)
* We need multiple requests, so first check that the
* controller can handle the chunk size;
*/
- chunk_sz = mmc_align_data_size(func->card,
- sdio_max_byte_size(func));
+ chunk_sz = _sdio_align_size(sdio_max_byte_size(func));
if (chunk_sz == sdio_max_byte_size(func)) {
/*
* Fix up the size of the remainder (if any)
*/
byte_sz = orig_sz % chunk_sz;
if (byte_sz) {
- byte_sz = mmc_align_data_size(func->card,
- byte_sz);
+ byte_sz = _sdio_align_size(byte_sz);
}
return (orig_sz / chunk_sz) * chunk_sz + byte_sz;
@@ -699,6 +709,7 @@ EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps);
/**
* sdio_set_host_pm_flags - set wanted host power management capabilities
* @func: SDIO function attached to host
+ * @flags: Power Management flags to set
*
* Set a capability bitmask corresponding to wanted host controller
* power management features for the upcoming suspend state.
@@ -725,3 +736,79 @@ int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags)
return 0;
}
EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags);
+
+/**
+ * sdio_retune_crc_disable - temporarily disable retuning on CRC errors
+ * @func: SDIO function attached to host
+ *
+ * If the SDIO card is known to be in a state where it might produce
+ * CRC errors on the bus in response to commands (like if we know it is
+ * transitioning between power states), an SDIO function driver can
+ * call this function to temporarily disable the SD/MMC core behavior of
+ * triggering an automatic retuning.
+ *
+ * This function should be called while the host is claimed and the host
+ * should remain claimed until sdio_retune_crc_enable() is called.
+ * Specifically, the expected sequence of calls is:
+ * - sdio_claim_host()
+ * - sdio_retune_crc_disable()
+ * - some number of calls like sdio_writeb() and sdio_readb()
+ * - sdio_retune_crc_enable()
+ * - sdio_release_host()
+ */
+void sdio_retune_crc_disable(struct sdio_func *func)
+{
+ func->card->host->retune_crc_disable = true;
+}
+EXPORT_SYMBOL_GPL(sdio_retune_crc_disable);
+
+/**
+ * sdio_retune_crc_enable - re-enable retuning on CRC errors
+ * @func: SDIO function attached to host
+ *
+ * This is the complement to sdio_retune_crc_disable().
+ */
+void sdio_retune_crc_enable(struct sdio_func *func)
+{
+ func->card->host->retune_crc_disable = false;
+}
+EXPORT_SYMBOL_GPL(sdio_retune_crc_enable);
+
+/**
+ * sdio_retune_hold_now - start deferring retuning requests till release
+ * @func: SDIO function attached to host
+ *
+ * This function can be called if it's currently a bad time to do
+ * a retune of the SDIO card. Retune requests made during this time
+ * will be held and we'll actually do the retune sometime after the
+ * release.
+ *
+ * This function could be useful if an SDIO card is in a power state
+ * where it can respond to a small subset of commands that doesn't
+ * include the retuning command. Care should be taken when using
+ * this function since (presumably) the retuning request we might be
+ * deferring was made for a good reason.
+ *
+ * This function should be called while the host is claimed.
+ */
+void sdio_retune_hold_now(struct sdio_func *func)
+{
+ mmc_retune_hold_now(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_retune_hold_now);
+
+/**
+ * sdio_retune_release - signal that it's OK to retune now
+ * @func: SDIO function attached to host
+ *
+ * This is the complement to sdio_retune_hold_now(). Calling this
+ * function won't make a retune happen right away but will allow
+ * them to be scheduled normally.
+ *
+ * This function should be called while the host is claimed.
+ */
+void sdio_retune_release(struct sdio_func *func)
+{
+ mmc_retune_release(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_retune_release);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index c771843e4c15..2b24bdf38296 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/core/sdio_irq.c
*
@@ -6,11 +7,6 @@
* Copyright: MontaVista Software Inc.
*
* Copyright 2008 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#include <linux/kernel.h>
@@ -31,32 +27,21 @@
#include "core.h"
#include "card.h"
-static int process_sdio_pending_irqs(struct mmc_host *host)
+static int sdio_get_pending_irqs(struct mmc_host *host, u8 *pending)
{
struct mmc_card *card = host->card;
- int i, ret, count;
- unsigned char pending;
- struct sdio_func *func;
+ int ret;
- /*
- * Optimization, if there is only 1 function interrupt registered
- * and we know an IRQ was signaled then call irq handler directly.
- * Otherwise do the full probe.
- */
- func = card->sdio_single_irq;
- if (func && host->sdio_irq_pending) {
- func->irq_handler(func);
- return 1;
- }
+ WARN_ON(!host->claimed);
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, pending);
if (ret) {
pr_debug("%s: error %d reading SDIO_CCCR_INTx\n",
mmc_card_id(card), ret);
return ret;
}
- if (pending && mmc_card_broken_irq_polling(card) &&
+ if (*pending && mmc_card_broken_irq_polling(card) &&
!(host->caps & MMC_CAP_SDIO_IRQ)) {
unsigned char dummy;
@@ -67,6 +52,39 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
mmc_io_rw_direct(card, 0, 0, 0xff, 0, &dummy);
}
+ return 0;
+}
+
+static int process_sdio_pending_irqs(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+ int i, ret, count;
+ bool sdio_irq_pending = host->sdio_irq_pending;
+ unsigned char pending;
+ struct sdio_func *func;
+
+ /* Don't process SDIO IRQs if the card is suspended. */
+ if (mmc_card_suspended(card))
+ return 0;
+
+ /* Clear the flag to indicate that we have processed the IRQ. */
+ host->sdio_irq_pending = false;
+
+ /*
+ * Optimization, if there is only 1 function interrupt registered
+ * and we know an IRQ was signaled then call irq handler directly.
+ * Otherwise do the full probe.
+ */
+ func = card->sdio_single_irq;
+ if (func && sdio_irq_pending) {
+ func->irq_handler(func);
+ return 1;
+ }
+
+ ret = sdio_get_pending_irqs(host, &pending);
+ if (ret)
+ return ret;
+
count = 0;
for (i = 1; i <= 7; i++) {
if (pending & (1 << i)) {
@@ -92,41 +110,39 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
return ret;
}
-void sdio_run_irqs(struct mmc_host *host)
+static void sdio_run_irqs(struct mmc_host *host)
{
mmc_claim_host(host);
if (host->sdio_irqs) {
- host->sdio_irq_pending = true;
process_sdio_pending_irqs(host);
- if (host->ops->ack_sdio_irq)
+ if (!host->sdio_irq_pending)
host->ops->ack_sdio_irq(host);
}
mmc_release_host(host);
}
-EXPORT_SYMBOL_GPL(sdio_run_irqs);
void sdio_irq_work(struct work_struct *work)
{
struct mmc_host *host =
- container_of(work, struct mmc_host, sdio_irq_work.work);
+ container_of(work, struct mmc_host, sdio_irq_work);
sdio_run_irqs(host);
}
void sdio_signal_irq(struct mmc_host *host)
{
- queue_delayed_work(system_wq, &host->sdio_irq_work, 0);
+ host->sdio_irq_pending = true;
+ schedule_work(&host->sdio_irq_work);
}
EXPORT_SYMBOL_GPL(sdio_signal_irq);
static int sdio_irq_thread(void *_host)
{
struct mmc_host *host = _host;
- struct sched_param param = { .sched_priority = 1 };
unsigned long period, idle_period;
int ret;
- sched_setscheduler(current, SCHED_FIFO, &param);
+ sched_set_fifo_low(current);
/*
* We want to allow for SDIO cards to work even on non SDIO
@@ -155,11 +171,11 @@ static int sdio_irq_thread(void *_host)
* holding of the host lock does not cover too much work
* that doesn't require that lock to be held.
*/
- ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
+ ret = __mmc_claim_host(host, NULL,
+ &host->sdio_irq_thread_abort);
if (ret)
break;
ret = process_sdio_pending_irqs(host);
- host->sdio_irq_pending = false;
mmc_release_host(host);
/*
@@ -259,14 +275,15 @@ static void sdio_single_irq_set(struct mmc_card *card)
card->sdio_single_irq = NULL;
if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
- card->host->sdio_irqs == 1)
+ card->host->sdio_irqs == 1) {
for (i = 0; i < card->sdio_funcs; i++) {
- func = card->sdio_func[i];
- if (func && func->irq_handler) {
- card->sdio_single_irq = func;
- break;
- }
- }
+ func = card->sdio_func[i];
+ if (func && func->irq_handler) {
+ card->sdio_single_irq = func;
+ break;
+ }
+ }
+ }
}
/**
@@ -276,8 +293,8 @@ static void sdio_single_irq_set(struct mmc_card *card)
*
* Claim and activate the IRQ for the given SDIO function. The provided
* handler will be called when that IRQ is asserted. The host is always
- * claimed already when the handler is called so the handler must not
- * call sdio_claim_host() nor sdio_release_host().
+ * claimed already when the handler is called so the handler should not
+ * call sdio_claim_host() or sdio_release_host().
*/
int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
{
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index abaaba38514f..4c229dd2b6e5 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/mmc/sdio_ops.c
*
* Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#include <linux/scatterlist.h>
@@ -125,6 +121,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
struct sg_table sgtable;
unsigned int nents, left_size, i;
unsigned int seg_size = card->host->max_seg_size;
+ int err;
WARN_ON(blksz == 0);
@@ -174,28 +171,32 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
mmc_set_data_timeout(&data, card);
- mmc_wait_for_req(card->host, &mrq);
+ mmc_pre_req(card->host, &mrq);
- if (nents > 1)
- sg_free_table(&sgtable);
+ mmc_wait_for_req(card->host, &mrq);
if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- if (mmc_host_is_spi(card->host)) {
+ err = cmd.error;
+ else if (data.error)
+ err = data.error;
+ else if (mmc_host_is_spi(card->host))
/* host driver already reported errors */
- } else {
- if (cmd.resp[0] & R5_ERROR)
- return -EIO;
- if (cmd.resp[0] & R5_FUNCTION_NUMBER)
- return -EINVAL;
- if (cmd.resp[0] & R5_OUT_OF_RANGE)
- return -ERANGE;
- }
+ err = 0;
+ else if (cmd.resp[0] & R5_ERROR)
+ err = -EIO;
+ else if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+ err = -EINVAL;
+ else if (cmd.resp[0] & R5_OUT_OF_RANGE)
+ err = -ERANGE;
+ else
+ err = 0;
- return 0;
+ mmc_post_req(card->host, &mrq, err);
+
+ if (nents > 1)
+ sg_free_table(&sgtable);
+
+ return err;
}
int sdio_reset(struct mmc_host *host)
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
index 96945cafbf0b..37f79732a206 100644
--- a/drivers/mmc/core/sdio_ops.h
+++ b/drivers/mmc/core/sdio_ops.h
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* linux/drivers/mmc/sdio_ops.c
*
* Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
#ifndef _MMC_SDIO_OPS_H
@@ -25,7 +21,6 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
int sdio_reset(struct mmc_host *host);
-unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz);
void sdio_irq_work(struct work_struct *work);
static inline bool sdio_is_io_busy(u32 opcode, u32 arg)
diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c
index d3c91f412b69..7423a601e1e5 100644
--- a/drivers/mmc/core/sdio_uart.c
+++ b/drivers/mmc/core/sdio_uart.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* SDIO UART/GPS driver
*
@@ -7,11 +8,6 @@
* Author: Nicolas Pitre
* Created: June 15, 2007
* Copyright: MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
*/
/*
@@ -32,6 +28,7 @@
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/seq_file.h>
+#include <linux/serial.h>
#include <linux/serial_reg.h>
#include <linux/circ_buf.h>
#include <linux/tty.h>
@@ -181,11 +178,9 @@ static inline void sdio_uart_release_func(struct sdio_uart_port *port)
sdio_release_host(port->func);
}
-static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset)
+static inline u8 sdio_in(struct sdio_uart_port *port, int offset)
{
- unsigned char c;
- c = sdio_readb(port->func, port->regs_offset + offset, NULL);
- return c;
+ return sdio_readb(port->func, port->regs_offset + offset, NULL);
}
static inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
@@ -195,8 +190,8 @@ static inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
{
- unsigned char status;
unsigned int ret;
+ u8 status;
/* FIXME: What stops this losing the delta bits and breaking
sdio_uart_check_modem_status ? */
@@ -249,26 +244,12 @@ static inline void sdio_uart_update_mctrl(struct sdio_uart_port *port,
static void sdio_uart_change_speed(struct sdio_uart_port *port,
struct ktermios *termios,
- struct ktermios *old)
+ const struct ktermios *old)
{
unsigned char cval, fcr = 0;
unsigned int baud, quot;
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- cval = UART_LCR_WLEN5;
- break;
- case CS6:
- cval = UART_LCR_WLEN6;
- break;
- case CS7:
- cval = UART_LCR_WLEN7;
- break;
- default:
- case CS8:
- cval = UART_LCR_WLEN8;
- break;
- }
+ cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag));
if (termios->c_cflag & CSTOPB)
cval |= UART_LCR_STOP;
@@ -371,15 +352,13 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
sdio_out(port, UART_IER, port->ier);
}
-static void sdio_uart_receive_chars(struct sdio_uart_port *port,
- unsigned int *status)
+static void sdio_uart_receive_chars(struct sdio_uart_port *port, u8 *status)
{
- unsigned int ch, flag;
int max_count = 256;
do {
- ch = sdio_in(port, UART_RX);
- flag = TTY_NORMAL;
+ u8 ch = sdio_in(port, UART_RX);
+ u8 flag = TTY_NORMAL;
port->icount.rx++;
if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
@@ -443,7 +422,7 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
tty = tty_port_tty_get(&port->port);
if (tty == NULL || !kfifo_len(xmit) ||
- tty->stopped || tty->hw_stopped) {
+ tty->flow.stopped || tty->hw_stopped) {
sdio_uart_stop_tx(port);
tty_kref_put(tty);
return;
@@ -466,8 +445,8 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
{
- int status;
struct tty_struct *tty;
+ u8 status;
status = sdio_in(port, UART_MSR);
@@ -492,16 +471,16 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
port->icount.cts++;
tty = tty_port_tty_get(&port->port);
if (tty && C_CRTSCTS(tty)) {
- int cts = (status & UART_MSR_CTS);
+ bool cts = status & UART_MSR_CTS;
if (tty->hw_stopped) {
if (cts) {
- tty->hw_stopped = 0;
+ tty->hw_stopped = false;
sdio_uart_start_tx(port);
tty_wakeup(tty);
}
} else {
if (!cts) {
- tty->hw_stopped = 1;
+ tty->hw_stopped = true;
sdio_uart_stop_tx(port);
}
}
@@ -516,7 +495,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
static void sdio_uart_irq(struct sdio_func *func)
{
struct sdio_uart_port *port = sdio_get_drvdata(func);
- unsigned int iir, lsr;
+ u8 iir, lsr;
/*
* In a few places sdio_uart_irq() is called directly instead of
@@ -543,7 +522,7 @@ static void sdio_uart_irq(struct sdio_func *func)
port->in_sdio_uart_irq = NULL;
}
-static int uart_carrier_raised(struct tty_port *tport)
+static bool uart_carrier_raised(struct tty_port *tport)
{
struct sdio_uart_port *port =
container_of(tport, struct sdio_uart_port, port);
@@ -552,28 +531,27 @@ static int uart_carrier_raised(struct tty_port *tport)
return 1;
ret = sdio_uart_get_mctrl(port);
sdio_uart_release_func(port);
- if (ret & TIOCM_CAR)
- return 1;
- return 0;
+
+ return ret & TIOCM_CAR;
}
/**
* uart_dtr_rts - port helper to set uart signals
* @tport: tty port to be updated
- * @onoff: set to turn on DTR/RTS
+ * @active: set to turn on DTR/RTS
*
* Called by the tty port helpers when the modem signals need to be
* adjusted during an open, close and hangup.
*/
-static void uart_dtr_rts(struct tty_port *tport, int onoff)
+static void uart_dtr_rts(struct tty_port *tport, bool active)
{
struct sdio_uart_port *port =
container_of(tport, struct sdio_uart_port, port);
int ret = sdio_uart_claim_func(port);
if (ret)
return;
- if (onoff == 0)
+ if (!active)
sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
else
sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
@@ -651,7 +629,7 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
if (C_CRTSCTS(tty))
if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
- tty->hw_stopped = 1;
+ tty->hw_stopped = true;
clear_bit(TTY_IO_ERROR, &tty->flags);
@@ -778,8 +756,8 @@ static void sdio_uart_hangup(struct tty_struct *tty)
tty_port_hangup(&port->port);
}
-static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
- int count)
+static ssize_t sdio_uart_write(struct tty_struct *tty, const u8 *buf,
+ size_t count)
{
struct sdio_uart_port *port = tty->driver_data;
int ret;
@@ -801,19 +779,19 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
return ret;
}
-static int sdio_uart_write_room(struct tty_struct *tty)
+static unsigned int sdio_uart_write_room(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
return FIFO_SIZE - kfifo_len(&port->xmit_fifo);
}
-static int sdio_uart_chars_in_buffer(struct tty_struct *tty)
+static unsigned int sdio_uart_chars_in_buffer(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
return kfifo_len(&port->xmit_fifo);
}
-static void sdio_uart_send_xchar(struct tty_struct *tty, char ch)
+static void sdio_uart_send_xchar(struct tty_struct *tty, u8 ch)
{
struct sdio_uart_port *port = tty->driver_data;
@@ -876,7 +854,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
}
static void sdio_uart_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios)
+ const struct ktermios *old_termios)
{
struct sdio_uart_port *port = tty->driver_data;
unsigned int cflag = tty->termios.c_cflag;
@@ -900,14 +878,14 @@ static void sdio_uart_set_termios(struct tty_struct *tty,
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
+ tty->hw_stopped = false;
sdio_uart_start_tx(port);
}
/* Handle turning on CRTSCTS */
if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) {
- tty->hw_stopped = 1;
+ tty->hw_stopped = true;
sdio_uart_stop_tx(port);
}
}
@@ -1008,19 +986,6 @@ static int sdio_uart_proc_show(struct seq_file *m, void *v)
return 0;
}
-static int sdio_uart_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, sdio_uart_proc_show, NULL);
-}
-
-static const struct file_operations sdio_uart_proc_fops = {
- .owner = THIS_MODULE,
- .open = sdio_uart_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static const struct tty_port_operations sdio_uart_port_ops = {
.dtr_rts = uart_dtr_rts,
.carrier_raised = uart_carrier_raised,
@@ -1045,7 +1010,7 @@ static const struct tty_operations sdio_uart_ops = {
.tiocmset = sdio_uart_tiocmset,
.install = sdio_uart_install,
.cleanup = sdio_uart_cleanup,
- .proc_fops = &sdio_uart_proc_fops,
+ .proc_show = sdio_uart_proc_show,
};
static struct tty_driver *sdio_uart_tty_driver;
@@ -1152,9 +1117,10 @@ static int __init sdio_uart_init(void)
int ret;
struct tty_driver *tty_drv;
- sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR);
- if (!tty_drv)
- return -ENOMEM;
+ sdio_uart_tty_driver = tty_drv = tty_alloc_driver(UART_NR,
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(tty_drv))
+ return PTR_ERR(tty_drv);
tty_drv->driver_name = "sdio_uart";
tty_drv->name = "ttySDIO";
@@ -1162,7 +1128,6 @@ static int __init sdio_uart_init(void)
tty_drv->minor_start = 0;
tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
tty_drv->subtype = SERIAL_TYPE_NORMAL;
- tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_drv->init_termios = tty_std_termios;
tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
tty_drv->init_termios.c_ispeed = 4800;
@@ -1182,7 +1147,7 @@ static int __init sdio_uart_init(void)
err2:
tty_unregister_driver(tty_drv);
err1:
- put_tty_driver(tty_drv);
+ tty_driver_kref_put(tty_drv);
return ret;
}
@@ -1190,11 +1155,12 @@ static void __exit sdio_uart_exit(void)
{
sdio_unregister_driver(&sdio_uart_driver);
tty_unregister_driver(sdio_uart_tty_driver);
- put_tty_driver(sdio_uart_tty_driver);
+ tty_driver_kref_put(sdio_uart_tty_driver);
}
module_init(sdio_uart_init);
module_exit(sdio_uart_exit);
MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("SDIO UART/GPS driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 863f1dbbfc1b..c5bc6268803e 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -1,15 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic GPIO card-detect helper
*
* Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
@@ -23,118 +19,106 @@
struct mmc_gpio {
struct gpio_desc *ro_gpio;
struct gpio_desc *cd_gpio;
- bool override_ro_active_level;
- bool override_cd_active_level;
- irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
+ irq_handler_t cd_gpio_isr;
char *ro_label;
- char cd_label[0];
+ char *cd_label;
+ u32 cd_debounce_delay_ms;
+ int cd_irq;
};
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
/* Schedule a card detection after a debounce timeout */
struct mmc_host *host = dev_id;
+ struct mmc_gpio *ctx = host->slot.handler_priv;
host->trigger_card_event = true;
- mmc_detect_change(host, msecs_to_jiffies(200));
+ mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms));
return IRQ_HANDLED;
}
int mmc_gpio_alloc(struct mmc_host *host)
{
- size_t len = strlen(dev_name(host->parent)) + 4;
- struct mmc_gpio *ctx = devm_kzalloc(host->parent,
- sizeof(*ctx) + 2 * len, GFP_KERNEL);
-
- if (ctx) {
- ctx->ro_label = ctx->cd_label + len;
- snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
- snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
- host->slot.handler_priv = ctx;
- host->slot.cd_irq = -EINVAL;
- }
+ const char *devname = dev_name(host->parent);
+ struct mmc_gpio *ctx;
+
+ ctx = devm_kzalloc(host->parent, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->cd_debounce_delay_ms = 200;
+ ctx->cd_label = devm_kasprintf(host->parent, GFP_KERNEL, "%s cd", devname);
+ if (!ctx->cd_label)
+ return -ENOMEM;
+ ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL, "%s ro", devname);
+ if (!ctx->ro_label)
+ return -ENOMEM;
+ ctx->cd_irq = -EINVAL;
+ host->slot.handler_priv = ctx;
+ host->slot.cd_irq = -EINVAL;
- return ctx ? 0 : -ENOMEM;
+ return 0;
}
+void mmc_gpio_set_cd_irq(struct mmc_host *host, int irq)
+{
+ struct mmc_gpio *ctx = host->slot.handler_priv;
+
+ if (!ctx || irq < 0)
+ return;
+
+ ctx->cd_irq = irq;
+}
+EXPORT_SYMBOL(mmc_gpio_set_cd_irq);
+
int mmc_gpio_get_ro(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
+ int cansleep;
if (!ctx || !ctx->ro_gpio)
return -ENOSYS;
- if (ctx->override_ro_active_level)
- return !gpiod_get_raw_value_cansleep(ctx->ro_gpio) ^
- !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH);
-
- return gpiod_get_value_cansleep(ctx->ro_gpio);
+ cansleep = gpiod_cansleep(ctx->ro_gpio);
+ return cansleep ?
+ gpiod_get_value_cansleep(ctx->ro_gpio) :
+ gpiod_get_value(ctx->ro_gpio);
}
EXPORT_SYMBOL(mmc_gpio_get_ro);
int mmc_gpio_get_cd(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
+ int cansleep;
if (!ctx || !ctx->cd_gpio)
return -ENOSYS;
- if (ctx->override_cd_active_level)
- return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^
- !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
-
- return gpiod_get_value_cansleep(ctx->cd_gpio);
+ cansleep = gpiod_cansleep(ctx->cd_gpio);
+ return cansleep ?
+ gpiod_get_value_cansleep(ctx->cd_gpio) :
+ gpiod_get_value(ctx->cd_gpio);
}
EXPORT_SYMBOL(mmc_gpio_get_cd);
-/**
- * mmc_gpio_request_ro - request a gpio for write-protection
- * @host: mmc host
- * @gpio: gpio number requested
- *
- * As devm_* managed functions are used in mmc_gpio_request_ro(), client
- * drivers do not need to worry about freeing up memory.
- *
- * Returns zero on success, else an error.
- */
-int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
-{
- struct mmc_gpio *ctx = host->slot.handler_priv;
- int ret;
-
- if (!gpio_is_valid(gpio))
- return -EINVAL;
-
- ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
- ctx->ro_label);
- if (ret < 0)
- return ret;
-
- ctx->override_ro_active_level = true;
- ctx->ro_gpio = gpio_to_desc(gpio);
-
- return 0;
-}
-EXPORT_SYMBOL(mmc_gpio_request_ro);
-
void mmc_gpiod_request_cd_irq(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
- int ret, irq;
+ int irq = -EINVAL;
+ int ret;
if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio)
return;
- irq = gpiod_to_irq(ctx->cd_gpio);
-
/*
- * Even if gpiod_to_irq() returns a valid IRQ number, the platform might
- * still prefer to poll, e.g., because that IRQ number is already used
- * by another unit and cannot be shared.
+ * Do not use IRQ if the platform prefers to poll, e.g., because that
+ * IRQ number is already used by another unit and cannot be shared.
*/
- if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
- irq = -EINVAL;
+ if (ctx->cd_irq >= 0)
+ irq = ctx->cd_irq;
+ else if (!(host->caps & MMC_CAP_NEEDS_POLL))
+ irq = gpiod_to_irq(ctx->cd_gpio);
if (irq >= 0) {
if (!ctx->cd_gpio_isr)
@@ -151,67 +135,29 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host)
if (irq < 0)
host->caps |= MMC_CAP_NEEDS_POLL;
- else if ((host->caps & MMC_CAP_CD_WAKE) && !enable_irq_wake(irq))
- host->slot.cd_wake_enabled = true;
}
EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
-/* Register an alternate interrupt service routine for
- * the card-detect GPIO.
- */
-void mmc_gpio_set_cd_isr(struct mmc_host *host,
- irqreturn_t (*isr)(int irq, void *dev_id))
-{
- struct mmc_gpio *ctx = host->slot.handler_priv;
-
- WARN_ON(ctx->cd_gpio_isr);
- ctx->cd_gpio_isr = isr;
-}
-EXPORT_SYMBOL(mmc_gpio_set_cd_isr);
-
-/**
- * mmc_gpio_request_cd - request a gpio for card-detection
- * @host: mmc host
- * @gpio: gpio number requested
- * @debounce: debounce time in microseconds
- *
- * As devm_* managed functions are used in mmc_gpio_request_cd(), client
- * drivers do not need to worry about freeing up memory.
- *
- * If GPIO debouncing is desired, set the debounce parameter to a non-zero
- * value. The caller is responsible for ensuring that the GPIO driver associated
- * with the GPIO supports debouncing, otherwise an error will be returned.
- *
- * Returns zero on success, else an error.
- */
-int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
- unsigned int debounce)
+int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on)
{
- struct mmc_gpio *ctx = host->slot.handler_priv;
- int ret;
-
- ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
- ctx->cd_label);
- if (ret < 0)
- /*
- * don't bother freeing memory. It might still get used by other
- * slot functions, in any case it will be freed, when the device
- * is destroyed.
- */
- return ret;
-
- if (debounce) {
- ret = gpio_set_debounce(gpio, debounce);
- if (ret < 0)
- return ret;
+ int ret = 0;
+
+ if (!(host->caps & MMC_CAP_CD_WAKE) ||
+ host->slot.cd_irq < 0 ||
+ on == host->slot.cd_wake_enabled)
+ return 0;
+
+ if (on) {
+ ret = enable_irq_wake(host->slot.cd_irq);
+ host->slot.cd_wake_enabled = !ret;
+ } else {
+ disable_irq_wake(host->slot.cd_irq);
+ host->slot.cd_wake_enabled = false;
}
- ctx->override_cd_active_level = true;
- ctx->cd_gpio = gpio_to_desc(gpio);
-
- return 0;
+ return ret;
}
-EXPORT_SYMBOL(mmc_gpio_request_cd);
+EXPORT_SYMBOL(mmc_gpio_set_cd_wake);
/**
* mmc_gpiod_request_cd - request a gpio descriptor for card-detection
@@ -220,18 +166,15 @@ EXPORT_SYMBOL(mmc_gpio_request_cd);
* @idx: index of the GPIO to obtain in the consumer
* @override_active_level: ignore %GPIO_ACTIVE_LOW flag
* @debounce: debounce time in microseconds
- * @gpio_invert: will return whether the GPIO line is inverted or not, set
- * to NULL to ignore
*
- * Use this function in place of mmc_gpio_request_cd() to use the GPIO
- * descriptor API. Note that it must be called prior to mmc_add_host()
+ * Note that this must be called prior to mmc_add_host()
* otherwise the caller must also call mmc_gpiod_request_cd_irq().
*
* Returns zero on success, else an error.
*/
int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
unsigned int idx, bool override_active_level,
- unsigned int debounce, bool *gpio_invert)
+ unsigned int debounce)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
struct gpio_desc *desc;
@@ -241,48 +184,69 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
if (IS_ERR(desc))
return PTR_ERR(desc);
+ /* Update default label if no con_id provided */
+ if (!con_id)
+ gpiod_set_consumer_name(desc, ctx->cd_label);
+
if (debounce) {
ret = gpiod_set_debounce(desc, debounce);
if (ret < 0)
- return ret;
+ ctx->cd_debounce_delay_ms = debounce / 1000;
}
- if (gpio_invert)
- *gpio_invert = !gpiod_is_active_low(desc);
+ /* override forces default (active-low) polarity ... */
+ if (override_active_level && !gpiod_is_active_low(desc))
+ gpiod_toggle_active_low(desc);
+
+ /* ... or active-high */
+ if (host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH)
+ gpiod_toggle_active_low(desc);
- ctx->override_cd_active_level = override_active_level;
ctx->cd_gpio = desc;
return 0;
}
EXPORT_SYMBOL(mmc_gpiod_request_cd);
-bool mmc_can_gpio_cd(struct mmc_host *host)
+/**
+ * mmc_gpiod_set_cd_config - set config for card-detection GPIO
+ * @host: mmc host
+ * @config: Generic pinconf config (from pinconf_to_config_packed())
+ *
+ * This can be used by mmc host drivers to fixup a card-detection GPIO's config
+ * (e.g. set PIN_CONFIG_BIAS_PULL_UP) after acquiring the GPIO descriptor
+ * through mmc_gpiod_request_cd().
+ *
+ * Returns:
+ * 0 on success, or a negative errno value on error.
+ */
+int mmc_gpiod_set_cd_config(struct mmc_host *host, unsigned long config)
+{
+ struct mmc_gpio *ctx = host->slot.handler_priv;
+
+ return gpiod_set_config(ctx->cd_gpio, config);
+}
+EXPORT_SYMBOL(mmc_gpiod_set_cd_config);
+
+bool mmc_host_can_gpio_cd(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
return ctx->cd_gpio ? true : false;
}
-EXPORT_SYMBOL(mmc_can_gpio_cd);
+EXPORT_SYMBOL(mmc_host_can_gpio_cd);
/**
* mmc_gpiod_request_ro - request a gpio descriptor for write protection
* @host: mmc host
* @con_id: function within the GPIO consumer
* @idx: index of the GPIO to obtain in the consumer
- * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
* @debounce: debounce time in microseconds
- * @gpio_invert: will return whether the GPIO line is inverted or not,
- * set to NULL to ignore
- *
- * Use this function in place of mmc_gpio_request_ro() to use the GPIO
- * descriptor API.
*
* Returns zero on success, else an error.
*/
int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
- unsigned int idx, bool override_active_level,
- unsigned int debounce, bool *gpio_invert)
+ unsigned int idx, unsigned int debounce)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
struct gpio_desc *desc;
@@ -292,18 +256,29 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
if (IS_ERR(desc))
return PTR_ERR(desc);
+ /* Update default label if no con_id provided */
+ if (!con_id)
+ gpiod_set_consumer_name(desc, ctx->ro_label);
+
if (debounce) {
ret = gpiod_set_debounce(desc, debounce);
if (ret < 0)
return ret;
}
- if (gpio_invert)
- *gpio_invert = !gpiod_is_active_low(desc);
+ if (host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH)
+ gpiod_toggle_active_low(desc);
- ctx->override_ro_active_level = override_active_level;
ctx->ro_gpio = desc;
return 0;
}
EXPORT_SYMBOL(mmc_gpiod_request_ro);
+
+bool mmc_host_can_gpio_ro(struct mmc_host *host)
+{
+ struct mmc_gpio *ctx = host->slot.handler_priv;
+
+ return ctx->ro_gpio ? true : false;
+}
+EXPORT_SYMBOL(mmc_host_can_gpio_ro);
diff --git a/drivers/mmc/core/slot-gpio.h b/drivers/mmc/core/slot-gpio.h
index a06fd843f025..546a5843b40b 100644
--- a/drivers/mmc/core/slot-gpio.h
+++ b/drivers/mmc/core/slot-gpio.h
@@ -1,9 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2014 Linaro Ltd
*
* Author: Ulf Hansson <ulf.hansson@linaro.org>
- *
- * License terms: GNU General Public License (GPL) version 2
*/
#ifndef _MMC_CORE_SLOTGPIO_H
#define _MMC_CORE_SLOTGPIO_H