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

Re: ehci_hcd map_single: unable to map unsafe buffer on a standard NSLU2



Thierry Merle a écrit :
> Lennart Sorensen a écrit :
>> On Tue, Sep 11, 2007 at 04:53:41AM -0700, Thierry Merle wrote:
>>  
>>> I am using a Terratec Cinergy T2 USB tuner on my 266MHz NSLU2.
>>> When I am recording a DVB-T stream, it takes around 33% CPU (zapdvb
>>> process,
>>> the tool I use to record) but surprisingly, my NSLU2 is much less
>>> responsive
>>> for other tasks (big latencies for ssh, fetchmail, imap and other
>>> things
>>> that run on my box).
>>> Nevertheless, the recorded file contains the entire stream (video is
>>> fluid).
>>> Do you think this is a CPU related problem?
>>>     
>>
>> Isn't DVB-T mpeg?  That would be a lot less work than a raw captured tv
>> signal (the driver in question mentioned needing 170MBit per second on
>> the USB port per tuner, which sounds like an awful lot more data than an
>> mpeg stream would generate).  That would need much more bandwidth from
>> the cpu, and if the cpu now has to compress the video it would take
>> quite a lot of cpu.  Even the disk access to write 170MBit/s starts to
>> add up, especially since the disk is almost certainly on another USB
>> port.  I am assuming your tuner has hardware encoding to mpeg or that it
>> is receiving an existing mpeg stream from some other DVB device.
>>
>> So yes I could see it being simply a CPU issue.
>>
>> -- 
>> Len Sorensen
>>
>>
>>   
> Right, DVB-T mpeg-2 TS for both cinergyT2 and em28xx based tuners.
> To inform you the current state of the investigation:
> - I wired a serial-to-usb cable to get the serial console (I used a
> DKU-5 data cable containing a ark3116 chip, works perfectly for this
> usage, and very cheap).
> - by lowering the number of URB allocated in em28xx, I succeeded in
> going further... to another bug :)
> I have now the following error on console, so frequently that the NSLU2
> cannot respond to any sollicitation (need to hard-shutdown it) :
> BUG: warning at arch/arm/mm/consistent.c:363/dma_free_coherent()
> BUG: warning at arch/arm/mm/consistent.c:363/dma_free_coherent()
> BUG: warning at arch/arm/mm/consistent.c:363/dma_free_coherent()
> [...]
> This warning is caused by: WARN_ON(irqs_disabled()); in
> dma_free_coherent.
> The function comment says:  * Must not be called with IRQs disabled.
> I suggested that a dma_free_coherent has been indirectly called in a
> critical section...
> So we need to analyze that with the em28xx maintainer that does his best
> to help me with the poor information I can give to him.
>
> Thierry
>
>
>
Hello,
I proposed a patch on the linux-arm ML (you will find at the end of this
message) to correct the dma_free_coherent calls when IRQ are disabled.
This allows the tuner to tune frequencies without kernel freezes, but
the streaming is corrupted, I need to investigate on this now.
This patches the kernel, the dmabounce part; this corrects a very rare
bug I think, so nobody commented it yet.
Do someone encountered a kernel freeze on the NSLU2 using a USB device?

Cheers,
Thierry

--- linux-source-2.6.22.orig/arch/arm/common/dmabounce.c	2007-10-12 21:51:54.000000000 +0200
+++ linux-source-2.6.22/arch/arm/common/dmabounce.c	2007-10-10 19:16:36.000000000 +0200
@@ -29,7 +29,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/list.h>
-
+#include <linux/interrupt.h>
 #include <asm/cacheflush.h>
 
 #undef STATS
@@ -51,6 +51,7 @@ struct safe_buffer {
 	int		direction;
 
 	/* safe buffer info */
+	struct device *dev;
 	struct dmabounce_pool *pool;
 	void		*safe;
 	dma_addr_t	safe_dma_addr;
@@ -125,6 +126,7 @@ alloc_safe_buffer(struct dmabounce_devic
 		return NULL;
 	}
 
+	buf->dev = device_info->dev;
 	buf->ptr = ptr;
 	buf->size = size;
 	buf->direction = dir;
@@ -180,6 +182,39 @@ find_safe_buffer(struct dmabounce_device
 	return rb;
 }
 
+/* The free safe buffer part. dma_free_coherent cannot be called irq disabled.
+   To cope with that, a tasklet (do_free) does the job upon request */
+static DEFINE_SPINLOCK(buflock);
+static LIST_HEAD(buffers);
+
+static void do_free(unsigned long ignored)
+{
+       spin_lock_irq(&buflock);
+       while (!list_empty(&buffers)) {
+               struct safe_buffer *buf;
+
+               buf = list_entry(buffers.next,
+				struct safe_buffer,
+				node);
+               list_del(&buf->node);
+               spin_unlock_irq(&buflock);
+
+	       if (buf->pool)
+		 dma_pool_free(buf->pool->pool, buf->safe, buf->safe_dma_addr);
+	       else
+		 dma_free_coherent(buf->dev, buf->size, buf->safe,
+				   buf->safe_dma_addr);
+
+	       kfree(buf);
+
+               spin_lock_irq(&buflock);
+
+       }
+       spin_unlock_irq(&buflock);
+}
+
+static DECLARE_TASKLET(deferred_free, do_free, 0);
+
 static inline void
 free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer *buf)
 {
@@ -193,13 +228,12 @@ free_safe_buffer(struct dmabounce_device
 
 	write_unlock_irqrestore(&device_info->lock, flags);
 
-	if (buf->pool)
-		dma_pool_free(buf->pool->pool, buf->safe, buf->safe_dma_addr);
-	else
-		dma_free_coherent(device_info->dev, buf->size, buf->safe,
-				    buf->safe_dma_addr);
+	/* pass the safe buffer to the tasklet */
+	spin_lock_irqsave(&buflock, flags);
+	list_add_tail(&buf->node, &buffers);
+	tasklet_schedule(&deferred_free);
+	spin_unlock_irqrestore(&buflock, flags);
 
-	kfree(buf);
 }
 
 /* ************************************************** */



Reply to: