/*++

Copyright (c) 2000 Microsoft Corporation

Module Name:

    i82558.h

Abstract:

    Intel 82558 NIC hardware related declarations

Revision History:

    05/07/2000 davidx
        Created it.

--*/

#ifndef _82558_H
#define _82558_H

//
// Vendor and device IDs for EPRO100+
//
#define NIC_VENDORID 0x8086
#define NIC_DEVICEID 0x1229

//------------------------------------------------------------------------
// I82558 command/status registers
//------------------------------------------------------------------------

typedef struct _NIC_CSR {
    BYTE cusRus;
        // CU and RU status
        // Bit 7-6: CUS - CU status field
        //  00 - idle
        //  01 - suspended
        //  10 - active
        //  11 - * (reserved)
        // Bit 5-2: RUS - RU status field
        //  0000 - idle
        //  0001 - suspended
        //  0010 - no resources
        //  0011 - *
        //  0100 - ready
        //  0101 - *
        //  0110 - *
        //  0111 - *
        //  1000 - *
        //  1001 - suspended with no more RBDs
        //  1010 - No resources due to no more RBDs
        //  1011 - *
        //  1100 - ready with no RBDs present
        //  1101 - *
        //  1110 - *
        //  1111 - *
        // Bit 1-0: reserved

    #define SCB_STAT_CUS(x) (((x) >> 6) & 3)
    #define   CUS_IDLE          0
    #define   CUS_SUSPENDED     1
    #define   CUS_ACTIVE        2
    #define SCB_STAT_RUS(x) (((x) >> 2) & 0xf)
    #define   RUS_IDLE          0
    #define   RUS_SUSPENDED     1
    #define   RUS_NORES         2
    #define   RUS_READY         4
    #define   RUS_SUSPENDED_RBD 9
    #define   RUS_NORES_RBD     10
    #define   RUS_READY_RBD     12

    BYTE statAck;
        // Interrupt status and acknowledgement bits
        // Bit 7: CX - CU finished executing a command with I-bit set
        // Bit 6: FR - RU finished receiving a frame
        // Bit 5: CNA - CU went from active to idle or suspended state
        // Bit 4: RNR - RU left ready state
        // Bit 3: MDI - MDI read or write cycle is done
        // Bit 2: SWI - software generated an interrupt
        // Bit 1: reserved
        // Bit 0: FCP - flow control pause interrupt bit

    #define SCB_STAT_CX     BIT(7)
    #define SCB_STAT_FR     BIT(6)
    #define SCB_STAT_CNA    BIT(5)
    #define SCB_STAT_RNR    BIT(4)
    #define SCB_STAT_MDI    BIT(3)
    #define SCB_STAT_SWI    BIT(2)
    #define SCB_STAT_FCP    BIT(0)

    BYTE cucRuc;
        // Bit 7-4: CUC - CU command field
        //  0000 - NOP
        //  0001 - CU start
        //  0010 - CU resume
        //  0011 - *
        //  0100 - load dump counters address
        //  0101 - dump statistical counters
        //  0110 - load CU base
        //  0111 - dump and reset statistical counters
        //  1000 - *
        //  1001 - *
        //  1010 - static resume
        //  1011 - *
        //  ...
        //  1111 - *
        // Bit 3: reserved
        // Bit 2-0: RU command field
        //  000 - NOP
        //  001 - RU start
        //  010 - RU resume
        //  011 - RU DMA redirect
        //  100 - RU abort
        //  101 - load header data size
        //  110 - load RU base
        //  111 - RBD resume

    #define CUC_NOP             (0 << 4)
    #define CUC_START           (1 << 4)
    #define CUC_RESUME          (2 << 4)
    #define CUC_LOAD_DUMP_ADDR  (4 << 4)
    #define CUC_DUMP_STAT       (5 << 4)
    #define CUC_LOAD_CU_BASE    (6 << 4)
    #define CUC_DUMP_RESET_STAT (7 << 4)
    #define CUC_STATIC_RESUME   (10 << 4)

    #define RUC_NOP             0
    #define RUC_START           1
    #define RUC_RESUME          2
    #define RUC_RCVDMA_REDIRECT 3
    #define RUC_ABORT           4
    #define RUC_LOAD_HDS        5
    #define RUC_LOAD_RU_BASE    6
    #define RUC_RBD_RESUME      7

    BYTE intrMask;
        // Bit 7: CX interrupt mask bit
        // Bit 6: FR interrupt mask bit
        // Bit 5: CNA interrupt mask bit
        // Bit 4: RNR interrupt mask bit
        // Bit 3: ER interrupt mask bit
        // Bit 2: FCP interrupt mask bit
        // Bit 1: SI - software interrupt request
        // Bit 0: M - global interrupt mask

    #define CX_INTR_BIT     BIT(7)
    #define FR_INTR_BIT     BIT(6)
    #define CNA_INTR_BIT    BIT(5)
    #define RNR_INTR_BIT    BIT(4)
    #define ER_INTR_BIT     BIT(3)
    #define FCP_INTR_BIT    BIT(2)
    #define SW_INTR_BIT     BIT(1)
    #define INTR_MASK_BIT   BIT(0)

    DWORD scbGeneralPtr;
        // SCB general pointer

    DWORD port;
        // PORT interface
        // Bit 31-4: address bits
        // Bit 3-0: port function selection
        //  0000 - software reset
        //  0001 - self-test
        //  0010 - selective reset
        //  0011 - dump
        //  0100 - *
        //  ...
        //  1111 - *

    #define PORTCMD_SOFTWARE_RESET  0
    #define PORTCMD_SELF_TEST       1
    #define PORTCMD_SELECTIVE_RESET 2
    #define PORTCMD_DUMP            3

    WORD flashCtrl;
        // Flash control register

    WORD eepromCtrl;
        // EEPROM control register
        // Bit 7-4: reserved
        // Bit 3: EEDO - data out
        // Bit 2: EEDI - data in
        // Bit 1: EECS - chip select
        // Bit 0: EESK - serial clock

    #define EEPROM_DO   BIT(3)
    #define EEPROM_DI   BIT(2)
    #define EEPROM_CS   BIT(1)
    #define EEPROM_SK   BIT(0)

    #define EEPROMOP_WRITE  1
    #define EEPROMOP_READ   2

    DWORD mdiCtrl;
        // MDI control register
        // Bit 31-30: reserved
        // Bit 29: interrupt enable
        // Bit 28: ready
        // Bit 27-26: opcode
        //  00 - *
        //  01 - MDI write
        //  10 - MDI read
        //  11 - *
        // Bit 25-21: PHY address
        // Bit 20-16: PHY register address
        // Bit 15-0: data field

    #define MDI_INTR_ENABLE     BIT(29)
    #define MDI_READY           BIT(28)
    #define MDIOP_WRITE         (1 << 26)
    #define MDIOP_READ          (2 << 26)
    #define MDI_PHY_ADDR(x)     ((x) << 21)
    #define MDI_PHY_REG_ADDR(x) ((x) << 16)

    DWORD reserved1;
    DWORD reserved2;
        // Bit 31-24: PMDR - power management driver register
        // Bit 23-8: flow control register
        // Bit 7-0: reserved
} volatile *PNIC_CSR;

extern PNIC_CSR NicCsr;

//------------------------------------------------------------------------
// 82558 general action command format
// NOTE: We store this information in the Packet.ifdata field
// of an outgoing packet. And it's tail-aligned so that it's
// contiguous with the packet data field.
//------------------------------------------------------------------------

typedef struct _ActionCmdBlock {
    DWORD cmdstatus;
        // Command and status:
        //  bit 31 (EL) - end of command block list
        //  bit 30 (S) - suspend after command completion
        //  bit 29 (I) - interrupt after command completion
        //  bit 28-19 - varies with different commands
        //  bit 18-16 (CMD) - command code
        //  bit 15 (C) - command completed
        //  bit 14 - reserved
        //  bit 13 - command executed ok
        //  bit 12-0 - varies with different commands

    #define CMDFLAG_EL          BIT(31)
    #define CMDFLAG_S           BIT(30)
    #define CMDFLAG_I           BIT(29)

    #define ACTIONCMD_NOP       (0 << 16)
    #define ACTIONCMD_IA_SETUP  (1 << 16)
    #define ACTIONCMD_CONFIGURE (2 << 16)
    #define ACTIONCMD_MC_SETUP  (3 << 16)
    #define ACTIONCMD_TRANSMIT  (4 << 16)
    #define ACTIONCMD_DUMP      (6 << 16)
    #define ACTIONCMD_DIAGNOSE  (7 << 16)

    #define CMDSTATUS_C         BIT(15)
    #define CMDSTATUS_OK        BIT(13)

    DWORD link;
        // link to the next command block in the list
        //  this is a physical address
        //  use 0xffffffff at the end of the list

    #define LINK_OFFSET_NULL 0xffffffff

} ActionCmdBlock;

