📄 am79c970.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:
Plain Vanilla Routines for AMD Am79c970a NIC.
This mainly supports initialization and Sending/Receiving Ethernet packets
as well as interrupt handler.
Minimum error handling is provided here...
Functions:
Notes:
Code is meant to be used for ethernet download and debugging only and
is expected to run in Kernel Mode...
--*/
#include <windows.h>
#include <halether.h>
#include <ceddk.h>
#include "am79c970.h"
/////////////////////////////////////////////////////////////////////////////////
// External Functions that must be there...
//
#define localDEBUGMSG EdbgOutputDebugString
//extern void localDEBUGMSG(const unsigned char *sz, ...);
extern DWORD OEMEthGetMSecs (void);
/////////////////////////////////////////////////////////////////////////////////
// Global Variables and defines...
//
#define MAX_BUFFER_SIZE 1536 // 12*128(=max cache line size)
PBYTE pbEthernetBase; // Ethernet IO Base Address...
DWORD dwTRANSMIT_DESCRIPTORS_HEAD; // Start of TX descriptors.
DWORD dwTRANSMIT_BUFFER_START; // Start of TX buffer linked to descriptors.
DWORD dwTRANSMIT_RING_SIZE; // Size of the entire TX ring.
DWORD dwRECEIVE_DESCRIPTORS_HEAD; // Start of RX descriptors.
DWORD dwRECEIVE_BUFFER_START; // Start of RX buffer linked to descriptors.
DWORD dwRECEIVE_RING_SIZE; // Size of the entire RX ring.
static DWORD dwMEM_OFFSET; // When NIC and CPU not having same offset to memory...
volatile PRX_DESCRIPTOR_FORMAT pCurrentRxDesc; // pointer to current RX Descriptor that Rx may use.
volatile PRX_DESCRIPTOR_FORMAT pLastRxDesc; // pointer to Last RX descriptor.
volatile PTX_DESCRIPTOR_FORMAT pCurrentTxDesc; // pointer to current TX Descriptor that Tx may use.
volatile PTX_DESCRIPTOR_FORMAT pLastTxDesc; // pointer to Last TX descriptor.
/////////////////////////////////////////////////////////////////////////////////
// Forward decl...
//
void DumpOneTxDescriptor (PTX_DESCRIPTOR_FORMAT pTxDesc);
void DumpOneRxDescriptor (PRX_DESCRIPTOR_FORMAT pRxDesc);
void DumpTxDescriptors ();
void DumpRxDescriptors ();
void DumpMemory (PBYTE pSource, DWORD dwLength);
void DumpSenderAddr (PBYTE pSource);
/////////////////////////////////////////////////////////////////////////////////
// Misc helper functions...
//
#define SECOND_COMP(x) ((long) (0-(DWORD)x))
//#define TO_REAL(Addr) ((Addr & 0x1fffffff) + dwMEM_OFFSET)
//#define TO_VIRT(Addr) ((Addr | 0xA0000000) - dwMEM_OFFSET)
#define TO_REAL(Addr) (Addr)
#define TO_VIRT(Addr) (Addr)
void SleepLoop (DWORD dwCounter)
{
// Simply loop...
while (dwCounter--)
;
} // SleepLoop()
void WriteCSR (DWORD dwIndex, DWORD dwValue)
{
//localDEBUGMSG (">>> [%d] <-- 0x%x \r\n", dwIndex, dwValue);
WRITE_PORT_ULONG(RAP, dwIndex);
WRITE_PORT_ULONG(RDP, dwValue);
}
DWORD ReadCSR (DWORD dwIndex)
{
DWORD dwRAP;
WRITE_PORT_ULONG(RAP, dwIndex);
dwRAP = READ_PORT_ULONG(RDP);
return dwRAP;
}
void WriteBCR (DWORD dwIndex, DWORD dwValue)
{
WRITE_PORT_ULONG(RAP, dwIndex);
WRITE_PORT_ULONG(BDP, dwValue);
}
DWORD ReadBCR (DWORD dwIndex)
{
DWORD dwBDP;
WRITE_PORT_ULONG(RAP, dwIndex);
dwBDP = READ_PORT_ULONG(BDP);
return dwBDP;
}
PTX_DESCRIPTOR_FORMAT GetNextTxDesc (PTX_DESCRIPTOR_FORMAT pGivenTxDesc)
{
if (pGivenTxDesc == pLastTxDesc)
return (PTX_DESCRIPTOR_FORMAT) dwTRANSMIT_DESCRIPTORS_HEAD;
else
return (PTX_DESCRIPTOR_FORMAT) (pGivenTxDesc + 1);
}
PRX_DESCRIPTOR_FORMAT GetNextRxDesc (PRX_DESCRIPTOR_FORMAT pGivenRxDesc)
{
if (pGivenRxDesc == pLastRxDesc)
return (PRX_DESCRIPTOR_FORMAT) dwRECEIVE_DESCRIPTORS_HEAD;
else
return (PRX_DESCRIPTOR_FORMAT) (pGivenRxDesc + 1);
}
/////////////////////////////////////////////////////////////////////////////////
// InitTxDescriptor initializes a given descriptor pointed to by pTxDesc to
// use buffer pointed to by pBuffer...
//
void InitTxDescriptor (PTX_DESCRIPTOR_FORMAT pTxDesc, DWORD pBuffer)
{
//localDEBUGMSG ("Address: 0x%x --- Buffer 0x%x \r\n", pTxDesc, pBuffer);
pTxDesc->TMD2.dwReg = 0x00; // AMD controls the contents here...
pTxDesc->TMD1.dwReg = 0x00; // Important one is the OWN bit settting.
pTxDesc->TMD1.ALL_ONES = 0xf; // And the MUST BE ONEs field.
pTxDesc->TMD1.BCNT = SECOND_COMP(MAX_BUFFER_SIZE);
if (pBuffer) // Only point to buffer if pBuffer is avail...
pTxDesc->TBADR = TO_REAL(pBuffer); // TX buffer for this descriptor...
} // InitTxDescriptor()
/////////////////////////////////////////////////////////////////////////////////
// InitTxDescriptor initializes a given descriptor pointed to by pRxDesc to
// use buffer pointed to by pBuffer...
//
void InitRxDescriptor (PRX_DESCRIPTOR_FORMAT pRxDesc, DWORD pBuffer)
{
//localDEBUGMSG ("Address: 0x%x --- Buffer 0x%x \r\n", pRxDesc, pBuffer);
pRxDesc->RMD2.dwReg = 0x00; // AMD controls the fields in here...
pRxDesc->RMD1.dwReg = RMD1_DEFAULT; // The goodies...
pRxDesc->RMD1.BCNT = SECOND_COMP(MAX_BUFFER_SIZE); // Main things are the size of buffer + OWN bit.
if (pBuffer)
pRxDesc->RBADR = TO_REAL(pBuffer); // Rx buffer for this descriptor...
} // InitRxDescriptor()
/////////////////////////////////////////////////////////////////////////////////
// AM789C970Init()
// Initializes the NIC.
// pbBaseAddress = IO base address assigned to the NIC.
// dwMemOffset = Can be used if the common memory (for descriptors and mem)
// is not at the same offset as seen between host and NIC.
// MacAddr = Contains the MAC address read from hardware upon successful
// initialization.
//
// Return value:
// TRUE when NIC initialized successfully, FALSE otherwise.
//
//
// Initialization procedure:
// 1. BCR20 (or CSR58) bit 8 (SSIZE32) set to 1 for 32 bit accesses.
// 2. Use Alternative method for Initialization (Appendix C of am79c970a spec).
// 3. Setup Transmit and Receive Descriptor Rings.
//
// x. Finally... Set INIT bit in CSR0 to get am789c970 to start reading the
// initialization block.
//
BOOL AM79C970Init(BYTE *pbBaseAddress, ULONG dwMemOffset, USHORT MacAddr[3])
{
DWORD i;
if (MacAddr == NULL) return FALSE;
localDEBUGMSG ("AM79C970Init:: Init using i/o address: 0x%x - MEM Offset = 0x%x\r\n",
pbBaseAddress, dwMemOffset);
pbEthernetBase = pbBaseAddress;
dwMEM_OFFSET = dwMemOffset;
/////////////////////////////////////////////////////////////////////////////
// Make sure all the tx and rx process stopped.
// I may get to this code because of jumping to reset vector from the
// bootloader flash download...
//
WriteCSR (0, 0x04);
SleepLoop(10000);
/////////////////////////////////////////////////////////////////////////////
// The very first step is to soft reset the controller and invoke
// DWIO (DWord IO) mode (accomplished by writing 32 bit to RDP).
//
/////////////////////////////////////////////////////////////////////////////
// This causes the internal reset, and AMD PCI controller blocks further
// accesses until its internal reset is done (around 1 uS).
ReadWord (RESET_REGISTER);
WriteDword (0x10, 0x00);
SleepLoop(10000000);
/////////////////////////////////////////////////////////////////////////////
// We are in business... First turn is to fix the MAC address required by
// caller...
//
if( NULL != MacAddr ) {
for (i = 0 ; i < 3 ; i++)
MacAddr[i] = ReadWord(i*2);
}
localDEBUGMSG ("+--------------------- BEFORE -------------------------+\r\n");
localDEBUGMSG ("CSR0 == 0x%x \r\n", ReadCSR(0));
localDEBUGMSG ("CSR04 == 0x%x \r\n", ReadCSR(4));
localDEBUGMSG ("CSR15 == 0x%x \r\n", ReadCSR(15));
localDEBUGMSG ("CSR58 == 0x%x \r\n", ReadCSR(58));
localDEBUGMSG ("BCR02 == 0x%x \r\n", ReadBCR(2));
localDEBUGMSG ("BCR9 == 0x%x \r\n", ReadBCR(9));
/////////////////////////////////////////////////////////////////////////////
// Set the software style correctly then proceed with initialization
// explained in appendix c of am79c970a manual.
//
WriteCSR (58, CSR58_SSIZE32 | CSR58_SW_STYLE_PCNET_PCI_II_CONTROLLER); // Software style.
WriteCSR (4, ReadCSR(4) | CSR4_DMA_PLUS | CSR4_APAD_XMIT | CSR4_TXSTRTM); // Must be set for PCNET_PCI_II setting.
WriteBCR (2, ReadBCR(2) | BCR2_ASEL); // Use auto select feature.
WriteCSR (8, 0x00); /////////////////////////////////////////////////////
WriteCSR (9, 0x00); // At this point we don't care about Logical adddr
WriteCSR (10, 0x00); // Filtering
WriteCSR (11, 0x00); //
/////////////////////////////////////////////////////
WriteCSR (12, MacAddr[0]); // Physical Address [15:00]
WriteCSR (13, MacAddr[1]); // Physical Address [31:16]
WriteCSR (14, MacAddr[2]); // Physical Address [47:32]
WriteCSR (15, 0x00); // Turn off Promiscuous mode...
WriteCSR (24, TO_REAL(dwRECEIVE_DESCRIPTORS_HEAD) & 0x0000ffff); // RX descriptor starts...
WriteCSR (25, (TO_REAL(dwRECEIVE_DESCRIPTORS_HEAD) & 0xffff0000) >> 16);
WriteCSR (30, TO_REAL(dwTRANSMIT_DESCRIPTORS_HEAD) & 0x0000ffff); // TX descriptor starts...
WriteCSR (31, (TO_REAL(dwTRANSMIT_DESCRIPTORS_HEAD) & 0xffff0000) >> 16);
WriteCSR (47, (DWORD) SECOND_COMP(0)); // Polling interval, use default...1.966ms
WriteCSR (76, (DWORD) SECOND_COMP(dwRECEIVE_RING_SIZE)); // RX Ring Size...
WriteCSR (78, (DWORD) SECOND_COMP(dwTRANSMIT_RING_SIZE)); // TX Ring Size...
WriteBCR (9, ReadBCR(9) & 0xfffffffe); // Make sure it is half duplex...
WriteCSR (3, ReadCSR(3) | CSR3_MASK_ALL_INTS); // Start off with all interrupt mask...EnableInts() will handle which one to turn on.
/////////////////////////////////////////////////////////////////////////////
// Lets read 'em back for fun... :-)
//
localDEBUGMSG ("+--------------------- AFTERWARDS -------------------------+\r\n");
localDEBUGMSG ("CSR0 == 0x%x \r\n", ReadCSR(0));
localDEBUGMSG ("CSR3 == 0x%x \r\n", ReadCSR(3));
localDEBUGMSG ("CSR04 == 0x%x \r\n", ReadCSR(4));
localDEBUGMSG ("CSR12 == 0x%x \r\n", ReadCSR(12));
localDEBUGMSG ("CSR13 == 0x%x \r\n", ReadCSR(13));
localDEBUGMSG ("CSR14 == 0x%x \r\n", ReadCSR(14));
localDEBUGMSG ("CSR15 == 0x%x \r\n", ReadCSR(15));
localDEBUGMSG ("CSR24 == 0x%x \r\n", ReadCSR(24));
localDEBUGMSG ("CSR25 == 0x%x \r\n", ReadCSR(25));
localDEBUGMSG ("CSR30 == 0x%x \r\n", ReadCSR(30));
localDEBUGMSG ("CSR31 == 0x%x \r\n", ReadCSR(31));
localDEBUGMSG ("CSR47 == 0x%x \r\n", ReadCSR(47));
localDEBUGMSG ("CSR58 == 0x%x \r\n", ReadCSR(58));
localDEBUGMSG ("CSR76 == 0x%x \r\n", ReadCSR(76));
localDEBUGMSG ("CSR78 == 0x%x \r\n", ReadCSR(78));
localDEBUGMSG ("BCR02 == 0x%x \r\n", ReadBCR(2));
localDEBUGMSG ("BCR9 == 0x%x \r\n", ReadBCR(9));
/////////////////////////////////////////////////////////////////////////////
// Initialize TX Descriptors...
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -