📄 mac.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.
//
//------------------------------------------------------------------------------
//
// File: mac.c
//
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <ethdbg.h>
#include <oal.h>
#include <au1.h>
//------------------------------------------------------------------------------
static AU1_MAC_REGS *g_macRegs;
static AU1_MACDMA_REGS *g_dmaRegs;
static AU1_MACEN_REGS *g_enRegs;
static UINT32 g_dmaAddress = 0;
static UINT32 g_dmaSize = 0;
static UINT32 g_enId = 0;
static UINT32 g_rxBufAddr[MAC_RX_BUFFERS];
static UINT32 g_txBufAddr[MAC_TX_BUFFERS];
static UINT32 g_rxPos;
static UINT32 g_txPosUp;
static UINT32 g_txPosDn;
static UINT32 g_txCount;
static UINT16 g_mac[3];
static UINT32 g_hash[2];
static UINT8 g_phy;
//------------------------------------------------------------------------------
static UINT16 PhyRead(UINT8 phy, UINT8 reg)
{
// Wait while MII is busy
while ((INREG32(&g_macRegs->MIICTRL) & MAC_MIICTRL_MB) != 0);
// Set address
OUTREG32(&g_macRegs->MIICTRL, (phy << 11)|(reg << 6));
// Wait while MII is busy
while ((INREG32(&g_macRegs->MIICTRL) & MAC_MIICTRL_MB) != 0);
// Return data
return (UINT16)INREG32(&g_macRegs->MIIDATA);
}
//------------------------------------------------------------------------------
static void PhyWrite(UINT8 phy, UINT8 reg, UINT16 data)
{
// Wait while MII is busy
while ((INREG32(&g_macRegs->MIICTRL) & MAC_MIICTRL_MB) != 0);
// Set data
OUTREG32(&g_macRegs->MIIDATA, data);
// Set address
OUTREG32(&g_macRegs->MIICTRL, (phy << 11)|(reg << 6)|MAC_MIICTRL_MW);
// Wait while MII is busy
while ((INREG32(&g_macRegs->MIICTRL) & MAC_MIICTRL_MB) != 0);
}
//------------------------------------------------------------------------------
static BOOL PhyInit(BOOL *pFullDuplex)
{
BOOL rc = FALSE;
UINT16 id1, id2;
// First find PHY
for (g_phy = 0; g_phy < 32; g_phy++) {
id1 = PhyRead(g_phy, MAC_PHY_PHYIDR1);
if (id1 == 0xFFFF) continue;
id2 = PhyRead(g_phy, MAC_PHY_PHYIDR2);
if (id2 == 0xFFFF) continue;
break;
};
// There is something wrong if we don't find PHY device, leave
if (g_phy >= 32) {
OALMSGS(OAL_ERROR, (L"Au1EdbgInit: Failed to detect PHY device\r\n"));
goto cleanUp;
}
// Wait until link is up
OALLogSerial(L"Au1 MAC: Wait for link...");
PhyRead(g_phy, MAC_PHY_BMSR);
while ((PhyRead(g_phy, MAC_PHY_BMSR) & MAC_PHY_BMSR_LINK) == 0);
OALLogSerial(L" Link detected\r\n");
// Check if final mode is full duplex
*pFullDuplex = (
PhyRead(g_phy, MAC_PHY_ANAR) & PhyRead(g_phy, MAC_PHY_ANLPAR) &
(MAC_PHY_AN_100FD | MAC_PHY_AN_10FD)
) != 0;
// We are done
rc = TRUE;
cleanUp:
return rc;
}
//------------------------------------------------------------------------------
static UINT32 HashAddress(UCHAR* pAddress)
{
UINT32 crc, carry;
UINT i, j;
UCHAR uc;
crc = 0xFFFFFFFF;
for (i = 0; i < MAC_ADDR_SIZE; i++) {
uc = pAddress[i];
for (j = 0; j < 8; j++) {
carry = ((crc & 0x80000000) ? 1 : 0) ^ (uc & 0x01);
crc <<= 1;
uc >>= 1;
if (carry) crc = (crc ^ 0x04c11db7) | carry;
}
}
return crc;
}
//------------------------------------------------------------------------------
static BOOL HWInit()
{
BOOL rc = FALSE;
UINT32 address, i, ctrl;
BOOL fullDuplex;
// Enable clock
OUTREG32(&g_enRegs->MAC[g_enId], MACEN_CE);
// Enable MAC
OUTREG32(&g_enRegs->MAC[g_enId], MACEN_E2 | MACEN_E1 | MACEN_E0 | MACEN_CE);
// Initialize RX structures
address = g_dmaAddress;
for (i = 0; i < MAC_RX_BUFFERS; i++) {
g_rxBufAddr[i] = address;
OUTREG32(
&g_dmaRegs->RX[i].ADDR,
OALVAtoPA((VOID*)address) | MACDMA_ADDR_EN
);
address += MAC_BUFFER_SIZE;
}
g_rxPos = (INREG32(&g_dmaRegs->RX[0].ADDR) & MACDMA_ADDR_CB) >> 2;
// Initialize TX structures
for (i = 0; i < MAC_TX_BUFFERS; i++) {
g_txBufAddr[i] = address;
OUTREG32(&g_dmaRegs->TX[i].STAT, 0);
OUTREG32(&g_dmaRegs->TX[i].ADDR, 0);
address += MAC_BUFFER_SIZE;
}
g_txPosUp = (INREG32(&g_dmaRegs->TX[0].ADDR) & MACDMA_ADDR_CB) >> 2;
g_txPosDn = g_txPosUp;
g_txCount = 0;
// Setup MAC address
OUTREG32(&g_macRegs->ADDRLOW, g_mac[0] |(g_mac[1] << 16));
OUTREG32(&g_macRegs->ADDRHIGH, g_mac[2]);
// Then hast table
OUTREG32(&g_macRegs->HASHLOW, g_hash[0]);
OUTREG32(&g_macRegs->HASHHIGH, g_hash[1]);
// Initialize PHY
if (!(rc = PhyInit(&fullDuplex))) goto cleanUp;
// And enable rx&tx
ctrl = MAC_CTRL_DO|MAC_CTRL_AP|MAC_CTRL_RE|MAC_CTRL_TE;
if (fullDuplex) ctrl |= MAC_CTRL_F;
OUTREG32(&g_macRegs->CTRL, ctrl);
cleanUp:
return rc;
}
//------------------------------------------------------------------------------
BOOL Au1EdbgInitDMABuffer(UINT32 address, UINT32 size)
{
BOOL rc = FALSE;
UINT32 offset;
OALMSGS(OAL_ETHER&&OAL_FUNC, (
L"+Au1EdbgInitDMABuffer(0x%08x, 0x%08x)\r\n", address, size
));
// Buffers must be aligned to 32 bytes boundary
offset = address & 0x1F;
if (offset != 0) {
address = address + 0x20 - offset;
size = size + 0x20 - offset;
}
// Check if buffer is big enough
if (size < MAC_BUFFER_SIZE * (MAC_TX_BUFFERS + MAC_RX_BUFFERS)) {
OALMSGS(OAL_ERROR, (
L"ERROR: Au1EdbgInitDMABuffer: DMA buffer is too small\r\n"
));
goto cleanUp;
}
// Store address and size
g_dmaAddress = (UINT32)OALCAtoUA(address);
g_dmaSize = size;
// Done
rc = TRUE;
cleanUp:
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgInitDMABuffer(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
BOOL Au1EdbgInit(UINT8 *pAddress, UINT32 offset, UINT16 mac[3])
{
BOOL rc = FALSE;
UINT32 address;
OALMSGS(OAL_ETHER&&OAL_FUNC, (
L"+Au1EdbgInit(0x%X, 0x%X, %02x:%02x:%02x:%02x:%02x:%02x)\r\n",
pAddress, offset, mac[0]&0xFF, mac[0]>>8, mac[1]&0xFF, mac[1]>>8,
mac[2]&0xFF, mac[2]>>8
));
// Set device addresses
address = OALVAtoPA(pAddress);
if (address == AU1_MACA0_REGS_PA) {
g_macRegs = (AU1_MAC_REGS*)OALPAtoUA(AU1_MACA0_REGS_PA);
g_dmaRegs = (AU1_MACDMA_REGS*)OALPAtoUA(AU1_MACDMA0_REGS_PA);
g_enRegs = (AU1_MACEN_REGS*)OALPAtoUA(AU1_MACAEN_REGS_PA);
g_enId = 0;
} else if (address == AU1_MACA1_REGS_PA) {
g_macRegs = (AU1_MAC_REGS*)OALPAtoUA(AU1_MACA1_REGS_PA);
g_dmaRegs = (AU1_MACDMA_REGS*)OALPAtoUA(AU1_MACDMA1_REGS_PA);
g_enRegs = (AU1_MACEN_REGS*)OALPAtoUA(AU1_MACAEN_REGS_PA);
g_enId = 1;
} else if (address == AU1_MACB0_REGS_PA) {
g_macRegs = (AU1_MAC_REGS*)OALPAtoUA(AU1_MACB0_REGS_PA);
g_dmaRegs = (AU1_MACDMA_REGS*)OALPAtoUA(AU1_MACDMA0_REGS_PA);
g_enRegs = (AU1_MACEN_REGS*)OALPAtoUA(AU1_MACBEN_REGS_PA);
g_enId = 0;
} else if (address == AU1_MACB1_REGS_PA) {
g_macRegs = (AU1_MAC_REGS*)OALPAtoUA(AU1_MACB1_REGS_PA);
g_dmaRegs = (AU1_MACDMA_REGS*)OALPAtoUA(AU1_MACDMA1_REGS_PA);
g_enRegs = (AU1_MACEN_REGS*)OALPAtoUA(AU1_MACBEN_REGS_PA);
g_enId = 1;
} else {
goto cleanUp;
}
// Save MAC address to global variable
g_mac[0] = mac[0]; g_mac[1] = mac[1]; g_mac[2] = mac[2];
// Start with empty hash table
g_hash[0] = g_hash[1] = 0;
// Initialize hardware
rc = HWInit();
cleanUp:
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgInit(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
VOID Au1EdbgPowerOff()
{
// Disable clock to device
OUTREG32(&g_enRegs->MAC[g_enId], 0);
}
//------------------------------------------------------------------------------
VOID Au1EdbgPowerOn()
{
HWInit();
}
//------------------------------------------------------------------------------
UINT16 Au1EdbgGetFrame(UINT8 *pData, UINT16 *pLength)
{
UINT32 stat, length;
// Let be pesimistic
length = 0;
// When packet is in buffer DN bit is set
while ((INREG32(&g_dmaRegs->RX[g_rxPos].ADDR) & MACDMA_ADDR_DN) != 0) {
// Get result
stat = INREG32(&g_dmaRegs->RX[g_rxPos].STAT);
length = (stat & MACDMA_STATRX_LEN) - 4;
// Copy packet if there is no problem
if ((stat & MACDMA_STATRX_ERR) == 0 && length <= *pLength) {
memcpy(pData, (VOID*)g_rxBufAddr[g_rxPos], length);
} else {
length = 0;
}
// Reinitialize channel
OUTREG32(&g_dmaRegs->RX[g_rxPos].STAT, 0);
OUTREG32(
&g_dmaRegs->RX[g_rxPos].ADDR,
OALVAtoPA((VOID*)g_rxBufAddr[g_rxPos])|MACDMA_ADDR_EN
);
// Move to next possition
if (++g_rxPos >= MAC_RX_BUFFERS) g_rxPos = 0;
// If we get a packet break loop
if (length > 0) break;
}
*pLength = (USHORT)length;
#if 0
// Clear all TxDone
ClearTxDone();
#endif
// Return size
return *pLength;
}
//------------------------------------------------------------------------------
UINT16 Au1EdbgSendFrame(UCHAR *pData, UINT32 length)
{
UINT16 rc = 1;
// Fail when packet is too long...
if (length > MAC_BUFFER_SIZE) goto cleanUp;
if (g_txPosUp != ((INREG32(&g_dmaRegs->TX[0].ADDR) & 0x0C) >> 2)) {
OALMSGS(OAL_ERROR, (
L"Au1EdbgSendFrame: DMA out of sync: %d - 0x%08x\r\n",
g_txPosUp, INREG32(&g_dmaRegs->TX[0].ADDR)
));
}
// Copy packet to buffer
memcpy((PVOID)g_txBufAddr[g_txPosUp], pData, length);
// Set status, length & buffer address
OUTREG32(&g_dmaRegs->TX[g_txPosUp].STAT, 0);
OUTREG32(&g_dmaRegs->TX[g_txPosUp].LEN, length);
OUTREG32(
&g_dmaRegs->TX[g_txPosUp].ADDR,
OALVAtoPA((VOID*)g_txBufAddr[g_txPosUp])|MACDMA_ADDR_EN
);
// Wait until packet is send
while ((INREG32(&g_dmaRegs->TX[g_txPosUp].ADDR) & MACDMA_ADDR_DN) == 0);
OUTREG32(&g_dmaRegs->TX[g_txPosUp].ADDR, 0);
// Move to next possition
if (++g_txPosUp >= MAC_TX_BUFFERS) g_txPosUp = 0;
// And it is done
rc = 0;
cleanUp:
return 0;
}
//------------------------------------------------------------------------------
VOID Au1EdbgEnableInts()
{
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"+Au1EdbgEnableInts\r\n"));
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgEnableInts\r\n"));
}
//------------------------------------------------------------------------------
VOID Au1EdbgDisableInts()
{
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"+Au1EdbgDisableInts\r\n"));
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgDisableInts\r\n"));
}
//------------------------------------------------------------------------------
VOID Au1EdbgCurrentPacketFilter(UINT32 filter)
{
UINT32 ctrl;
OALMSG(OAL_ETHER&&OAL_FUNC, (
L"+Au1EdbgCurrentPacketFilter(0x%08x)\r\n", filter
));
ctrl = INREG32(&g_macRegs->CTRL);
#if 0
if ((filter & PACKET_TYPE_ALL_MULTICAST) != 0) {
ctrl |= MAC_CTRL_PM;
} else {
ctrl &= ~MAC_CTRL_PM;
}
if ((filter & PACKET_TYPE_MULTICAST) != 0) {
ctrl |= MAC_CTRL_HP;
} else {
ctrl &= ~MAC_CTRL_HP;
}
#else
if (
(filter & PACKET_TYPE_ALL_MULTICAST) != 0 ||
(filter & PACKET_TYPE_MULTICAST) != 0
) {
ctrl |= MAC_CTRL_PM;
} else {
ctrl &= ~MAC_CTRL_PM;
}
#endif
if ((filter & PACKET_TYPE_PROMISCUOUS) != 0) {
ctrl |= MAC_CTRL_PR;
} else {
ctrl &= ~MAC_CTRL_PR;
}
OUTREG32(&g_macRegs->CTRL, ctrl);
OALMSG(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgCurrentPacketFilter\r\n"));
}
//------------------------------------------------------------------------------
BOOL Au1EdbgMulticastList(UINT8 *pAddresses, UINT32 count)
{
UINT32 i, crc, bit;
OALMSG(OAL_ETHER&&OAL_FUNC, (
L"+Au1EdbgMulticastList(0x%08x, %d)\r\n", pAddresses, count
));
g_hash[0] = g_hash[1] = 0;
for (i = 0; i < count; i++) {
crc = HashAddress(pAddresses);
bit = crc >> 26;
g_hash[bit >> 5] |= 1 << (bit & 0x1F);
pAddresses += MAC_ADDR_SIZE;
}
OUTREG32(&g_macRegs->HASHHIGH, g_hash[1]);
OUTREG32(&g_macRegs->HASHLOW, g_hash[0]);
OALMSG(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgMulticastList(rc = 1)\r\n"));
return TRUE;
}
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -