Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 607fdf34 authored by Ram Prakash Gupta's avatar Ram Prakash Gupta
Browse files

MMC: Core: Fix reading ext_csd and status from debugfs



When trying to read ext_csd and status of card from debugfs,
device is getting stuck. This is caused due to mishandling of
driver in type of request from block layer to command queue.

Driver in/out type of request handling added in command queue to
process request of type drv in/out.

Change-Id: I9a5a17dc262c43b4b4dfe3446c2887ffe3adc6f3
Signed-off-by: default avatarRam Prakash Gupta <rampraka@codeaurora.org>
parent 77880ea2
Loading
Loading
Loading
Loading
+102 −74
Original line number Original line Diff line number Diff line
@@ -3467,6 +3467,89 @@ static inline int mmc_blk_cmdq_part_switch(struct mmc_card *card,
	return ret;
	return ret;
}
}


static void  mmc_cmdq_wait_for_small_sector_read(struct mmc_card *card)
{
	struct mmc_host *host = card->host;
	struct mmc_cmdq_context_info *ctx = &host->cmdq_ctx;
	int ret;

	if ((card->quirks & MMC_QUIRK_CMDQ_EMPTY_BEFORE_DCMD) &&
		ctx->active_small_sector_read_reqs) {
		ret = wait_event_interruptible(ctx->queue_empty_wq,
					      !ctx->active_reqs);
		if (ret) {
			pr_err("%s: failed while waiting for the CMDQ to be empty %s err (%d)\n",
				mmc_hostname(host), __func__, ret);
			BUG_ON(1);
		}
		/* clear the counter now */
		ctx->active_small_sector_read_reqs = 0;
		/*
		 * If there were small sector (less than 8 sectors) read
		 * operations in progress then we have to wait for the
		 * outstanding requests to finish and should also have
		 * atleast 6 microseconds delay before queuing the DCMD
		 * request.
		 */
		udelay(MMC_QUIRK_CMDQ_DELAY_BEFORE_DCMD);
	}
}

static int mmc_blk_cmdq_issue_drv_op(struct mmc_card *card, struct request *req)
{
	struct mmc_queue_req *mq_rq;
	u8 **ext_csd;
	u32 status;
	int ret;

	mq_rq = req_to_mmc_queue_req(req);
	ext_csd = mq_rq->drv_op_data;

	ret = mmc_cmdq_halt_on_empty_queue(card->host);
	if (ret) {
		pr_err("%s: failed to halt on empty queue\n",
						mmc_hostname(card->host));
		blk_end_request_all(req, ret);
		return ret;
	}

	switch (mq_rq->drv_op) {
	case MMC_DRV_OP_GET_EXT_CSD:
		ret = mmc_get_ext_csd(card, ext_csd);
		if (ret) {
			pr_err("%s: failed to get ext_csd\n",
						mmc_hostname(card->host));
			goto out_unhalt;
		}
		break;
	case MMC_DRV_OP_GET_CARD_STATUS:
		ret = mmc_send_status(card, &status);
		if (ret) {
			pr_err("%s: failed to get status\n",
						mmc_hostname(card->host));
			goto out_unhalt;
		}
		ret = status;
		break;
	default:
		pr_err("%s: unknown driver specific operation\n",
					mmc_hostname(card->host));
		ret = -EINVAL;
		break;
	}
	mq_rq->drv_op_result = ret;
	ret = ret ? BLK_STS_IOERR : BLK_STS_OK;

out_unhalt:
	blk_end_request_all(req, ret);
	ret = mmc_cmdq_halt(card->host, false);
	if (ret)
		pr_err("%s: %s: failed to unhalt\n",
				mmc_hostname(card->host), __func__);

	return ret;
}

