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               RegMask;
    U32               RegStatus;
    U32               Offset_Mask;
    U32               Offset_StatClear;
    DEVICE_EXTENSION *pdx;


    // Get the device extension
    pdx = (DEVICE_EXTENSION *)dev_id;

    // Set proper reg offset
    if (pdx->bFromLinkSide)
    {
        Offset_Mask      = 0x11000 + 0xa8;   // Link side interrupt registers
        Offset_StatClear = 0x11000 + 0xa4;
    }
    else
    {
        Offset_Mask      = 0x10000 + 0x98;   // Virtual side interrupt registers
        Offset_StatClear = 0x10000 + 0x94;
    }

    // Get interrupt mask
    RegMask =
        PLX_8000_REG_READ(
            pdx,
            Offset_Mask
            );

    // Invert mask to make it an 'enable'
    RegMask = ~RegMask;

    // Get interrupt status
    RegStatus =
        PLX_8000_REG_READ(
            pdx,
            Offset_StatClear
            );

    // Clear unused bits
    RegMask   &= 0xFFFF;
    RegStatus &= 0xFFFF;

    // Determine active interrupts
    RegStatus = RegMask & RegStatus;

    // Return if no interrupt active
    if (RegStatus == 0)
    {
        return FALSE;
    }

    // At this point, the device interrupt is verified

    // Store the doorbell value
    pdx->Source_Doorbell |= RegStatus;

    // Clear active interrupts
    PLX_8000_REG_WRITE(
        pdx,
        Offset_StatClear,
        RegStatus
        );

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