help with PCI drivers

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

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;
}


Site Timeline