📄 dec21140.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
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:
Abstract:
Routines for DEC21140 NIC used by bootloader download and
ether debug.
Functions:
Notes:
--*/
#include <windows.h>
#include <halether.h>
#include <wdm.h>
#include "dec21140.h"
#define MIN_DMA_SIZE 0x20000 // Minimum DMA buffer possible.
#define DEC21140_SETUP_PERFECT_ENTRIES 16 // # of perfect match entries
// Forward declaration...
void DEC21140ModeSetByAutoNegotiation(void);
BOOL EEPROMReadMAC(WORD *wMAC);
/////////////////////////////////////////////////////////////////////////////////
//
//
#define __DEC21140_DUMP_TX_DESCRIPTOR__ 1
#ifdef __DEC21140_DUMP_TX_DESCRIPTOR__
static void DumpTxDescriptor (PTX_DESCRIPTOR_FORMAT pTxHead);
#endif
#define __DEC21140_DUMP_RX_DESCRIPTOR__ 1
#ifdef __DEC21140_DUMP_RX_DESCRIPTOR__
static void DumpRxDescriptor (PRX_DESCRIPTOR_FORMAT pRxHead);
#endif
#define __DEC21140_DUMP_MEMORY__ 1
#ifdef __DEC21140_DUMP_MEMORY__
static void DumpMemory (PBYTE pSource, DWORD dwLength);
#endif
/////////////////////////////////////////////////////////////////////////////////
// External Functions that must be there...
//
//extern void localDEBUGMSG(const unsigned char *sz, ...);
#define localDEBUGMSG EdbgOutputDebugString
extern DWORD OEMEthGetMSecs (void);
/////////////////////////////////////////////////////////////////////////////////
// Misc defines
//
#define CSR0_OFFSET 0x00
#define CSR1_OFFSET 0x08
#define CSR2_OFFSET 0x10
#define CSR3_OFFSET 0x18
#define CSR4_OFFSET 0x20
#define CSR5_OFFSET 0x28
#define CSR6_OFFSET 0x30
#define CSR7_OFFSET 0x38
#define CSR8_OFFSET 0x40
#define CSR9_OFFSET 0x48
#define CSR10_OFFSET 0x50
#define CSR11_OFFSET 0x58
#define CSR12_OFFSET 0x60
#define CSR13_OFFSET 0x68
#define CSR14_OFFSET 0x70
#define CSR15_OFFSET 0x78
#define CSR0_REG (PULONG)(g_pIOBase + CSR0_OFFSET)
#define CSR1_REG (PULONG)(g_pIOBase + CSR1_OFFSET)
#define CSR2_REG (PULONG)(g_pIOBase + CSR2_OFFSET)
#define CSR3_REG (PULONG)(g_pIOBase + CSR3_OFFSET)
#define CSR4_REG (PULONG)(g_pIOBase + CSR4_OFFSET)
#define CSR5_REG (PULONG)(g_pIOBase + CSR5_OFFSET)
#define CSR6_REG (PULONG)(g_pIOBase + CSR6_OFFSET)
#define CSR7_REG (PULONG)(g_pIOBase + CSR7_OFFSET)
#define CSR8_REG (PULONG)(g_pIOBase + CSR8_OFFSET)
#define CSR9_REG (PULONG)(g_pIOBase + CSR9_OFFSET)
#define CSR10_REG (PULONG)(g_pIOBase + CSR10_OFFSET)
#define CSR11_REG (PULONG)(g_pIOBase + CSR11_OFFSET)
#define CSR12_REG (PULONG)(g_pIOBase + CSR12_OFFSET)
#define CSR13_REG (PULONG)(g_pIOBase + CSR13_OFFSET)
#define CSR14_REG (PULONG)(g_pIOBase + CSR14_OFFSET)
#define CSR15_REG (PULONG)(g_pIOBase + CSR15_OFFSET)
#ifdef MIPS
#define TO_REAL(Addr) ((Addr & 0x1fffffff) + dwMEM_OFFSET)
#define TO_VIRT(Addr) ((Addr | 0xA0000000) - dwMEM_OFFSET)
#else
#define TO_REAL(Addr) (Addr)
#define TO_VIRT(Addr) (Addr)
#endif
/////////////////////////////////////////////////////////////////////////////////
// Local Variables...
//
static BYTE pbEthernetAddr[6]; // Local copy of MAC address
volatile PCSR pCSR; // pointer to 21140 Control and Status Register
PUCHAR g_pIOBase = NULL;
volatile PRX_DESCRIPTOR_FORMAT pRxDesc; // pointer to RX Descriptor head.
volatile PRX_DESCRIPTOR_FORMAT pCurrentRxDesc; // pointer to current RX Descriptor that Rx may use.
volatile PTX_DESCRIPTOR_FORMAT pTxDesc; // pointer to TX Descriptor head.
volatile PTX_DESCRIPTOR_FORMAT pCurrentTxDesc; // pointer to current TX Descriptor that Tx may use.
static DWORD dwMEM_OFFSET;
// These used to be constants.
// To make this a true hardware independent library, user needs to provide these addresses...
volatile DWORD dwTRANSMIT_DESCRIPTORS_HEAD;
volatile DWORD dwRECEIVE_DESCRIPTORS_HEAD;
volatile DWORD dwTRANSMIT_BUFFER_START;
volatile DWORD dwRECEIVE_BUFFER_START;
// Then we will calculate the following...
static DWORD dwTRANSMIT_RING_SIZE;
static DWORD dwRECEIVE_RING_SIZE;
// Forward declaration...
BOOL DEC21140SetupPerfectFilter (PUCHAR pucMulticastAddresses, DWORD dwNoOfAddresses);
/////////////////////////////////////////////////////////////////////////////////
// Delay - Spin for the asked amount of time in MilliSecond.
// Input: dwMilliSecond === Delay required in MilliSecond.
// Oh well, simply spin...
//
void Delay (DWORD dwMilliSecond)
{
// Need to find a better way...
// But should be okay for ether debug purposes...
while (dwMilliSecond--)
{
READ_PORT_ULONG(CSR9_REG);
}
} // Delay()
/////////////////////////////////////////////////////////////////////////////////
// MIIRead() -
// On ICS1890, it's written:
// Management Interface uses a serial bit stream with a specified frame
// structure and protocol as defined:
// - Preamble [32 ones]
// - SOF [01]
// - OpCode [10(read) ; 01(write)]
// - Address [5 bits]
// - Register [5 bits]
// - TA [2 bits]
// - Data [16 bits]
// - Idle [at least 1 bit]
//
//
// CSR9 controls:
// +-----------------+-----------------+-----------------+-----------------+
// | MII Management | MII Management | MII Management | MII Management |
// | Data In | Operation Mode | Write Data | Clock |
// +-----------------+-----------------+-----------------+-----------------+
// 19 18 17 16
//
WORD MIIRead (BYTE bRegAddr)
{
WORD wValue;
DWORD wData;
int i;
// Start with clock low and MDIO high
WRITE_PORT_ULONG(CSR9_REG, 0x00020000);
// 32 cycles with MDIO = '1'
for( i = 0; i < 32; i++ )
{
WRITE_PORT_ULONG(CSR9_REG, 0x00030000);
WRITE_PORT_ULONG(CSR9_REG, 0x00020000);
}
// Start of frame 01
WRITE_PORT_ULONG(CSR9_REG, 0x00000000);
WRITE_PORT_ULONG(CSR9_REG, 0x00010000);
WRITE_PORT_ULONG(CSR9_REG, 0x00020000);
WRITE_PORT_ULONG(CSR9_REG, 0x00030000);
// Read cycle 10
WRITE_PORT_ULONG(CSR9_REG, 0x00020000);
WRITE_PORT_ULONG(CSR9_REG, 0x00030000);
WRITE_PORT_ULONG(CSR9_REG, 0x00000000);
WRITE_PORT_ULONG(CSR9_REG, 0x00010000);
// Physical address of 00001.
WRITE_PORT_ULONG(CSR9_REG, 0x00000000);
WRITE_PORT_ULONG(CSR9_REG, 0x00010000);
WRITE_PORT_ULONG(CSR9_REG, 0x00000000);
WRITE_PORT_ULONG(CSR9_REG, 0x00010000);
WRITE_PORT_ULONG(CSR9_REG, 0x00000000);
WRITE_PORT_ULONG(CSR9_REG, 0x00010000);
WRITE_PORT_ULONG(CSR9_REG, 0x00000000);
WRITE_PORT_ULONG(CSR9_REG, 0x00010000);
WRITE_PORT_ULONG(CSR9_REG, 0x00020000);
WRITE_PORT_ULONG(CSR9_REG, 0x00030000);
// Register address
for( i = 4; i >= 0; i-- )
{
if (bRegAddr & (1 << i))
{
WRITE_PORT_ULONG(CSR9_REG, 0x00020000);
WRITE_PORT_ULONG(CSR9_REG, 0x00030000);
}
else
{
WRITE_PORT_ULONG(CSR9_REG, 0x00000000);
WRITE_PORT_ULONG(CSR9_REG, 0x00010000);
}
}
// Two cycle turnaround time
WRITE_PORT_ULONG(CSR9_REG, 0x00040000);
WRITE_PORT_ULONG(CSR9_REG, 0x00050000);
WRITE_PORT_ULONG(CSR9_REG, 0x00040000);
WRITE_PORT_ULONG(CSR9_REG, 0x00050000);
// Read out the data bits
wValue = 0;
for( i = 0; i < 16; i++ )
{
wValue <<= 1;
WRITE_PORT_ULONG(CSR9_REG, 0x00040000);
wData = READ_PORT_ULONG(CSR9_REG);
WRITE_PORT_ULONG(CSR9_REG, 0x00050000);
wData = (wData >> 19);
wValue |= (WORD) (wData & 1);
}
// Two cycle at the end to make sure it's now Idle
WRITE_PORT_ULONG(CSR9_REG, 0x00040000);
WRITE_PORT_ULONG(CSR9_REG, 0x00050000);
WRITE_PORT_ULONG(CSR9_REG, 0x00040000);
WRITE_PORT_ULONG(CSR9_REG, 0x00050000);
return wValue;
}
/////////////////////////////////////////////////////////////////////////////////
// HWStopAdapter - Stop the adapter by resetting the chip through CSR0[0]
//
static void
HWStopAdapter(void)
{
CSR6_21140 CSR6;
CSR0_21140 CSR0;
CSR6.dwReg = READ_PORT_ULONG(CSR6_REG);
CSR6.PortSelect = 1; // Select MII/SYM port.
WRITE_PORT_ULONG(CSR6_REG, CSR6.dwReg);
CSR0.dwReg = READ_PORT_ULONG(CSR0_REG);
CSR0.dwReg |= SOFTWARE_RESET;
WRITE_PORT_ULONG(CSR0_REG, CSR0.dwReg);
Delay (12000);
CSR6.dwReg = READ_PORT_ULONG(CSR6_REG);
CSR6.TransmitThresholdMode = 1;
WRITE_PORT_ULONG(CSR6_REG, CSR6.dwReg);
} // HWStopAdapter()
/////////////////////////////////////////////////////////////////////////////////
// HWInit - completely initialize the hardware and leave it in a state that is ready to transmit and receive
// packets.
//
static BOOL
HWInit(void)
{
int i;
int dwTxRingSize;
int dwRxRingSize;
int dwTxBufferStart;
int dwRxBufferStart;
volatile PTX_DESCRIPTOR_FORMAT pTxHead;
volatile PRX_DESCRIPTOR_FORMAT pRxHead;
CSR0_21140 localCSR0;
CSR6_21140 localCSR6;
dwTxRingSize = dwTRANSMIT_RING_SIZE;
dwRxRingSize = dwRECEIVE_RING_SIZE;
dwTxBufferStart = TO_REAL(dwTRANSMIT_BUFFER_START);
dwRxBufferStart = TO_REAL(dwRECEIVE_BUFFER_START);
HWStopAdapter();
// ==========================================================================
// The descriptors are linked by circular linked list
// They are basically one after another, and we use buffer address 2 as pointer to
// next descriptor.
// The last descriptor will link back to first descriptor.
// First stop, TX descriptors...
// Note: Initializing pTxDesc and pCurrentTxDesc for future global use...
pTxHead = pTxDesc = pCurrentTxDesc = (PTX_DESCRIPTOR_FORMAT) dwTRANSMIT_DESCRIPTORS_HEAD;;
memset (pTxHead, 0, (sizeof(TX_DESCRIPTOR_FORMAT) * dwTxRingSize));
for (i = 0 ; i < dwTxRingSize ; i++)
{
// For each descriptor, this is what we need to set:
// - The descriptor is now owned by Host TDES0[31]
// - TDES1[24] set indicating second address is a chained address
// - TDES1[25] set for last descriptor indicating a loop back.
// - TDES2 will point to the buffer this descriptor points to.
// - The next descriptor address in TDES3
pTxHead->TDES0.dwReg = pTxHead->TDES0.dwReg & DESC_OWNED_BY_HOST;
pTxHead->TDES1.dwReg = pTxHead->TDES1.dwReg | SECOND_ADDRESS_CHAINED;
pTxHead->TDES2 = dwTxBufferStart;
dwTxBufferStart += MAX_BUFFER_SIZE;
if (i == dwTxRingSize - 1)
{
// Last descriptor points to first descriptor...
// And indicates that this is the end of the ring...
pTxHead->TDES1.TransmitEndOfRing = 1;
pTxHead->TDES3 = TO_REAL((DWORD) pTxDesc);
}
else
{
pTxHead->TDES3 = TO_REAL((DWORD) ((DWORD)pTxHead + sizeof(TX_DESCRIPTOR_FORMAT)));
pTxHead = (PTX_DESCRIPTOR_FORMAT) TO_VIRT(pTxHead->TDES3);
}
}
//DumpTxDescriptor (pTxDesc);
// ==========================================================================
// Then, Rx descriptors...
// Note: Initializing pRxDesc for future global use...
//
pRxHead = pRxDesc = pCurrentRxDesc = (PRX_DESCRIPTOR_FORMAT) dwRECEIVE_DESCRIPTORS_HEAD;;
memset (pRxHead, 0, (sizeof(RX_DESCRIPTOR_FORMAT) * dwRxRingSize));
memset ((PBYTE)TO_VIRT(dwRxBufferStart), 0, dwRxRingSize * 1536);
for (i = 0 ; i < dwRxRingSize ; i++)
{
// For each descriptor, this is what we need to set:
// - The descriptor is now owned by DEC21140 RDES0[31] = 1
// - RDES1[24] set indicating second address is a chained address,
// - RDES1[25] set for last descriptor indicating a loop back.
// - RDES2 will point to the buffer this descriptor points to.
// - The next descriptor address in TDES3
pRxHead->RDES0.dwReg = pRxHead->RDES0.dwReg | DESC_OWNED_BY_DEC21140;
pRxHead->RDES1.dwReg = pRxHead->RDES1.dwReg | SECOND_ADDRESS_CHAINED;
pRxHead->RDES1.Buffer1Size = MAX_BUFFER_SIZE;
pRxHead->RDES2 = dwRxBufferStart;
dwRxBufferStart += MAX_BUFFER_SIZE;
if (i == dwRxRingSize - 1)
{
// Last descriptor points to first descriptor...
// And indicates that this is the end of the ring...
pRxHead->RDES1.ReceiveEndOfRing = 1;
pRxHead->RDES3 = TO_REAL((DWORD) pRxDesc);
}
else
{
pRxHead->RDES3 = TO_REAL((DWORD) ((DWORD)pRxHead + sizeof(RX_DESCRIPTOR_FORMAT)));
pRxHead = (PRX_DESCRIPTOR_FORMAT) TO_VIRT(pRxHead->RDES3);
}
}
// DumpRxDescriptor (pRxDesc);
// ==========================================================================
// Set CSRs:
//
// enable the 21143 chip
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -