⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isrdpc.c

📁 基于xilinx vierex5得pci express dma设计实现。
💻 C
字号:
/*++

Copyright (c) Microsoft Corporation.  All rights reserved.

    THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
    PURPOSE.

Module Name:

    IsrDpc.c

Abstract:

    Contains routines related to interrupt and dpc handling.

Environment:

    Kernel mode

--*/

#include "precomp.h"

#include "IsrDpc.tmh"


void PCIEWait(int ms);

NTSTATUS
PCIEInterruptCreate(
    IN PDEVICE_EXTENSION DevExt
    )
/*++
Routine Description:

    Configure and create the WDFINTERRUPT object.
    This routine is called by EvtDeviceAdd callback.

Arguments:

    DevExt      Pointer to our DEVICE_EXTENSION

Return Value:

    NTSTATUS code

--*/
{
    NTSTATUS                    status;
    WDF_INTERRUPT_CONFIG        InterruptConfig;

    WDF_INTERRUPT_CONFIG_INIT( &InterruptConfig,
                               PCIEEvtInterruptIsr,
                               PCIEEvtInterruptDpc );

    InterruptConfig.EvtInterruptEnable  = PCIEEvtInterruptEnable;
    InterruptConfig.EvtInterruptDisable = PCIEEvtInterruptDisable;

    // JOHNR: Enable testing of the DpcForIsr Synchronization
    InterruptConfig.AutomaticSerialization = TRUE;

    //
    // Unlike WDM, framework driver should create interrupt object in EvtDeviceAdd and
    // let the framework do the resource parsing and registration of ISR with the kernel.
    // Framework connects the interrupt after invoking the EvtDeviceD0Entry callback
    // and disconnect before invoking EvtDeviceD0Exit. EvtInterruptEnable is called after
    // the interrupt interrupt is connected and EvtInterruptDisable before the interrupt is
    // disconnected.
    //
    status = WdfInterruptCreate( DevExt->Device,
                                 &InterruptConfig,
                                 WDF_NO_OBJECT_ATTRIBUTES,
                                 &DevExt->Interrupt );

    if( !NT_SUCCESS(status) )
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    "WdfInterruptCreate failed: %!STATUS!", status);

        KdPrint(("PCIEInterruptCreate: Failed: %x", status));
    }
    KdPrint(("PCIEInterruptCreate: OK"));

    return status;
}

BOOLEAN
PCIEEvtInterruptIsr(
    IN WDFINTERRUPT Interrupt,
    IN ULONG        MessageID
    )
/*++
Routine Description:

    Interrupt handler for this driver. Called at DIRQL level when the
    device or another device sharing the same interrupt line asserts
    the interrupt. The driver first checks the device to make sure whether
    this interrupt is generated by its device and if so clear the interrupt
    register to disable further generation of interrupts and queue a
    DPC to do other I/O work related to interrupt - such as reading
    the device memory, starting a DMA transaction, coping it to
    the request buffer and completing the request, etc.

Arguments:

    Interupt   - Handle to WDFINTERRUPT Object for this device.
    MessageID  - MSI message ID (always 0 in this configuration)

Return Value:

     TRUE   --  This device generated the interrupt.
     FALSE  --  This device did not generated this interrupt.

--*/
{
    PDEVICE_EXTENSION   devExt;
    BOOLEAN             isRecognized = FALSE;
    __int64             i64End;

    union {
        DMA_INT     bits;
        ULONG       ulong;
    } DMAINT;

    UNREFERENCED_PARAMETER(MessageID);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
                "--> PCIEInterruptHandler");


    // Our ISR Routine will be called event if the test card hasn't trigger any interrupt signal.
    // So we comment the debug log here.
    //    KdPrint(("PCIEEvtInterruptIsr: Begin"));

    devExt  = PCIEGetDeviceContext(WdfInterruptGetDevice(Interrupt));


    //
    // Read the Interrupt CSR register (INTCSR)
    //
    DMAINT.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->INT);


    isRecognized = (BOOLEAN)DMAINT.bits.INT_ASSERT;

    if(isRecognized)
    {
        //
        // Is write Int?
        //
        if (DMAINT.bits.INT_WR) {

            TraceEvents(TRACE_LEVEL_INFORMATION,  DBG_INTERRUPT,
                        "write Interrupt for DMA Channel");

            // Record the TSC now.
            _asm rdtsc
            _asm mov DWORD PTR i64End, EAX
            _asm mov DWORD PTR (i64End+4), EDX

            devExt->WriteEndTsc = i64End;

            KdPrint(("PCIEEvtInterruptIsr: WriteDMA_Int"));
        }

        //
        // Is DMA read-done?
        //
        if (DMAINT.bits.INT_RD) {

            TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
                        "read Interrupt for DMA Channel");


            // Record the TSC now
            _asm rdtsc
            _asm mov DWORD PTR i64End, EAX
            _asm mov DWORD PTR (i64End+4), EDX

            devExt->ReadEndTsc = i64End;

            KdPrint(("PCIEEvtInterruptIsr: ReadDMA_Int"));
        }

        // To Clear the Interrupt
        WRITE_REGISTER_ULONG((PULONG) &devExt->Regs->INT, DMAINT.ulong);
    }

    if (isRecognized)
    {
        //
        // A read or a write or both is done. Queue a DPC.
        //
        // There is no need for this driver to queue a DPC. So we comment it.
        //WdfInterruptQueueDpcForIsr( devExt->Interrupt );
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- PCIEInterruptHandler");

    KdPrint(("PCIEEvtInterruptIsr: Over"));

    return isRecognized;
}

