Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux-dvb] Re: EPG scan cause high load and AC3 drop outs - maybe not solved yet ?



On Thu, Mar 27, 2003 at 08:58:52AM +0100, Christian Jacobsen wrote:
> 
> While using VDR 1.1.26 I Yesterday saw a kdvb-fe process using 29% CPU Time
> again (Pentium3 933).
> 
> I used "top" so it is only snapshots of what really happens. Did not watch
> it that long - but Sometimes it uses less that 1% and sometimes it uses 29%.
> Is there a better tool for watching such things ?
> As far as i remember the exact name of the process was kdvb-fe1:0 (or
> kdvb-fe-1:0)
> IIRC this is the process that switches channels ? Does it do other things to
> ?
> 
> Could it be involved in the "AC3-processing" - so that the high IRQ load
> also causes this high load on kdvb-fe ?
> 
> Is 1:0 somehow related to the card it is running on ?

see driver/dvb_frontend.c at dvb_frontend_thread() ...

[...]
        snprintf (current->comm, sizeof (current->comm), "kdvb-fe-%i:%i",
                  fe->frontend.i2c->adapter->num, fe->frontend.i2c->id);
[...]

... IMHO the first is the card used on the i2c bus (1 == the second), the
second number is the i2c bus its self. What I2C is for see
/usr/src/linux/Documentation/Configure.help , search for CONFIG_I2C, and
/usr/src/linux/Documentation/i2c/summary .

I2C is a slow dog but is used for programming/reading registers of the
DVB cards. IMHO there are also missed some
request_mem_region()/release_mem_region() within av7110/saa7146_core.c 
also a better wait mechanism as mdelay().  Maybe the patch attached
will help to for this.

The thread dvb_frontend_thread() calls dvb_frontend_recover() which is used
for compensating LNB drift.  IMHO this should not happen (nevertheless it
could be the first reason of the high load!!).
Beside this, this is what I've found by searching for lost_sync_count:

/**
 *  if 2 tuners are located side by side you can get interferences when
 *  they try to tune to the same frequency, so both lose sync.
 *  We will slightly mistune in this case. The AFC of the demodulator
 *  should make it still possible to receive the requested transponder 
 *  on both tuners...
 */

