www.pudn.com > PlxSdk.rar > PlxInterrupt.c
/******************************************************************************* * Copyright (c) 2007 PLX Technology, Inc. * * PLX Technology Inc. licenses this software under specific terms and * conditions. Use of any of the software or derviatives thereof in any * product without a PLX Technology chip is strictly prohibited. * * PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY, * EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. PLX makes no guarantee * or representations regarding the use of, or the results of the use of, * the software and documentation in terms of correctness, accuracy, * reliability, currentness, or otherwise; and you rely on the software, * documentation and results solely at your own risk. * * IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS, * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES * OF ANY KIND. IN NO EVENT SHALL PLX'S TOTAL LIABILITY EXCEED THE SUM * PAID TO PLX FOR THE PRODUCT LICENSED HEREUNDER. * ******************************************************************************/ /****************************************************************************** * * File Name: * * PlxInterrupt.c * * Description: * * This file handles interrupts for the PLX device * * Revision History: * * 04-01-07 : PLX SDK v5.00 * ******************************************************************************/ #include#include #include #include #include #include #include // Note: interrupt.h must be last to avoid compiler // errors with some 2.4 kernel headers #include "PlxChipFn.h" #include "PlxInterrupt.h" #include "SupportFunc.h" /****************************************************************************** * * Function : OnInterrupt * * Description: The Interrupt Service Routine for the PLX device * ******************************************************************************/ irqreturn_t OnInterrupt( int irq, void *dev_id #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) , struct pt_regs *regs #endif ) { U32 RegPciInt; U32 InterruptSource; DEVICE_EXTENSION *pdx; // Get the device extension pdx = (DEVICE_EXTENSION *)dev_id; // Read interrupt status register RegPciInt = PLX_9000_REG_READ( pdx, PCI9030_INT_CTRL_STAT ); /**************************************************** * If the chip is in a low power state, then local * register reads are disabled and will always return * 0xFFFFFFFF. If the PLX chip's interrupt is shared * with another PCI device, the PXL ISR may continue * to be called. This case is handled to avoid * erroneous reporting of an active interrupt. ***************************************************/ if (RegPciInt == 0xFFFFFFFF) return PLX_IRQ_RETVAL(IRQ_NONE); // Check for master PCI interrupt enable if ((RegPciInt & (1 << 6)) == 0) return PLX_IRQ_RETVAL(IRQ_NONE); // Verify that an interrupt is truly active // Clear the interrupt type flag InterruptSource = INTR_TYPE_NONE; // Check if Local Interrupt 1 is active and not masked if ((RegPciInt & (1 << 2)) && (RegPciInt & (1 << 0))) { InterruptSource |= INTR_TYPE_LOCAL_1; } // Check if Local Interrupt 2 is active and not masked if ((RegPciInt & (1 << 5)) && (RegPciInt & (1 << 3))) { InterruptSource |= INTR_TYPE_LOCAL_2; } // Software Interrupt if (RegPciInt & (1 << 7)) { InterruptSource |= INTR_TYPE_SOFTWARE; } // Return if no interrupts are active if (InterruptSource == INTR_TYPE_NONE) return PLX_IRQ_RETVAL(IRQ_NONE); // At this point, the device interrupt is verified // Mask the PCI Interrupt PLX_9000_REG_WRITE( pdx, PCI9030_INT_CTRL_STAT, RegPciInt & ~(1 << 6) ); // // Schedule deferred procedure (DPC) to complete interrupt processing // // Provide interrupt source to DPC pdx->Source_Ints = InterruptSource; #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) // Reset task structure pdx->Task_DpcForIsr.sync = 0; // Add task to system immediate queue queue_task( &(pdx->Task_DpcForIsr), &tq_immediate ); // Mark queue for Bottom-half processing mark_bh( IMMEDIATE_BH ); #else // Add task to system work queue schedule_work( &(pdx->Task_DpcForIsr) ); #endif return PLX_IRQ_RETVAL(IRQ_HANDLED); } /****************************************************************************** * * Function : DpcForIsr * * Description: This routine will be triggered by the ISR to service an interrupt * ******************************************************************************/ void DpcForIsr( PLX_DPC_PARAM *pArg1 ) { U32 RegValue; DEVICE_EXTENSION *pdx; PLX_INTERRUPT_DATA IntData; // Get the device extension pdx = container_of( pArg1, DEVICE_EXTENSION, Task_DpcForIsr ); // Get interrupt source IntData.Source_Ints = pdx->Source_Ints; IntData.Source_Doorbell = 0; // Local Interrupt 1 if (IntData.Source_Ints & INTR_TYPE_LOCAL_1) { // Synchronize access to Interrupt Control/Status Register spin_lock( &(pdx->Lock_Isr) ); // Check if this is an edge-triggered interrupt RegValue = PLX_9000_REG_READ( pdx, PCI9030_INT_CTRL_STAT ); if ((RegValue & (1 << 1)) && (RegValue & (1 << 8))) { // Clear edge-triggered interrupt PLX_9000_REG_WRITE( pdx, PCI9030_INT_CTRL_STAT, RegValue | (1 << 10) ); } else { // Mask Local Interrupt 1 PLX_9000_REG_WRITE( pdx, PCI9030_INT_CTRL_STAT, RegValue & ~(1 << 0) ); } spin_unlock( &(pdx->Lock_Isr) ); } // Local Interrupt 2 if (IntData.Source_Ints & INTR_TYPE_LOCAL_2) { // Synchronize access to Interrupt Control/Status Register spin_lock( &(pdx->Lock_Isr) ); // Check if this is an edge-triggered interrupt RegValue = PLX_9000_REG_READ( pdx, PCI9030_INT_CTRL_STAT ); if ((RegValue & (1 << 4)) && (RegValue & (1 << 9))) { // Clear edge-triggered interrupt PLX_9000_REG_WRITE( pdx, PCI9030_INT_CTRL_STAT, RegValue | (1 << 11) ); } else { // Mask Local Interrupt 2 PLX_9000_REG_WRITE( pdx, PCI9030_INT_CTRL_STAT, RegValue & ~(1 << 3) ); } spin_unlock( &(pdx->Lock_Isr) ); } // Software Interrupt if (IntData.Source_Ints & INTR_TYPE_SOFTWARE) { // Synchronize access to Interrupt Control/Status Register spin_lock( &(pdx->Lock_Isr) ); // Clear the software interrupt RegValue = PLX_9000_REG_READ( pdx, PCI9030_INT_CTRL_STAT ); PLX_9000_REG_WRITE( pdx, PCI9030_INT_CTRL_STAT, RegValue & ~(1 << 7) ); spin_unlock( &(pdx->Lock_Isr) ); } // Signal any objects waiting for notification PlxSignalNotifications( pdx, &IntData ); // Re-enable interrupts PlxChipInterruptsEnable( pdx ); }