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

📄 nic_pm.c

📁 ddk开发pci范例,使用9054芯片
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
** COPYRIGHT (C) 1994-1997 INTEL CORPORATION                               **
** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON               **
** HTTP://WWW.INTEL.COM/                                                   **
** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND            **
** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER               **
****************************************************************************/
/* Converted to WDM - Eliyas Yakub - Feb 13, 2003 */

#include "precomp.h"

#if defined(EVENT_TRACING)
#include "nic_pm.tmh"
#endif


// Things to note:
// PME_ena bit should be active before the 82558 is set into low power mode
// Default for WOL should generate wake up event after a HW Reset

// Fixed Packet Filtering
// Need to verify that the micro code is loaded and Micro Machine is active
// Clock signal is active on PCI clock


// Address Matching
// Need to enable IAMatch_Wake_En bit and the MCMatch_Wake_En bit is set

// ARP Wakeup 
// Need to set BRCST DISABL bet to 0 (broadcast enable)
// To handle VLAN set the VLAN_ARP bit
// IP address needs to be configured with 16 least significant bits
// Set the IP Address in the IP_Address configuration word.

// Fixed WakeUp Filters:
// There are 3ight different fixed WakeUp Filters 
// ( Unicast, Multicast, Arp. etc). 


// Link Status Event
// Set Link_Status_Wakeup Enable bit.

// Flexible filtering:
// Supports: ARP packets, Directed, Magic Packet and Link Event

// Flexible Filtering Overview:
// driver should program micro-code before setting card into low power
// Incoming packets are compared against the loadable microcode. If PME is 
// is enabled then, the system is woken up.


// Segments are defined in book - but not implemented here.

// WakeUp Packet -that causes the machine to wake up will be stored
// in the Micro Machine temporary storage area so that the driver can read it.


// Software Work:
// Power Down:
// OS requests the driver to go to a low power state
// Software Pends request
// SW sets CU and RU to idle by issuing a Selective Reset to the device
//      3rd portion .- Wake Up Segments defintion
// The above three segments are loaded as on chain. The last CB must have
// its EL bit set.
// Device can now be powered down. 
// Software driver completes OS request
// OS then physically switches the Device to low power state 
// 

// Power Up:
// OS powers up the Device
// OS tells the SW that it is now in D0
// driver should NOT initialize the Device. It should NOT issue a Self Test
// Driver Initiates a PORT DUMP command
// Device dumps its internal registers including the wakeup frame storage area
// SW reads the PME register
// SW reads the WakeUp Frame Data, analyzes it and acts accordingly
// SW restores its cvonfiguration and and resumes normal operation.
//

//
// Power Management definitions from the Intel Handbook
//

//
// Definitions from Table 4.2, Pg 4.9 
// of the 10/100 Mbit Ethernet Family Software Technical 
// Reference Manual
//

#define PMC_Offset  0xDE
#define E100_PMC_WAKE_FROM_D0       0x1
#define E100_PMC_WAKE_FROM_D1       0x2
#define E100_PMC_WAKE_FROM_D2       0x4
#define E100_PMC_WAKE_FROM_D3HOT    0x8
#define E100_PMC_WAKE_FROM_D3_AUX   0x10

//
// Load Programmable filter definintions.
// Taken from C-19 from the Software Reference Manual.
// It has examples too. The opcode used for load is 0x80000
//

#define BIT_15_13                   0xA000

#define CB_LOAD_PROG_FILTER         BIT_3
#define CU_LOAD_PROG_FILTER_EL      BIT_7
#define CU_SUCCEED_LOAD_PROG_FILTER BIT_15_13
#define CB_FILTER_EL                BIT_7
#define CB_FILTER_PREDEFINED_FIX    BIT_6
#define CB_FILTER_ARP_WAKEUP        BIT_3
#define CB_FILTER_IA_WAKEUP         BIT_1

#define CU_SCB_NULL                 ((UINT)-1)


#pragma pack( push, enter_include1, 1 )

