From: jean-jacques hiblot <jjhiblot@traphandler.com>
To: wsa@the-dreams.de
Cc: gregory.clement@free-electrons.com,
jean-jacques hiblot <jjhiblot@traphandler.com>,
linuxppc-dev@lists.ozlabs.org, linux-i2c@vger.kernel.org,
jean-jacques hiblot <jjhiblot@gmail.com>
Subject: [PATCH v3 REPOST 3/4] i2c: i2c-ibm-iic: Implements transfer abortion
Date: Fri, 20 Dec 2013 16:12:55 +0100 [thread overview]
Message-ID: <1387552376-12986-4-git-send-email-jjhiblot@traphandler.com> (raw)
In-Reply-To: <1387552376-12986-1-git-send-email-jjhiblot@traphandler.com>
From: jean-jacques hiblot <jjhiblot@gmail.com>
Clean-up properly when a transfer fails for whatever reason.
Cancel the transfer when the process is signaled.
Signed-off-by: jean-jacques hiblot <jjhiblot@traphandler.com>
---
drivers/i2c/busses/i2c-ibm_iic.c | 146 ++++++++++-----------------------------
drivers/i2c/busses/i2c-ibm_iic.h | 2 +-
2 files changed, 36 insertions(+), 112 deletions(-)
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index a92e8f6..857259e 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -336,120 +336,25 @@ static irqreturn_t iic_handler(int irq, void *dev_id)
}
/*
- * Get master transfer result and clear errors if any.
- * Returns the number of actually transferred bytes or error (<0)
- */
-static int iic_xfer_result(struct ibm_iic_private* dev)
-{
- struct iic_regs __iomem *iic = dev->vaddr;
-
- if (unlikely(in_8(&iic->sts) & STS_ERR)){
- DBG(dev, "xfer error, EXTSTS = 0x%02x\n",
- in_8(&iic->extsts));
-
- /* Clear errors and possible pending IRQs */
- out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD |
- EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA);
-
- /* Flush master data buffer */
- out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
-
- /*
- * Is bus free?
- * If error happened during combined xfer
- * IIC interface is usually stuck in some strange
- * state, the only way out - soft reset.
- */
- if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
- DBG(dev, "bus is stuck, resetting\n");
- iic_dev_reset(dev);
- }
- return -EREMOTEIO;
- }
- else
- return in_8(&iic->xfrcnt) & XFRCNT_MTC_MASK;
-}
-
-/*
* Try to abort active transfer.
*/
-static void iic_abort_xfer(struct ibm_iic_private* dev)
+static void iic_abort_xfer(struct ibm_iic_private *dev)
{
- struct iic_regs __iomem *iic = dev->vaddr;
- unsigned long x;
-
- DBG(dev, "iic_abort_xfer\n");
+ struct device *device = dev->adap.dev.parent;
+ unsigned long end;
- out_8(&iic->cntl, CNTL_HMT);
+ DBG(dev, "aborting transfer\n");
+ /* transfer should be aborted within 10ms */
+ end = jiffies + 10;
+ dev->abort = 1;
- /*
- * Wait for the abort command to complete.
- * It's not worth to be optimized, just poll (timeout >= 1 tick)
- */
- x = jiffies + 2;
- while ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
- if (time_after(jiffies, x)){
- DBG(dev, "abort timeout, resetting...\n");
- iic_dev_reset(dev);
- return;
- }
+ while (time_after(end, jiffies) && !dev->transfer_complete)
schedule();
- }
- /* Just to clear errors */
- iic_xfer_result(dev);
-}
-
-/*
- * Wait for master transfer to complete.
- * It puts current process to sleep until we get interrupt or timeout expires.
- * Returns the number of transferred bytes or error (<0)
- */
-static int iic_wait_for_tc(struct ibm_iic_private* dev){
-
- struct iic_regs __iomem *iic = dev->vaddr;
- int ret = 0;
-
- if (dev->irq >= 0){
- /* Interrupt mode */
- ret = wait_event_interruptible_timeout(dev->wq,
- !(in_8(&iic->sts) & STS_PT), dev->adap.timeout);
-
- if (unlikely(ret < 0))
- DBG(dev, "wait interrupted\n");
- else if (unlikely(in_8(&iic->sts) & STS_PT)){
- DBG(dev, "wait timeout\n");
- ret = -ETIMEDOUT;
- }
- }
- else {
- /* Polling mode */
- unsigned long x = jiffies + dev->adap.timeout;
-
- while (in_8(&iic->sts) & STS_PT){
- if (unlikely(time_after(jiffies, x))){
- DBG(dev, "poll timeout\n");
- ret = -ETIMEDOUT;
- break;
- }
-
- if (unlikely(signal_pending(current))){
- DBG(dev, "poll interrupted\n");
- ret = -ERESTARTSYS;
- break;
- }
- schedule();
- }
+ if (!dev->transfer_complete) {
+ dev_err(device, "abort operation failed\n");
+ iic_dev_reset(dev);
}
-
- if (unlikely(ret < 0))
- iic_abort_xfer(dev);
- else
- ret = iic_xfer_result(dev);
-
- DBG2(dev, "iic_wait_for_tc -> %d\n", ret);
-
- return ret;
}
/*
@@ -473,6 +378,13 @@ static int iic_xfer_bytes(struct ibm_iic_private *dev)
EXTSTS_ICT | EXTSTS_XFRA);
out_8(&iic->sts, STS_IRQA | STS_SCMP);
+ if (dev->status == -ECANCELED) {
+ DBG(dev, "abort completed\n");
+ dev->transfer_complete = 1;
+ complete(&dev->iic_compl);
+ return dev->status;
+ }
+
if ((status & STS_ERR) ||
(ext_status & (EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA))) {
DBG(dev, "status 0x%x\n", status);
@@ -577,7 +489,14 @@ static int iic_xfer_bytes(struct ibm_iic_private *dev)
/* actually start the transfer of the current data chunk */
out_8(&iic->cntl, cntl | CNTL_PT);
- return 0;
+ /* The transfer must be aborted. */
+ if (dev->abort) {
+ DBG(dev, "aborting\n");
+ out_8(&iic->cntl, CNTL_HMT);
+ dev->status = -ECANCELED;
+ }
+
+ return dev->status;
}
/*
@@ -682,6 +601,7 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
dev->current_byte = dev->current_msg = dev->current_byte_rx = 0;
dev->transfer_complete = 0;
dev->status = 0;
+ dev->abort = 0;
dev->msgs = msgs;
dev->num_msgs = num;
@@ -719,8 +639,10 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
/* wait for the transfer to complete */
ret = wait_for_completion_interruptible_timeout(
&dev->iic_compl, num * HZ);
- /* mask the interrupts */
- out_8(&iic->intmsk, 0);
+ /*
+ * we don't mask the interrupts here because we may
+ * need them to abort the transfer gracefully
+ */
}
if (ret == 0) {
@@ -729,11 +651,15 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
} else if (ret < 0) {
if (ret == -ERESTARTSYS)
ERR(dev, "transfer interrupted\n");
+ iic_abort_xfer(dev);
} else {
/* Transfer is complete */
ret = (dev->status) ? dev->status : num;
}
+ /* mask the interrupts */
+ out_8(&iic->intmsk, 0);
+
return ret;
}
@@ -832,8 +758,6 @@ static int iic_probe(struct platform_device *ofdev)
goto error_cleanup;
}
- init_waitqueue_head(&dev->wq);
-
dev->irq = iic_request_irq(ofdev, dev);
if (!dev->irq)
dev_info(&ofdev->dev, "using polling mode\n");
diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
index 76c476a..0ee28a9 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.h
+++ b/drivers/i2c/busses/i2c-ibm_iic.h
@@ -47,7 +47,6 @@ struct iic_regs {
struct ibm_iic_private {
struct i2c_adapter adap;
struct iic_regs __iomem *vaddr;
- wait_queue_head_t wq;
int irq;
int fast_mode;
u8 clckdiv;
@@ -58,6 +57,7 @@ struct ibm_iic_private {
int current_byte_rx;
int transfer_complete;
int status;
+ int abort;
struct completion iic_compl;
};
--
1.8.4.2
next prev parent reply other threads:[~2013-12-20 15:16 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-20 15:12 [PATCH v3 REPOST 0/4] i2c : i2c-ibm-iic : use interrupts to perform the data transfer jean-jacques hiblot
2013-12-20 15:12 ` [PATCH v3 REPOST 1/4] i2c: i2c-ibm-iic: cleanup jean-jacques hiblot
2013-12-20 15:12 ` [PATCH v3 REPOST 2/4] i2c: i2c-ibm-iic: perform the transfer in the interrupt handler jean-jacques hiblot
2014-01-03 15:04 ` Wolfram Sang
2014-01-03 15:57 ` Jean-Jacques Hiblot
2013-12-20 15:12 ` jean-jacques hiblot [this message]
2014-01-03 15:09 ` [PATCH v3 REPOST 3/4] i2c: i2c-ibm-iic: Implements transfer abortion Wolfram Sang
2014-01-03 16:14 ` Jean-Jacques Hiblot
2013-12-20 15:12 ` [PATCH v3 REPOST 4/4] i2c: i2c-ibm-iic: Implements a polling mode jean-jacques hiblot
2014-01-03 15:13 ` Wolfram Sang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1387552376-12986-4-git-send-email-jjhiblot@traphandler.com \
--to=jjhiblot@traphandler.com \
--cc=gregory.clement@free-electrons.com \
--cc=jjhiblot@gmail.com \
--cc=linux-i2c@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=wsa@the-dreams.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).