Hello all,

I have a linux driver for a 4-input DVB card. I have two other ASI
cards that transmit data and the 4 receivers of DVB card receive the
data. When I make the driver, it installs fine. dmesg shows everything
alright. The test applications run perfectly okay too. After that, I
tried testing the driver. So, I stopped and started the transmitters
and receivers several times. After certain attempts (no pattern really)



to stop and start, the machine completely freezes. I have to manually
power the machine down. But, when I use only one ASI card (one
transmitter and two receivers on the DVB card), it all works fine. I
am running Fedora Core 4.


Can anyone help me debug the code? Or else, at least, shed some light
on the debugging side of it. Any help is appreciated. I can post the
driver code as well if anyone would like to see it. I am guessing its
the interrupts that are not being released properly.

Thanks,

DB

Code for Interrupt handling----

static irqreturn_t
dvbm_qlf_irq_handler (int irq,
void *dev_id,
struct pt_regs *regs)
{
int i;
struct master_dev *card = dev_id;
struct list_head *p = &card->iface_list;
struct master_iface *iface;
unsigned int dmaintsrc = readl (card->bridge_addr + LSDMA_INTSRC);
unsigned int status, interrupting_iface = 0;

for (i = 0; i < 4; i++) {
p = p->next;

iface = list_entry (p, struct master_iface, list);


/* Check and Clear ASI interrupts */
spin_lock (&card->irq_lock);
status = readl (card->core_addr + DVBM_QLF_ICSR(i));

if ((status & DVBM_QLF_ICSR_ISMASK) != 0) {
writel (status, card->core_addr + DVBM_QLF_ICSR(i));

if (status & DVBM_QLF_ICSR_RXCDIS) {
set_bit (ASI_EVENT_RX_CARRIER_ORDER, &iface->events);
interrupting_iface |= (0x1 << i);
}
if (status & DVBM_QLF_ICSR_RXAOSIS) {
set_bit (ASI_EVENT_RX_AOS_ORDER, &iface->events);
interrupting_iface |= (0x1 << i);
}
if (status & DVBM_QLF_ICSR_RXLOSIS) {
set_bit (ASI_EVENT_RX_LOS_ORDER, &iface->events);
interrupting_iface |= (0x1 << i);
}
if (status & DVBM_QLF_ICSR_RXOIS) {
set_bit (ASI_EVENT_RX_FIFO_ORDER, &iface->events);
interrupting_iface |= (0x1 << i);
}
if (status & DVBM_QLF_ICSR_RXDIS) {
set_bit (ASI_EVENT_RX_DATA_ORDER, &iface->events);
interrupting_iface |= (0x1 << i);
}
}

spin_unlock (&card->irq_lock);

/* Check and Clear DMA interrupts */
if (dmaintsrc & LSDMA_INTSRC_CH(i)) {

/* Read the interrupt type and clear it */
spin_lock (&card->irq_lock);
status = readl (card->bridge_addr + LSDMA_CSR(i));
writel (status, card->bridge_addr + LSDMA_CSR(i));
spin_unlock (&card->irq_lock);

/* Increment the buffer pointer */
if (status & LSDMA_CH_CSR_INTSRCBUFFER) {
lsdma_advance (iface->dma);
if (lsdma_rx_isempty (iface->dma)) {
set_bit (ASI_EVENT_RX_BUFFER_ORDER, &iface->events);
}
}

/* Flag end-of-chain */
if (status & LSDMA_CH_CSR_INTSRCDONE) {
set_bit (0, &iface->dma_done);
}

/* Flag DMA abort */
if (status & LSDMA_CH_CSR_INTSRCSTOP) {
set_bit (0, &iface->dma_done);
}

interrupting_iface |= (0x1 << i);
}


if (interrupting_iface & (0x1 << i)) {
wake_up (&iface->queue);
}
}

if (interrupting_iface) {
/* Dummy read to flush PCI posted writes */
readl (card->bridge_addr + LSDMA_INTMSK);
return IRQ_HANDLED;
}
return IRQ_NONE;
}