//
// Define the PM Capabilities register in the device
// portion of the PCI config space
// 
typedef struct _MP_PM_CAP_REG {

    USHORT UnInteresting:11;
    USHORT PME_Support:5;
   

} MP_PM_CAP_REG;


//
// Define the PM Control/Status Register
//
typedef struct  _MP_PMCSR {

        USHORT PowerState:2;    // Power State;
        USHORT Res:2;           // reserved
        USHORT DynData:1;       // Ignored
        USHORT Res1:3;            // Reserved 
        USHORT PME_En:1;        // Enable device to set the PME Event;
        USHORT DataSel:4;       // Unused
        USHORT DataScale:2;     // Data Scale - Unused
        USHORT PME_Status:1;    // PME Status - Sticky bit;


} MP_PMCSR ;

typedef struct _MP_PM_PCI_SPACE {

    UCHAR Stuff[PMC_Offset];

    // PM capabilites 
    
    MP_PM_CAP_REG   PMCaps;

    // PM Control Status Register
    
    MP_PMCSR        PMCSR;
    

} MP_PM_PCI_SPACE , *PMP_PM_PCI_SPACE ;


//
// This is the Programmable Filter Command Structure
//
typedef struct _MP_PROG_FILTER_COMM_STRUCT
{
    // CB Status Word
    USHORT CBStatus;

    // CB Command Word
    USHORT CBCommand;

    //Next CB PTR == ffff ffff
    ULONG NextCBPTR;

    //Programmable Filters
    ULONG FilterData[16];


} MP_PROG_FILTER_COMM_STRUCT,*PMP_PROG_FILTER_COMM_STRUCT;

typedef struct _MP_PMDR
{
    // Status of the PME bit
    UCHAR PMEStatus:1;

    // Is the TCO busy
    UCHAR TCORequest:1;

    // Force TCO indication
    UCHAR TCOForce:1;

    // Is the TCO Ready
    UCHAR TCOReady:1;

    // Reserved
    UCHAR Reserved:1;

    // Has an InterestingPacket been received
    UCHAR InterestingPacket:1;

    // Has a Magic Packet been received
    UCHAR MagicPacket:1;

    // Has the Link Status been changed
    UCHAR LinkStatus:1;
    
} MP_PMDR , *PMP_PMDR;

//-------------------------------------------------------------------------
// Structure used to set up a programmable filter.
// This is overlayed over the Control/Status Register (CSR)
//-------------------------------------------------------------------------
typedef struct _CSR_FILTER_STRUC {

    // Status- used to  verify if the load prog filter command 
    // has been accepted .set to 0xa000 
    USHORT      ScbStatus;              // SCB Status register

    // Set to an opcode of  0x8  
    //
    UCHAR       ScbCommandLow;          // SCB Command register (low byte)

    // 80. Low + High gives the required opcode 0x80080000
    UCHAR       ScbCommandHigh;         // SCB Command register (high byte)

    // Set to NULL ff ff ff ff 
    ULONG       NextPointer;      // SCB General pointer

    // Set to a hardcoded filter, Arp + IA Match, + IP address

    union
    {
        ULONG u32;

        struct {
            UCHAR   IPAddress[2];
            UCHAR   Reserved;
            UCHAR   Set;
        
        }PreDefined;
        
    }Programmable;     // Wake UP Filter    union
    
} CSR_FILTER_STRUC, *PCSR_FILTER_STRUC;

#pragma pack( pop, enter_include1 )

#define MP_CLEAR_PMDR(pPMDR)  (*pPMDR) = ((*pPMDR) | 0xe0);  // clear the 3 uppermost bits in the PMDR


//-------------------------------------------------------------------------
// L O C A L    P R O T O T Y P E S 
//-------------------------------------------------------------------------

__inline 
NTSTATUS 
MPIssueScbPoMgmtCommand(
    IN PFDO_DATA Adapter,
    IN PCSR_FILTER_STRUC pFilter,
    IN BOOLEAN WaitForScb
    );


VOID
MPCreateProgrammableFilter (
    IN PMP_WAKE_PATTERN     pMpWakePattern , 
    IN PUCHAR pFilter, 
    IN OUT PULONG pNext
    );



//-------------------------------------------------------------------------
// P O W E R    M G M T    F U N C T I O N S  
//-------------------------------------------------------------------------

PUCHAR 
HwReadPowerPMDR(
    IN  PFDO_DATA     Adapter
    )
/*++
Routine Description:

    This routine will Hardware's PM registers
    
Arguments:

    Adapter     Pointer to our adapter

Return Value:

    STATUS_SUCCESS
    NTSTATUS_HARD_ERRORS

--*/    
{
    UCHAR PMDR =0;
    PUCHAR pPMDR = NULL;

#define CSR_SIZE sizeof (*Adapter->CSRAddress)



    ASSERT (CSR_SIZE == 0x18);

    pPMDR =  0x18 + (PUCHAR)Adapter->CSRAddress ;

    PMDR = *pPMDR;

    return pPMDR;

}


NTSTATUS
MpClearPME_En (
    IN PFDO_DATA FdoData,
    IN MP_PMCSR PMCSR
    )
{
    NTSTATUS status;
    UINT ulResult;
    
    PMCSR.PME_En = 0;    
    
    ulResult = FdoData->BusInterface.SetBusData(
                    FdoData->BusInterface.Context,
                    PCI_WHICHSPACE_CONFIG,
                    (PVOID)&PMCSR,
                    FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR),
                    sizeof(PMCSR));

    ASSERT (ulResult == sizeof(PMCSR));
    if (ulResult == sizeof(PMCSR))
    {
        status = STATUS_SUCCESS;
    }
    else
    {
        status = STATUS_UNSUCCESSFUL;
    }

    return status;
    
}



VOID
MPSetPowerLowPrivate(
    PFDO_DATA FdoData 
    )
/*++
Routine Description:

    The section follows the steps mentioned in 
    Section C.2.6.2 of the Reference Manual.
  

Arguments:

    Adapter     Pointer to our adapter

Return Value:

--*/    
{
    CSR_FILTER_STRUC    Filter;
    USHORT              IntStatus;
    MP_PMCSR            PMCSR;
    ULONG               ulResult; 

    DebugPrint(TRACE, DBG_POWER, "-->MPSetPowerLowPrivate\n");
    RtlZeroMemory (&Filter, sizeof (Filter));

    do
    {

        //
        // Before issue the command to low power state, we should disable the 
        // interrup and ack all the pending interrupts, then set the adapter's power to
        // low state.
        // 
        NICDisableInterrupt(FdoData);
        NIC_ACK_INTERRUPT(FdoData, IntStatus);    

        //
        // If the driver should wake up the machine
        //
        if (FdoData->AllowWakeArming)
        {
            //
            // Send the WakeUp Patter to the nic                        
            MPIssueScbPoMgmtCommand(FdoData, &Filter, TRUE);
        

            //
            // Section C.2.6.2 - The driver needs to wait for the CU to idle
            // The above function already waits for the CU to idle
            //
            ASSERT ((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_IDLE);
        }
        else
        {
    
            ulResult = FdoData->BusInterface.GetBusData(
                                    FdoData->BusInterface.Context,
                                    PCI_WHICHSPACE_CONFIG,
                                    (PVOID)&PMCSR,
                                    FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR),
                                    sizeof(PMCSR));

            if(ulResult != sizeof(PMCSR)){
                ASSERT(ulResult == sizeof(PMCSR));
                DebugPrint(ERROR, DBG_POWER, "GetBusData for PMCSR failed\n");
                return;
            }
            if (PMCSR.PME_En == 1)
            {
                //
                // PME is enabled. Clear the PME_En bit.
                // So that it is not asserted
                //
                MpClearPME_En (FdoData,PMCSR);

            }

            //
            // Set the driver to lower power state by OS
            //

⌨️ 快捷键说明

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