Problems with interrupts

Jeff Garzik (dave@clean.lanl.gov)
Tue, 17 Aug 1999 10:25:02 -0600 (MDT)


Please help,

This question has two parts:

1)

I have a board that uses the AMCC 5933 interface chip, and I am writing
a driver to use the chip to perform DMA transfers. I am using kernel 2.2.5

After working with the board for a while, I have discovered that if
another process gets the bus during a DMA transfer, then the transfer
drops a value in the stream.

Initially, I have solved this problem by issuing cli() and putting a
for-next loop in to wait for the DMA to be done, then issuing a sti(). Of
course we all know how pointless this approach is, since the AMCC chip can
generate an interrupt when the transfer is done.

The problem is that I need to disable all interrupts except the one that
the AMCC chip is generating. I have tried: disable_irq(x) where x is all
the irqs listed in /proc/interrupts (except irq 2), but something still
interrupts the DMA transfer.

I assume software interrupts are still active, could this be my problem?
How do I disable software interrupts and all interrupts except the one
that I am waiting for?

2)

Another solution to the problem is to limit the transfers to 240 values,
then the AMCC chip is pretty sure the have control over the bus during the
timeout latency of the PCI bus (set to 248). This is not optimal, but
workable until I can find a solution to the above problem.

When I implement this solution, transfers are fine for a while, then the
system hangs hard for no appearent reason. Anyone see why the following
code would hang the kernel intermittently? Am I missing something stupid?

Thanks for your help.

Dave Rector
*:^)

----------------------------------------------------------------------
void amcc_dmatask( unsigned long start_addr, unsigned long len )
{
unsigned long *varptr;
unsigned long val, i;

// sti();
/* reset AMCC bus master registers MFR APFR PAFR
and reset pcitarget chip AR */
outl( MCSR_MFR|MCSR_APFR|MCSR_PAFR|MCSR_AR,
m87pciConfig.virtualAddr[0]+AMCC_MCSR );
outl( 0, m87pciConfig.virtualAddr[0]+AMCC_MCSR );

/* store dma destination address */
outl( m87pciConfig.dmaBusAddress+start_addr,
m87pciConfig.virtualAddr[0]+AMCC_MWAR );

/* setup amcc bus master interrupt mode: 0x4000 */
outl( 0x4000, m87pciConfig.virtualAddr[0]+AMCC_INTCSR );

/* set transfer length to zero at this point */
outl( len, m87pciConfig.virtualAddr[0]+AMCC_MWTC );

/* enable write transfer WTE, set fifo mode to
"full before transfer" FMS and
enable write before read priority WRP */
/* without the FMS and WRP option, an initial zero value
was being written to the stream */
outl(MCSR_WTE | MCSR_FMS | MCSR_WRP,m87pciConfig.virtualAddr[0]+AMCC_MCSR);

/* Initiate transfers by writing a value to "var",
var address is the start address */
varptr = (unsigned long *)m87pciConfig.virtualAddr[4];
varptr[start_addr/4] = 0;

// for( val=0; val<0x20000*10; val++ )
// i++;

/* go to sleep until interrupt */
interruptible_sleep_on_timeout( &amcc_wait_queue, 20 );

/* clear all amcc interrupts */
outl( 0x003F0000, m87pciConfig.virtualAddr[0]+AMCC_INTCSR );
/* reset AMCC chip and pci target again */
outl( MCSR_MFR|MCSR_APFR|MCSR_PAFR|MCSR_AR,
m87pciConfig.virtualAddr[0]+AMCC_MCSR );
outl( 0, m87pciConfig.virtualAddr[0]+AMCC_MCSR );

// cli();

return;

}

static void amcc_interrupt(int irq, void *dev_id,
struct pt_regs * regs)
{
unsigned long intstat;

intstat = inl( m87pciConfig.virtualAddr[0]+AMCC_INTCSR );
printk( "amcc interrupt caused by: %08lX\n", intstat );
/* clear all amcc interrupts */
outl( 0x003F0000, m87pciConfig.virtualAddr[0]+AMCC_INTCSR );
/* reset AMCC chip and pci target again */
outl( MCSR_MFR|MCSR_APFR|MCSR_PAFR|MCSR_AR,
m87pciConfig.virtualAddr[0]+AMCC_MCSR );
outl( 0, m87pciConfig.virtualAddr[0]+AMCC_MCSR );
wake_up_interruptible( &amcc_wait_queue );
return;
}

---------------------------------------------------------------

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/