static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req)
static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req)
{
{
	int ret, err = 0;
	int ret, err = 0;
@@ -3510,42 +3593,28 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req)
	}
	}


	if (req) {
	if (req) {
		struct mmc_host *host = card->host;
		switch (req_op(req)) {
		struct mmc_cmdq_context_info *ctx = &host->cmdq_ctx;
		case REQ_OP_DISCARD:

			mmc_cmdq_wait_for_small_sector_read(card);
		if ((req_op(req) == REQ_OP_FLUSH ||
			req_op(req) ==  REQ_OP_DISCARD) &&
			(card->quirks & MMC_QUIRK_CMDQ_EMPTY_BEFORE_DCMD) &&
			ctx->active_small_sector_read_reqs) {
			ret = wait_event_interruptible(ctx->queue_empty_wq,
						      !ctx->active_reqs);
			if (ret) {
				pr_err("%s: failed while waiting for the CMDQ to be empty %s err (%d)\n",
					mmc_hostname(host), __func__, ret);
				BUG_ON(1);
			}
			/* clear the counter now */
			ctx->active_small_sector_read_reqs = 0;
			/*
			 * If there were small sector (less than 8 sectors) read
			 * operations in progress then we have to wait for the
			 * outstanding requests to finish and should also have
			 * atleast 6 microseconds delay before queuing the DCMD
			 * request.
			 */
			udelay(MMC_QUIRK_CMDQ_DELAY_BEFORE_DCMD);
		}

		if (req_op(req) == REQ_OP_DISCARD) {
			ret = mmc_blk_cmdq_issue_discard_rq(mq, req);
			ret = mmc_blk_cmdq_issue_discard_rq(mq, req);
		} else if (req_op(req) == REQ_OP_SECURE_ERASE) {
			break;
		case REQ_OP_SECURE_ERASE:
			if (!(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN))
			if (!(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN))
				ret = mmc_blk_cmdq_issue_secdiscard_rq(mq, req);
				ret = mmc_blk_cmdq_issue_secdiscard_rq(mq, req);
			else
			else
				ret = mmc_blk_cmdq_issue_discard_rq(mq, req);
				ret = mmc_blk_cmdq_issue_discard_rq(mq, req);
		} else if (req_op(req) == REQ_OP_FLUSH) {
			break;
		case REQ_OP_FLUSH:
			mmc_cmdq_wait_for_small_sector_read(card);
			ret = mmc_blk_cmdq_issue_flush_rq(mq, req);
			ret = mmc_blk_cmdq_issue_flush_rq(mq, req);
		} else {
			break;
		case REQ_OP_DRV_IN:
		case REQ_OP_DRV_OUT:
			ret = mmc_blk_cmdq_issue_drv_op(card, req);
			if (ret)
				goto out_card;
			break;
		default:
			ret = mmc_blk_cmdq_issue_rw_rq(mq, req);
			ret = mmc_blk_cmdq_issue_rw_rq(mq, req);
			/*
			/*
			 * If issuing of the request fails with eitehr EBUSY or
			 * If issuing of the request fails with eitehr EBUSY or
@@ -3568,6 +3637,7 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req)
				 */
				 */
				goto out;
				goto out;
			}
			}
			break;
		}
		}
	}
	}


@@ -3576,6 +3646,7 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req)
out:
out:
	if (req)
	if (req)
		blk_end_request_all(req, ret);
		blk_end_request_all(req, ret);
out_card:
	mmc_put_card(card);
	mmc_put_card(card);


	return ret;
	return ret;
@@ -4018,17 +4089,6 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
	struct request *req;
	struct request *req;
	int ret;
	int ret;


	mmc_get_card(card);
	if (mmc_card_cmdq(card)) {
		ret = mmc_cmdq_halt_on_empty_queue(card->host);
		if (ret) {
			pr_err("%s: halt failed while doing %s err (%d)\n",
					mmc_hostname(card->host), __func__,
					ret);
			goto out;
		}
	}

	/* Ask the block layer about the card status */
	/* Ask the block layer about the card status */
	req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
	req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
	if (IS_ERR(req))
	if (IS_ERR(req))
@@ -4042,13 +4102,6 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
	}
	}
	blk_put_request(req);
	blk_put_request(req);


	if (mmc_card_cmdq(card)) {
		if (mmc_cmdq_halt(card->host, false))
			pr_err("%s: %s: cmdq unhalt failed\n",
			       mmc_hostname(card->host), __func__);
	}
out:
	mmc_put_card(card);
	return ret;
	return ret;
}
}
DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
@@ -4072,18 +4125,6 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
	if (!buf)
	if (!buf)
		return -ENOMEM;
		return -ENOMEM;


	mmc_get_card(card);
	if (mmc_card_cmdq(card)) {
		err = mmc_cmdq_halt_on_empty_queue(card->host);
		if (err) {
			pr_err("%s: halt failed while doing %s err (%d)\n",
					mmc_hostname(card->host), __func__,
					err);
			mmc_put_card(card);
			goto out_free_halt;
		}
	}

	/* Ask the block layer for the EXT CSD */
	/* Ask the block layer for the EXT CSD */
	req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
	req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
	if (IS_ERR(req)) {
	if (IS_ERR(req)) {
@@ -4112,23 +4153,10 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)


	filp->private_data = buf;
	filp->private_data = buf;


	if (mmc_card_cmdq(card)) {
		if (mmc_cmdq_halt(card->host, false))
			pr_err("%s: %s: cmdq unhalt failed\n",
			       mmc_hostname(card->host), __func__);
	}

	mmc_put_card(card);
	kfree(ext_csd);
	kfree(ext_csd);
	return 0;
	return 0;

out_free:
out_free:
	if (mmc_card_cmdq(card)) {
		if (mmc_cmdq_halt(card->host, false))
			pr_err("%s: %s: cmdq unhalt failed\n",
			       mmc_hostname(card->host), __func__);
	}
	mmc_put_card(card);
out_free_halt:
	kfree(buf);
	kfree(buf);
	return err;
	return err;
}
}