VOID
PCIEEvtInterruptDpc(
    IN WDFINTERRUPT Interrupt,
    IN WDFDEVICE    Device
    )
/*++

Routine Description:

    DPC callback for ISR. Please note that on a multiprocessor system,
    you could have more than one DPCs running simulataneously on
    multiple processors. So if you are accesing any global resources
    make sure to synchrnonize the accesses with a spinlock.

Arguments:

    Interupt  - Handle to WDFINTERRUPT Object for this device.
    Device    - WDFDEVICE object passed to InterruptCreate

Return Value:

--*/
{
    NTSTATUS            status;
    WDFDMATRANSACTION   dmaTransaction;
    PDEVICE_EXTENSION   devExt;
    BOOLEAN             writeInterrupt = FALSE;
    BOOLEAN             readInterrupt  = FALSE;

    __int64             i64End;

    UNREFERENCED_PARAMETER(Device);


    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "--> EvtInterruptDpc");

    KdPrint(("EvtInterruptDpc: Begin"));

    devExt  = PCIEGetDeviceContext(WdfInterruptGetDevice(Interrupt));

    //
    // Acquire this device's InterruptSpinLock.
    //
    WdfInterruptAcquireLock( Interrupt );


    if (devExt->DMACSR2.bits.WriteDMADone)
    {
        devExt->DMACSR2.bits.WriteDMADone = 0;

        writeInterrupt = TRUE;
    }

    if (devExt->DMACSR2.bits.ReadDMADone)
    {
        devExt->DMACSR2.bits.ReadDMADone = 0;

        readInterrupt = TRUE;
    }

    //
    // Release our interrupt spinlock
    //
    WdfInterruptReleaseLock( Interrupt );

    //
    // Did a Write DMA complete?
    //
    if (writeInterrupt) {

        _asm rdtsc
        _asm mov DWORD PTR i64End, EAX
        _asm mov DWORD PTR (i64End + 4), EDX

        devExt->WriteEndTsc = i64End;

        KdPrint(("PCIEEvtInterruptDpc: writeInterrupt"));
    }

    //
    // Did a Read DMA complete?
    //
    if (readInterrupt) {

        _asm rdtsc
        _asm mov DWORD PTR i64End, EAX
        _asm mov DWORD PTR (i64End + 4), EDX

        devExt->ReadEndTsc = i64End;

        KdPrint(("PCIEEvtInterruptDpc: readInterrupt"));
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "<-- EvtInterruptDpc");
    KdPrint(("EvtInterruptDpc: Over"));

    return;
}

NTSTATUS
PCIEEvtInterruptEnable(
    IN WDFINTERRUPT Interrupt,
    IN WDFDEVICE    Device
    )
/*++

Routine Description:

    Called by the framework at DIRQL immediately after registering the ISR with the kernel
    by calling IoConnectInterrupt.

Return Value:

    NTSTATUS
--*/
{

    KdPrint(("PCIEEvtInterruptEnable"));

    return STATUS_SUCCESS;
}

NTSTATUS
PCIEEvtInterruptDisable(
    IN WDFINTERRUPT Interrupt,
    IN WDFDEVICE    Device
    )
/*++

Routine Description:

    Called by the framework at DIRQL before Deregistering the ISR with the kernel
    by calling IoDisconnectInterrupt.

Return Value:

    NTSTATUS
--*/
{

    KdPrint(("PCIEEvtInterruptDisable"));

    return STATUS_SUCCESS;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -