lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 3 May 2012 19:53:15 +0530
From:	Venkatraman S <svenkatr@...com>
To:	<linux-mmc@...r.kernel.org>, <cjb@...top.org>,
	<linux-mm@...ck.org>, <linux-fsdevel@...r.kernel.org>,
	<linux-omap@...r.kernel.org>
CC:	<linux-kernel@...r.kernel.org>, <arnd.bergmann@...aro.org>,
	<alex.lemberg@...disk.com>, <ilan.smith@...disk.com>,
	<lporzio@...ron.com>, <rmk+kernel@....linux.org.uk>,
	Venkatraman S <svenkatr@...com>
Subject: [PATCH v2 16/16] mmc: omap_hsmmc: Implement abort_req host_ops

Provide the abort_req implementation for omap_hsmmc host.

When invoked, the host controller should stop the transfer
and end the ongoing request as early as possible.

If the aborted command is a data transfer command, dma setup is
aborted and a STOP command is issued. The transfer state is
marked as an error (except when the command has almost completed
while receiving the abort request, in which case finish the command
normally).

Signed-off-by: Venkatraman S <svenkatr@...com>
---
 drivers/mmc/host/omap_hsmmc.c |   55 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 51 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index d15b149..a4da478 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -177,6 +177,7 @@ struct omap_hsmmc_host {
 	int			reqs_blocked;
 	int			use_reg;
 	int			req_in_progress;
+	int			abort_in_progress;
 	unsigned int		flags;
 	struct omap_hsmmc_next	next_data;
 
@@ -982,6 +983,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
 static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 {
 	struct mmc_data *data;
+	int err = 0;
 	int end_cmd = 0, end_trans = 0;
 
 	if (!host->req_in_progress) {
@@ -993,6 +995,11 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 		return;
 	}
 
+	if (host->abort_in_progress) {
+		end_trans = 1;
+		end_cmd = 1;
+	}
+
 	data = host->data;
 	dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
 
@@ -1021,7 +1028,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 		if ((status & DATA_TIMEOUT) ||
 			(status & DATA_CRC)) {
 			if (host->data || host->response_busy) {
-				int err = (status & DATA_TIMEOUT) ?
+				err = (status & DATA_TIMEOUT) ?
 						-ETIMEDOUT : -EILSEQ;
 
 				if (host->data)
@@ -1045,10 +1052,13 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 
 	OMAP_HSMMC_WRITE(host->base, STAT, status);
 
-	if (end_cmd || ((status & CC) && host->cmd))
+	if ((end_cmd || (status & CC)) && host->cmd)
 		omap_hsmmc_cmd_done(host, host->cmd);
-	if ((end_trans || (status & TC)) && host->mrq)
+	if ((end_trans || (status & TC)) && host->mrq) {
+		if (data)
+			data->error = err;
 		omap_hsmmc_xfer_done(host, data);
+	}
 }
 
 /*
@@ -1257,7 +1267,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
 	}
 
 	spin_lock_irqsave(&host->irq_lock, flags);
-	if (host->dma_ch < 0) {
+	if (host->dma_ch < 0 || host->abort_in_progress) {
 		spin_unlock_irqrestore(&host->irq_lock, flags);
 		return;
 	}
@@ -1478,6 +1488,40 @@ static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
 			mrq->data->host_cookie = 0;
 }
 
+static int omap_hsmmc_abort_req(struct mmc_host *mmc, struct mmc_request *req)
+{
+	struct omap_hsmmc_host *host = mmc_priv(mmc);
+	unsigned long flags;
+
+	if (!host->req_in_progress) {
+		dev_dbg(mmc_dev(host->mmc), "No request to abort\n");
+		return -EINVAL;
+	}
+	if (req && req != host->mrq) {
+		dev_dbg(mmc_dev(host->mmc), "Non matching abort request\n");
+		return -EINVAL;
+	}
+	spin_lock_irqsave(&host->irq_lock, flags);
+	host->abort_in_progress = 1;
+	omap_hsmmc_disable_irq(host);
+	spin_unlock_irqrestore(&host->irq_lock, flags);
+
+	host->response_busy = 0;
+
+	if (host->data) {
+		struct mmc_data *dat = host->data;
+		omap_hsmmc_dma_cleanup(host, -EIO);
+		dev_dbg(mmc_dev(host->mmc), "Aborting Transfer\n");
+		omap_hsmmc_xfer_done(host, dat);
+	} else if (host->cmd) {
+		dev_dbg(mmc_dev(host->mmc), "Aborting Command\n");
+		omap_hsmmc_cmd_done(host, host->cmd);
+	}
+
+	dev_dbg(mmc_dev(host->mmc), "Request %pK aborted\n", req);
+	return 0;
+
+}
 /*
  * Request function. for read/write operation
  */
@@ -1488,6 +1532,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
 
 	BUG_ON(host->req_in_progress);
 	BUG_ON(host->dma_ch != -1);
+	host->abort_in_progress = 0;
+
 	if (host->protect_card) {
 		if (host->reqs_blocked < 3) {
 			/*
@@ -1664,6 +1710,7 @@ static const struct mmc_host_ops omap_hsmmc_ops = {
 	.disable = omap_hsmmc_disable_fclk,
 	.post_req = omap_hsmmc_post_req,
 	.pre_req = omap_hsmmc_pre_req,
+	.abort_req = omap_hsmmc_abort_req,
 	.request = omap_hsmmc_request,
 	.set_ios = omap_hsmmc_set_ios,
 	.get_cd = omap_hsmmc_get_cd,
-- 
1.7.10.rc2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