Browse Source

V4L/DVB (6495): saa7146: saa7146_wait_for_debi_done fixes

Two fixes for the 'saa7146_wait_for_debi_done' code:
(a) Timeout did not work when the routine was called with
    interrupts disabled.
(b) Reduce PCI I/O load caused by saa7146_wait_for_debi_done.
    Seems to be very important on fast machines!

Based on code posted by Hartmut Birr @vdr-portal.


Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Oliver Endriss 17 years ago
parent
commit
26ac14e24f
1 changed files with 58 additions and 12 deletions
  1. 58 12
      drivers/media/common/saa7146_core.c

+ 58 - 12
drivers/media/common/saa7146_core.c

@@ -59,43 +59,89 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
 }
 
 /* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
-int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
+static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
+				unsigned long us1, unsigned long us2)
 {
-	unsigned long start;
+	unsigned long timeout;
 	int err;
 
 	/* wait for registers to be programmed */
-	start = jiffies;
+	timeout = jiffies + usecs_to_jiffies(us1);
 	while (1) {
-		err = time_after(jiffies, start + HZ/20);
+		err = time_after(jiffies, timeout);
 		if (saa7146_read(dev, MC2) & 2)
 			break;
 		if (err) {
-			DEB_S(("timed out while waiting for registers getting programmed\n"));
+			printk(KERN_ERR "%s: %s timed out while waiting for "
+					"registers getting programmed\n",
+					dev->name, __FUNCTION__);
 			return -ETIMEDOUT;
 		}
-		if (nobusyloop)
-			msleep(1);
+		msleep(1);
 	}
 
 	/* wait for transfer to complete */
-	start = jiffies;
+	timeout = jiffies + usecs_to_jiffies(us2);
 	while (1) {
-		err = time_after(jiffies, start + HZ/4);
+		err = time_after(jiffies, timeout);
 		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
 			break;
 		saa7146_read(dev, MC2);
 		if (err) {
-			DEB_S(("timed out while waiting for transfer completion\n"));
+			DEB_S(("%s: %s timed out while waiting for transfer "
+				"completion\n",	dev->name, __FUNCTION__));
 			return -ETIMEDOUT;
 		}
-		if (nobusyloop)
-			msleep(1);
+		msleep(1);
 	}
 
 	return 0;
 }
 
+static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
+				unsigned long us1, unsigned long us2)
+{
+	unsigned long loops;
+
+	/* wait for registers to be programmed */
+	loops = us1;
+	while (1) {
+		if (saa7146_read(dev, MC2) & 2)
+			break;
+		if (!loops--) {
+			printk(KERN_ERR "%s: %s timed out while waiting for "
+					"registers getting programmed\n",
+					dev->name, __FUNCTION__);
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	/* wait for transfer to complete */
+	loops = us2 / 5;
+	while (1) {
+		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
+			break;
+		saa7146_read(dev, MC2);
+		if (!loops--) {
+			DEB_S(("%s: %s timed out while waiting for transfer "
+				"completion\n", dev->name, __FUNCTION__));
+			return -ETIMEDOUT;
+		}
+		udelay(5);
+	}
+
+	return 0;
+}
+
+int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
+{
+	if (nobusyloop)
+		return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);
+	else
+		return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);
+}
+
 /****************************************************************************
  * general helper functions
  ****************************************************************************/