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 "DriverDefs.h" #include "PciSupport.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 TmpValue; U32 RegEnable_DB; U32 RegEnable_MSG; U32 RegStatus; BOOLEAN bInterrupt; DEVICE_EXTENSION *pdx; // Get the device extension pdx = (DEVICE_EXTENSION *)dev_id; // Assume no interrupt bInterrupt = FALSE; // Get interrupt enable PLX_PCI_REG_READ( pdx, 0xc4, &RegEnable_DB ); PLX_PCI_REG_READ( pdx, 0xc8, &RegEnable_MSG ); // Get interrupt status PLX_PCI_REG_READ( pdx, 0xcc, &RegStatus ); // Check for doorbell interrupt TmpValue = (RegEnable_DB & 0xFFFF) & (RegStatus & 0xFFFF); if (TmpValue) { // Ignore active doorbell interrupt if still pending if ((RegEnable_DB >> 16) & TmpValue) { // Doorbell interrupt still pending, ignore it } else { // Clear active doorbell interrupts PLX_PCI_REG_WRITE( pdx, 0xcc, (RegStatus & 0xFF000000) | TmpValue ); // Flag doorbell interrupt active pdx->Source_Doorbell |= TmpValue; // Flag interrupt found bInterrupt = TRUE; } } // Check for message, S_RSTIN, S_PME, & GPIO interrupts TmpValue = (RegEnable_MSG >> 24) & ((RegStatus >> 16) & 0xFF); if (TmpValue & 0xFF) { if (TmpValue & 0xF) { // Flag message interrupt active pdx->Source_Ints |= INTR_TYPE_MESSAGE; } if (TmpValue & (1 << 4)) { // Flag S_RSTIN de-assertion detected pdx->Source_Ints |= INTR_TYPE_S_RSTIN; } if (TmpValue & (1 << 5)) { // Flag S_PME de-assertion detected pdx->Source_Ints |= INTR_TYPE_S_PME; } // GPIO14 interrupt if (TmpValue & (1 << 6)) { // Interrupt active, must disable/mask since can't clear source RegEnable_MSG &= ~((1 << 6) << 24); PLX_PCI_REG_WRITE( pdx, 0xc8, (RegEnable_MSG & 0xFF000000) ); // Flag GPIO14 interrupt active pdx->Source_Ints |= INTR_TYPE_GPIO14; } // GPIO4 interrupt if (TmpValue & (1 << 7)) { // Interrupt active, must disable/mask since can't clear source RegEnable_MSG &= ~((1 << 7) << 24); PLX_PCI_REG_WRITE( pdx, 0xc8, (RegEnable_MSG & 0xFF000000) ); // Flag GPIO4 interrupt active pdx->Source_Ints |= INTR_TYPE_GPIO4; } // Clear active interrupts PLX_PCI_REG_WRITE( pdx, 0xcc, (RegStatus & 0x00FF0000) | (TmpValue << 16) ); // Flag interrupt found bInterrupt = TRUE; } // Return if no interrupt active if (bInterrupt == FALSE) return PLX_IRQ_RETVAL(IRQ_NONE); // // Schedule deferred procedure (DPC) to complete interrupt processing // #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 ) { DEVICE_EXTENSION *pdx; PLX_INTERRUPT_DATA IntData; // Get the device extension pdx = container_of( pArg1, DEVICE_EXTENSION, Task_DpcForIsr ); // Setup for synchonized access to interrupt source IntData.pdx = pdx; // Get current pending interrupt sources PlxSynchronizedGetInterruptSource( &IntData ); // Signal any objects waiting for notification PlxSignalNotifications( pdx, &IntData ); }