... and this could also explain why users of two or more DVB cards (full
featured or not) are `able' to see the phenomena you've described during
EPG scans.

IMHO the ml linux-dvb@linuxtv.org should notice that (therefore a cross
posting is needed IMHO:). For readers of linux-dvb@linuxtv.org: the
drop outs are happen during live view of Pro7 which means that the TS
stream has longer timeouts beginning with some bit failures which are
found by a CRC check of a VDR plugin forwarding the AC3 data stream
to the S/P-DIF of a sound card.


        Werner
--- av7110/av7110.c
+++ av7110/av7110.c	Thu Mar 27 11:15:38 2003
@@ -115,7 +115,7 @@
 
 static inline void ddelay(int i) 
 {
-        current->state=TASK_INTERRUPTIBLE;
+        set_current_state(TASK_INTERRUPTIBLE);
         schedule_timeout((HZ*i)/100);
 }
 
@@ -165,6 +165,8 @@
 	while (1) {
 		if (!(saaread(PSR) & SPCI_DEBI_S))
 			break;
+		if (saaread(SSR) & MASK_22)
+			saawrite(ISR, SPCI_DEBI_E);
 		saaread(MC2);
 		if (jiffies-start > HZ/4) {
 			printk ("%s: timed out while waiting for transfer "
@@ -183,15 +185,18 @@
 	u32 cmd;
 
 	if (count <= 0 || count > 32764)
-		return -1;
+		return -EINVAL;
 	if (wait_for_debi_done(av7110) < 0)
-		return -1;
+		return -ETIMEDOUT;
+
+	saawrite(0x00000000, DEBI_PAGE);
 	saawrite(config, DEBI_CONFIG);
+	saawrite((cmd = (count << 17) | (addr & 0xffff)), DEBI_COMMAND);
 	if (count <= 4)		/* immediate transfer */
 		saawrite(val, DEBI_AD);
 	else			/* block transfer */
 		saawrite(av7110->debi_bus, DEBI_AD);
-	saawrite((cmd = (count << 17) | (addr & 0xffff)), DEBI_COMMAND);
+	/* upload debi-registers */
 	saawrite((2 << 16) | 2, MC2);
 	return 0;
 }
@@ -205,11 +210,13 @@
 		return 0;
 	if (wait_for_debi_done(av7110) < 0)
 		return 0;
-	saawrite(av7110->debi_bus, DEBI_AD);
-	saawrite((count << 17) | 0x10000 | (addr & 0xffff),
-		 DEBI_COMMAND);
 
+	saawrite(0x00000000, DEBI_PAGE);
 	saawrite(config, DEBI_CONFIG);
+	saawrite((count << 17) | 0x10000 | (addr & 0xffff), DEBI_COMMAND);
+	saawrite(av7110->debi_bus, DEBI_AD);
+
+	/* upload debi-registers */
 	saawrite((2 << 16) | 2, MC2);
 	if (count > 4)	
 		return count;
@@ -1282,11 +1289,11 @@
                         len=av7110->bmplen;
                 if (len>2*1024)
                         len=2*1024;
-                iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
-                iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
                 memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);
                 av7110->bmpp+=len;
                 av7110->bmplen-=len;
+                iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
+                iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
                 wait_for_debi_done(av7110);
                 saa7146_write(av7110->saa_mem, IER, 
                               saa7146_read(av7110->saa_mem, IER) | MASK_19 );
--- av7110/saa7146.c
+++ av7110/saa7146.c	Thu Mar 27 11:15:38 2003
@@ -19,9 +19,25 @@
  */
 
 #include "saa7146_defs.h"
+#include "compat.h"
 
 #define TRUNC(val,max) ((val) < (max) ? (val) : (max))
 
+/* helper function */
+extern inline void saa7146_wait(struct saa7146* saa, long ms)
+{
+	long timeout = (ms*HZ)/1000;
+
+	if (timeout) {
+		wait_queue_head_t wait;
+		init_waitqueue_head(&wait);
+		interruptible_sleep_on_timeout(&wait, timeout);
+	} else {
+		cond_resched();
+		mdelay(ms);
+	}
+}
+
 #ifdef __COMPILE_SAA7146__
 
 struct saa7146_modes_constants
@@ -1286,8 +1302,7 @@
 			break;
 
 		/* see if anything can be done while we're waiting */
-		cond_resched ();
-		mdelay(1);
+		saa7146_wait(saa,1);
 	}
 
 	/* we don't check the i-value, since it does not matter
@@ -1311,9 +1326,7 @@
 			break;
 
 		/* see if anything can be done while we're waiting */
-		cond_resched ();
-
-		mdelay(1);
+		saa7146_wait(saa,1);
 	}
 	
 	/* did a timeout occur ? */
@@ -1361,6 +1374,7 @@
 	status = i2c_status_check(saa);
 
 	/* clear data-byte for sure */
+	saa7146_write(saa->mem, I2C_STATUS, SAA7146_I2C_BBR);
     	saa7146_write(saa->mem, I2C_TRANSFER, 0x00);
 	
 	/* check if any operation is still in progress */
@@ -1372,12 +1386,12 @@
 		/* set ABORT-OPERATION-bit */
 		saa7146_write(saa->mem, I2C_STATUS, ( SAA7146_I2C_BBR | MASK_07));
 		saa7146_write(saa->mem, MC2, (MASK_00 | MASK_16));
-		mdelay( SAA7146_I2C_DELAY );
+		saa7146_wait(saa, SAA7146_I2C_DELAY);
 
 		/* clear all error-bits pending; this is needed because p.123, note 1 */
 		saa7146_write(saa->mem, I2C_STATUS, SAA7146_I2C_BBR );
 		saa7146_write(saa->mem, MC2, (MASK_00 | MASK_16));
-		mdelay( SAA7146_I2C_DELAY );
+		saa7146_wait(saa, SAA7146_I2C_DELAY);
  	}
 
 	/* check if any other error is still present */
@@ -1386,14 +1400,23 @@
 		/* yes, try to kick it */
 		hprintk("saa7146: i2c_reset: error_state detected, status:0x%08x\n",status);
 
+		/* Repeat the abort operation. This seems to be necessary
+		   after serious protocol errors caused by e.g. the SAA7740 */
+		saa7146_write(saa, I2C_STATUS, (SAA7146_I2C_BBR | MASK_07));
+		saa7146_write(saa, MC2, (MASK_00 | MASK_16));
+		saa7146_wait(saa, SAA7146_I2C_DELAY);
+
+
 		/* clear all error-bits pending */
 		saa7146_write(saa->mem, I2C_STATUS, SAA7146_I2C_BBR );
 		saa7146_write(saa->mem, MC2, (MASK_00 | MASK_16));
-		mdelay( SAA7146_I2C_DELAY );
+		saa7146_wait(saa, SAA7146_I2C_DELAY);
+
  		/* the data sheet says it might be necessary to clear the status
 		   twice after an abort */
 		saa7146_write(saa->mem, I2C_STATUS, SAA7146_I2C_BBR );
 		saa7146_write(saa->mem, MC2, (MASK_00 | MASK_16));
+		saa7146_wait(saa,SAA7146_I2C_DELAY);
 	}
 
 	/* if any error is still present, a fatal error has occured ... */
--- av7110/saa7146_core.c
+++ av7110/saa7146_core.c	Thu Mar 27 11:15:38 2003
@@ -254,7 +254,8 @@
 		return -ERESTARTSYS;
 
 	do {
-		ret = do_master_xfer (i2c, msgs, num);
+		if ((ret = do_master_xfer (i2c, msgs, num)) != num)
+			cond_resched();
 	} while (ret != num && retries--);
 
 	up (&saa->i2c_sem);
@@ -346,7 +347,7 @@
 			saa7146_write(saa->mem, DD1_INIT, *i);
 
 			/* write out init-values */
-			saa7146_write(saa->mem,MC2, (MASK_09 | MASK_10 | MASK_26 | MASK_26));
+			saa7146_write(saa->mem,MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 
 			break;
 		}
@@ -458,6 +459,7 @@
 {
 	u32 rev = 0;
 	int result = 0;
+	unsigned char latency;
 
 	hprintk("saa7146_core.o: ==> configure_saa7146\n");
 
@@ -490,25 +492,38 @@
 	if( 0 > pci_read_config_dword(saa->device, 0x08, &rev)) {
 		printk (KERN_ERR 
 			"saa7146_core.o: cannot read from pci-device!\n");
-		return -1;
+		return -ENODEV;
 	}
 
 	saa->revision = (rev & 0xf);
 
 	/* remap the memory from virtual to physical adress */
-	saa->mem = ioremap ((saa->device->resource[0].start)
+	if (!request_mem_region(pci_resource_start(saa->device,0),
+				pci_resource_len(saa->device,0),
+				saa->name))
+		return -EBUSY;
+	saa->mem = ioremap (pci_resource_start(saa->device, 0)
 			    &PCI_BASE_ADDRESS_MEM_MASK, 0x1000);
 
 	if ( !saa->mem ) {
 	    	printk(KERN_ERR "saa7146_core.o: cannot map pci-address!\n");
 		return -EFAULT;
 	}
-	
+
+	/* Set PCI latency timer */
+	pci_read_config_byte(saa->device, PCI_LATENCY_TIMER, &latency);
+	if (latency != 64)
+		pci_write_config_byte(saa->device, PCI_LATENCY_TIMER, 64);
+
 	/* get clipping memory */	
 	saa->clipping = (u32*) kmalloc (CLIPPING_MEM_SIZE*sizeof(u32),GFP_KERNEL);
 
 	if ( !saa->clipping ) {
 	    	printk(KERN_ERR "saa7146_core.o: not enough kernel-memory for clipping!\n");
+		if (saa->mem)
+			iounmap((unsigned char *)((unsigned int)saa->mem));
+		release_mem_region(pci_resource_start(saa->device,0),
+				   pci_resource_len(saa->device,0));
 		return -ENOMEM;
 	}
 
@@ -520,6 +535,10 @@
 	if ( !saa->i2c ) {
 	    	printk(KERN_ERR "saa7146_core.o: not enough kernel-memory for i2c!\n");
 		kfree(saa->clipping);
+		if (saa->mem)
+			iounmap((unsigned char *)((unsigned int)saa->mem));
+		release_mem_region(pci_resource_start(saa->device,0),
+				   pci_resource_len(saa->device,0));
 		return -ENOMEM;
 	}
 
@@ -532,6 +551,10 @@
 	    	printk(KERN_ERR "saa7146_core.o: not enough kernel-memory for grabbing_mem!\n");
 		kfree(saa->i2c);
 		kfree(saa->clipping);
+		if (saa->mem)
+			iounmap((unsigned char *)((unsigned int)saa->mem));
+		release_mem_region(pci_resource_start(saa->device,0),
+				   pci_resource_len(saa->device,0));
 		return -ENOMEM;
 	}
 
@@ -543,6 +566,10 @@
 		kfree(saa->i2c);
 		kfree(saa->clipping);
 		rvfree(saa->grabbing, buffers, &saa->page_table[0]);
+		if (saa->mem)
+			iounmap((unsigned char *)((unsigned int)saa->mem));
+		release_mem_region(pci_resource_start(saa->device,0),
+				   pci_resource_len(saa->device,0));
 		return -ENOMEM;
 	}
 
@@ -556,7 +583,11 @@
 		kfree(saa->i2c);
 		kfree(saa->clipping);
 		rvfree(saa->grabbing, buffers, &saa->page_table[0]);
-		return -1;
+		if (saa->mem)
+			iounmap((unsigned char *)((unsigned int)saa->mem));
+		release_mem_region(pci_resource_start(saa->device,0),
+				   pci_resource_len(saa->device,0));
+		return -ENOMEM;
 	}
 
 	memset(saa->rps1, 0x0, RPS_MEM_SIZE*sizeof(u32));
@@ -571,7 +602,11 @@
 		kfree(saa->i2c);
 		kfree(saa->clipping);
 		rvfree(saa->grabbing, buffers, &saa->page_table[0]);
-		return -1;
+		if (saa->mem)
+			iounmap((unsigned char *)((unsigned int)saa->mem));
+		release_mem_region(pci_resource_start(saa->device,0),
+				   pci_resource_len(saa->device,0));
+		return -ENOMEM;
 	}
 
 	memset(saa->debi, 0x0, 8192*sizeof(u32));
@@ -581,7 +616,7 @@
 	memset(&saa->grab_width[0],  0x0, sizeof(int)*SAA7146_MAX_BUF);
 	memset(&saa->grab_height[0], 0x0, sizeof(int)*SAA7146_MAX_BUF);
 	memset(&saa->grab_format[0], 0x0, sizeof(int)*SAA7146_MAX_BUF);
-	memset(&saa->grab_port[0], 0x0, sizeof(int)*SAA7146_MAX_BUF);
+	memset(&saa->grab_port[0],   0x0, sizeof(int)*SAA7146_MAX_BUF);
 
 	/* init the frame-status array */
 	memset(&saa->frame_stat[0], GBUFFER_UNUSED, sizeof(int)*SAA7146_MAX_BUF);
@@ -595,36 +630,40 @@
 	result = request_irq (saa->device->irq, saa7146_irq,
 			      SA_SHIRQ | SA_INTERRUPT, saa->name, (void *) saa);
 
-	switch(result) {
-		case -EINVAL:
-		{
-			printk(KERN_ERR "saa7146_core.o: Bad irq number or handler\n");
-			return -EINVAL;
-		}
-		case -EBUSY:
-		{
-			printk(KERN_ERR "saa7146_core.o: IRQ %d busy, change your PnP config in BIOS\n", saa->device->irq);
-			return -EBUSY;
-		}
-		case 0:
-		{
-			break;
-		}
-		default:
-		{
-			return result;
+	if (result < 0) {
+		kfree(saa->rps1);
+		kfree(saa->rps0);
+		kfree(saa->i2c);
+		kfree(saa->clipping);
+		rvfree(saa->grabbing, buffers, &saa->page_table[0]);
+		if (saa->mem)
+			iounmap((unsigned char *)((unsigned int)saa->mem));
+		release_mem_region(pci_resource_start(saa->device,0),
+				   pci_resource_len(saa->device,0));
+		switch(result) {
+			case -EINVAL:
+				printk(KERN_ERR "saa7146_core.o: Bad irq number or handler\n");
+				break;
+			case -EBUSY:
+				printk(KERN_ERR "saa7146_core.o: IRQ %d busy, change your PnP config in BIOS\n",
+					saa->device->irq);
+				break;
+			default:
+				break;
 		}
+		return result;
 	}
 	
 	/* print status message */
-    	dprintk("saa7146_core.o: %s: bus:%d, rev:%d, mem:0x%08x.\n", saa->name, saa->device->bus->number, saa->revision, (unsigned int) saa->mem);
+    	dprintk("saa7146_core.o: %s: bus:%d, rev:%d, mem:0x%08x.\n",
+		saa->name, saa->device->bus->number, saa->revision, (unsigned int) saa->mem);
 
 	/* enable bus-mastering */
  	pci_set_master( saa->device );
 
 	/* disable everything on the saa7146, perform a software-reset */
 	saa7146_write(saa->mem, MC1, 0xbfff0000);
-	mdelay(2);
+	mdelay(20);
 #if 0
 	{
 		int j;
@@ -638,11 +677,14 @@
 		}
 	}
 #endif 
+	/* i2c-adapter preparations */
+	i2c_reset(saa);
+
 	/* clear out any rps-signals pending */
 	saa7146_write(saa->mem, MC2, 0xf8000000);
 
 	/* enable video-port-pins*/
-	saa7146_write(saa->mem,MC1, (MASK_10 | MASK_26));
+	saa7146_write(saa->mem, MC1, (MASK_10 | MASK_26));
 
 	/* disable all interrupt-conditions, only enable RPS interrupts */
 	saa7146_write(saa->mem, ISR, 0xffffffff);
@@ -720,11 +762,11 @@
 	for (ext_id = 0; ext_id < SAA7146_MAX_EXTENSIONS; ext_id++) {
 		if (NULL == saa7146_ext[ext_id])
 			break;
-		if (SAA7146_MAX_EXTENSIONS == ext_id) {
-			printk(KERN_WARNING "saa7146.o: attach_extension(%s) - "
-			       "enlarge SAA7146_MAX_EXTENSIONS.\n",ext->name);
-			return -ENOMEM;
-		}
+	}
+	if (SAA7146_MAX_EXTENSIONS == ext_id) {
+		printk(KERN_WARNING "saa7146.o: attach_extension(%s) - "
+		       "enlarge SAA7146_MAX_EXTENSIONS.\n",ext->name);
+		return -ENOMEM;
 	}
 
 	saa7146_ext[ext_id] = ext;
@@ -778,6 +820,9 @@
 	/* unmap the memory, if necessary */
 	if (saa->mem)
 		iounmap((unsigned char *)((unsigned int)saa->mem));
+
+	release_mem_region(pci_resource_start(saa->device,0),
+			   pci_resource_len(saa->device,0));
 	
 	dprintk("release grabbing memory\n");
 	/* release grabbing memory */
@@ -844,7 +889,8 @@
 	saa->card_type = card_type;
 	saa->dvb_adapter = adap;
 
-	pci_enable_device (saa->device);
+	if (pci_enable_device (saa->device))
+		return -EIO;
 
 	configure_saa7146 (saa);
 

Home | Main Index | Thread Index