//------------------------------------------------------------------------
// Transmit command block (TxCB)
//------------------------------------------------------------------------

typedef struct _TransmitCmdBlock {
    ActionCmdBlock;
        // General action command data:
        //  command / status
        //  link
        // Additional command and status flags:
        //  bit 20 (NC) - no CRC and source address insertion
        //  bit 19 (SF) - simple or flexible mode
        //  bit 12 (U) - transmit underrun encountered

    #define TxCBFLAG_NC     BIT(20)
    #define TxCBFLAG_SF     BIT(19)

    #define TxCBSTATUS_U    BIT(12)

    DWORD tbdArray;
        // in flexible mode, physical address of the TBD array

    WORD byteCount;
        // bit 15 (EOF) - whole frame is kept inside the command block itself
        // bit 14 - reserved
        // bit 13-0: amount of data in the transmit command block itself

    #define TxCB_EOF        BIT(15)

    BYTE txThreshold;
        // number of bytes that should be present in the Tx FIFO
        // before it starts transmitting the frame

    BYTE tbdNumber;
        // in flexible mode, represent the number of transmit buffers
        // in the TBD array
} TransmitCmdBlock;

//
// Early transmit threshold
//  This number is multiplied by 8 to get the actual byte count.
//  BOGUS: Not sure why w2k driver uses such a high value which
//  basically disables the early transmit feature.
//
#define DEFAULT_Tx_THRESHOLD 200

//
// Maximum number of TBD's for transmitting a single packet.
// This is not a hardware limit. Rather it's an arbitrary software
// limit we set. When there are two many fragments for a single
// packet, something upstream must be pretty bad and it's better
// to address the real issues there.
//
#define MAX_TBD_PER_XMIT 4

//
// TBD (Transmit Buffer Descriptor) entry
//
typedef struct _TBDEntry {
    DWORD bufaddr;
        // physical address of the buffer data

    DWORD bufsize;
        // bit 31-16: reserved
        // bit 15 (EL): end of the TBD array
        // bit 14: reserved
        // bit 13-0: buffer size (in bytes)
} TBDEntry;

//------------------------------------------------------------------------
// Multicast setup command block
//------------------------------------------------------------------------

typedef struct _McastSetupCmdBlock {
    ActionCmdBlock;
        // General action command data:
        //  command / status
        //  link
    
    WORD mcastCount;
        // Number of multicast addresses to follow
    
    BYTE mcastAddrs[ENETADDRLEN];
        // variable number of Ethernet multicast addresses
} McastSetupCmdBlock;

//------------------------------------------------------------------------
// Individual address setup command block
//------------------------------------------------------------------------

typedef struct _IASetupCmdBlock {
    ActionCmdBlock;
        // General action command data:
        //  command / status
        //  link

    BYTE hwaddr[ENETADDRLEN];
        // Individual address
} IASetupCmdBlock;

//------------------------------------------------------------------------
// Configure command block
//------------------------------------------------------------------------

typedef struct _ConfigCmdBlock {
    ActionCmdBlock;
        // General action command data:
        //  command / status
        //  link

    // Maximum number of configuration parameters
    #define CONFIG_PARAM_COUNT 22

    BYTE params[CONFIG_PARAM_COUNT];
        // Configuration parameters
} ConfigCmdBlock;

//------------------------------------------------------------------------
// Receive frame descriptor (RFD)
//------------------------------------------------------------------------

