Messages in this thread | | | Date | Tue, 17 Aug 1999 10:25:02 -0600 (MDT) | From | <> | Subject | Problems with interrupts |
| |
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/
| |