diff options
Diffstat (limited to 'drivers/mmc/core/block.c')
| -rw-r--r-- | drivers/mmc/core/block.c | 52 | 
1 files changed, 36 insertions, 16 deletions
| diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 506dc900f5c7..1259ca22d625 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -126,6 +126,7 @@ struct mmc_blk_data {  #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 @@ -330,7 +331,7 @@ static struct attribute *mmc_disk_attrs[] = {  static umode_t mmc_disk_attrs_is_visible(struct kobject *kobj,  		struct attribute *a, int n)  { -	struct device *dev = container_of(kobj, struct device, kobj); +	struct device *dev = kobj_to_dev(kobj);  	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));  	umode_t mode = a->mode; @@ -609,11 +610,11 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,  	if (idata->rpmb || (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {  		/* -		 * Ensure RPMB/R1B command has completed by polling CMD13 -		 * "Send Status". +		 * Ensure RPMB/R1B command has completed by polling CMD13 "Send Status". Here we +		 * allow to override the default timeout value if a custom timeout is specified.  		 */ -		err = mmc_poll_for_busy(card, MMC_BLK_TIMEOUT_MS, false, -					MMC_BUSY_IO); +		err = mmc_poll_for_busy(card, idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS, +					false, MMC_BUSY_IO);  	}  	return err; @@ -676,8 +677,9 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,  	struct mmc_ioc_cmd __user *cmds = user->cmds;  	struct mmc_card *card;  	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;  	if (copy_from_user(&num_of_cmds, &user->num_of_cmds, @@ -690,15 +692,16 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,  	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;  		}  		/* This will be NULL on non-RPMB ioctl():s */ @@ -725,18 +728,18 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,  	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_data = idata; -	req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; +	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_mq_free_request(req);  cmd_err: -	for (i = 0; i < num_of_cmds; i++) { +	for (i = 0; i < n; i++) {  		kfree(idata[i]->buf);  		kfree(idata[i]);  	} @@ -1090,12 +1093,13 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)  	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; -	int err = 0, type = MMC_BLK_DISCARD; +	int err = 0;  	blk_status_t status = BLK_STS_OK;  	if (!mmc_can_erase(card)) { @@ -1111,13 +1115,13 @@ static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)  		if (card->quirks & MMC_QUIRK_INAND_CMD38) {  			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,  					 INAND_CMD38_ARG_EXT_CSD, -					 card->erase_arg == MMC_TRIM_ARG ? +					 erase_arg == MMC_TRIM_ARG ?  					 INAND_CMD38_ARG_TRIM :  					 INAND_CMD38_ARG_ERASE,  					 card->ext_csd.generic_cmd6_time);  		}  		if (!err) -			err = mmc_erase(card, from, nr, card->erase_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; @@ -1127,6 +1131,19 @@ fail:  	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; + +	mmc_blk_issue_erase_rq(mq, req, MMC_BLK_DISCARD, card->erase_arg); +} +  static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,  				       struct request *req)  { @@ -2327,6 +2344,9 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req)  		case REQ_OP_SECURE_ERASE:  			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:  			mmc_blk_issue_flush(mq, req);  			break; | 