typedef struct _RecvFrameDesc {
    ActionCmdBlock;
        // General action command data:
        //  command / status
        //  link
        // Additional command and status flags:
        //  bit 20 (H) - indicate this RFD is a Header RFC
        //  bit 19 (SF) - simple or flexible mode
        //
        //  bit 11 - CRC error in an aligned frame
        //  bit 10 - alignment error (number of bits is not 8x)
        //  bit 9 - ran out of buffer space - no resources
        //  bit 8 - DMA overrun - failed to acquire the system bus
        //  bit 7 - frame too short
        //  bit 5 - type/length: 1 for Ethernet frame, 0 for 802.3 frame
        //  bit 4 - receive error
        //  bit 2 - no address match
        //  bit 1 - IA match bit
        //  bit 0 - receive collision
    
    #define RFDFLAG_H   BIT(20)
    #define RFDFLAG_SF  BIT(19)

    #define RFDSTATUS_CRC_ERROR     BIT(11)
    #define RFDSTATUS_ALIGN_ERROR   BIT(10)
    #define RFDSTATUS_NO_BUFFER     BIT(9)
    #define RFDSTATUS_DMA_OVERRUN   BIT(8)
    #define RFDSTATUS_SHORT_FRAME   BIT(7)
    #define RFDSTATUS_ENET_FRAME    BIT(5)
    #define RFDSTATUS_RECV_ERROR    BIT(4)
    #define RFDSTATUS_NOADDR_MATCH  BIT(2)
    #define RFDSTATUS_IA_MATCH      BIT(1)
    #define RFDSTATUS_COLLISION     BIT(0)

    DWORD rbdAddr;
        // only used in flexible mode
        // address of RBD (receive buffer descriptor)
    
    WORD actualCount;
        // bit 15 (EOF): set by 82558 when it writes data into the data area
        // bit 14 (F): set by 82558 when it updates the actualCount field
        // bit 13-0: number of bytes written into the data area

    #define RFD_EOF     BIT(15)
    #define RFD_F       BIT(14)
    #define RFD_CNTMASK 0x3fff

    WORD size;
        // bit 15-14: reserved
        // bit 13-0: size of the data buffer
} RecvFrameDesc;

//------------------------------------------------------------------------
// 82558 Statistical Counters
//------------------------------------------------------------------------

typedef struct _NicStatCounters {
    DWORD xmitGoodFrames;
    DWORD xmitMaxCollisionsErrors;
    DWORD xmitLateCollisionsErrors;
    DWORD xmitUnderrunErrors;
    DWORD xmitLostCarrierSense;
    DWORD xmitDeferred;
    DWORD xmitSingleCollisions;
    DWORD xmitMultipleCollisions;
    DWORD xmitTotalCollisions;
    DWORD recvGoodFrames;
    DWORD recvCrcErrors;
    DWORD recvAlignmentErrors;
    DWORD recvResourceErrors;
    DWORD recvOverrunErrors;
    DWORD recvCollisionDetectErrors;
    DWORD recvShortFrameErrors;
    DWORD dumpCompletionStatus;
} NicStatCounters;


//
// We allocate a page of physically contiguous memory that's shared by
// the CPU and the NIC. This buffer is used for storing action command
// data (e.g. transmit command block and transmit buffer descriptor)
// that's passed to the NIC.
//
//  start  head        tail         last
//   |      |           |           |
//   v      v           v           v
//  |       xxxxxxxxxxxx           |
//
// Note that we always leave at least one unit empty in the buffer.
// If head = tail, that means the whole buffer is empty.
//
typedef struct _NicCmdBuffer {
    BYTE* start;        // buffer base virtual address
    BYTE* last;         // points to after the buffer
    BYTE* head;         // points to the first busy entry
    BYTE* tail;         // points to the first free entry
    UINT phyaddrOffset; // offset between virtual and physical address
} NicCmdBuffer;

// The smallest allocation unit is 8 bytes.
#define CMDBUF_ALLOC_UNIT 8

// Map virtual command buffer address to physical address
#define CmdBufferGetPhyAddr(nic, p) \
        ((UINT_PTR) (p) + (nic)->cmdbuf.phyaddrOffset)

//
// Extra header information at the beginning of the DMA packet
// that's used by the NIC for receiving frames:
//  receive frame descriptor
//
#define RECVPKT_OVERHEAD sizeof(RecvFrameDesc)

//
// Allocate shared memory buffers for the NIC
//
#define NicAllocSharedMem(size) MmAllocateContiguousMemory(size)
#define NicFreeSharedMem(p) MmFreeContiguousMemory(p)

//
// Disable and enable NIC interrupts
//
INLINE VOID NicDisableInterrupt() {
    NicCsr->intrMask = INTR_MASK_BIT;
}

INLINE VOID NicEnableInterrupt() {
    NicCsr->intrMask = 0;
}

#endif // !_82558_H

