Re: Problems with Hauppauge HVR 1600 and cx18 driver

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

 



On Sun, 29 Mar 2009, Andy Walls wrote:
> On Sun, 2009-03-29 at 01:24 -0700, Trent Piepho wrote:
> > wait_event() should take care of this.  wait_event(q, test) basically does:
> >
> > for(;;) {
> > 	// point A
> > 	add_me_to_waitqueue(q);
> > 	set_current_state(TASK_UNINTERRUPTIBLE);
> > 	if (test)
> > 		break;
> > 	// point B
> > 	schedule();
> > }
> > clean_up_wait_stuff();
>
> As you know, the condition is checked even before this loop is entered,
> to avoid even being even added to a waitqueue.  (Thank God for ctags...)

I think the initial check of the condition is just an optimization and
everything will still work without it.  Seeing as all this is inlined, I
wonder if it's a good optimization...

> As you may have noticed, the original code was using
> wait_event_timeout() before like this:
>
>         CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n",
>                           irq, info->name);
>         cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
>
>         ret = wait_event_timeout(
>                        *waitq,
>                        cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request),
>                        timeout);
>
> Because waiting for the ack back is the right thing to do, but certainly
> waiting too long is not warranted.
>
> This gave me the occasional log message like this:
>
> 1: cx18-0:  irq: sending interrupt SW1: 8 to send CX18_CPU_DE_SET_MDL
> 2: cx18-0:  irq: received interrupts SW1: 0  SW2: 8  HW2: 0
> 3: cx18-0:  irq: received interrupts SW1: 10000  SW2: 0  HW2: 0
> 4: cx18-0:  warning: sending CX18_CPU_DE_SET_MDL timed out waiting 10 msecs for RPU acknowledgement
>
> Where line 1 is the driver notifiying the firmware with a SW1 interrupt.
> Line 2 is the firmware responding back to the cx18_irq_handler() with
> the Ack interrupt in SW2 (the flags match, 8 & 8, by design).
> Line 3 is an unrelated incoming video buffer notification for the cx18
> driver.
> Line 4 is the wait_event_timeout() timing out.

Could it be that the wait_event doesn't actually run and check its
condition until _after_ line 3?  In that case SW2 != 8 and so it goes back
to sleep?  Calling wake_up() just makes the processes on the waitq
runnable, they don't actually run until later, possibly much later.

> > If your event occurs and wake_up() is called at point A, then the test
> > should be true when it's checked and schedule() is never called.  If the
> > event happens at point B, then the process' state will have been changed to
> > TASK_RUNNING by wake_up(), remember it's already on the waitqueue at this
> > point, and schedule() won't sleep.
>
> OK, for some reason, I thought schedule() and schedule_timeout() would
> go to sleep anyway.

AFAIK, they'll still cause the kernel schedule a process.  Maybe a
different process.  But the original process is still in TASK_RUNNING state
and so still in the run queue and will get run again.  If it was in
TASK_(UN)INTERRUPTIBLE state then it wouldn't be in the run queue and
wouldn't run again until something woke it up.

> > I think what's probably happening is the test, cx18_readl(cx, &mb->ack) ==
> > cx18_readl(cx, &mb->request), is somehow not true even though the ack has
> > been received.
>
> A PCI bus read error could be the culprit here.  That's the only thing I
> can think of.  We only get one notification via IRQ from the firmware.
>
>
> >   Maybe a new request was added?
>
> No, I lock the respective epu2apu or epu2cpu mailboxes respectively with
> a mutex.

But in your log:
> 1: cx18-0:  irq: sending interrupt SW1: 8 to send CX18_CPU_DE_SET_MDL
> 2: cx18-0:  irq: received interrupts SW1: 0  SW2: 8  HW2: 0
> 3: cx18-0:  irq: received interrupts SW1: 10000  SW2: 0  HW2: 0
> 4: cx18-0:  warning: sending CX18_CPU_DE_SET_MDL timed out waiting 10 msecs for RPU acknowledgement

Isn't the wait_event_timeout() waiting until line 4?  And doesn't line 3
mean something has changed the registers?  Changed them before the
wait_event finished?

> > I think calling wait_event()'s with something that tests a hardware
> > register is a little iffy.  It's better if the irq handler sets some driver
> > state flag (atomically!) that indicates the event you were waiting for has
> > happened and then you check that flag.
>
> I was toying with setting an atomic while in the IRQ handler.  But then
> I realized when we get the ack interrupt, the firmware should actually
> be done. So really the wakeup() is the only indicator I really need.
> Checking for ack == req is just a formality I guess.

If you use an interruptible timeout, then you could get interrupted with a
signal before the irq handler has woken you.

> There wasn't a wait_timeout(), so I had tried something like this in my
> first iteration:

It's called sleep_on_timeout(q, timeout).
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux