本来是看着 Micrel 的 KSZ8842 文档全,U-boot 和 Linux 驱动都有才使用这颗芯片的,没想到它的U-boot驱动是没测试过的,根本不能用。没办法只好根据其文档来修改。
直接贴上修改后的U-boot驱动程序代码,将该文件存放到 drivers/net 目录下,文件名为ks884x.c和ks884x.h,其中ks884x.h基本不用做什么改动,主要是对主机接口的宏根据自己的板子作些调整,如16位或32位接口,有些CPU对内存访问的限制问题等。
可惜不能添加附件,直接贴上修改后的代码。145.6KB,有点大。
/*------------------------------------------------------------------------
. ks884x.c
. This is a driver for Micrel's KS884X Ethernet controller.
.
. (C) Copyright 2006
. Micrel, Inc.
.
. (C) Copyright 2002
. Sysgo Real-Time Solutions, GmbH <www.elinos.com>
. Rolf Offermanns <[email protected]>
.
. This program is free software; you can redistribute it and/or modify
. it under the terms of the GNU General Public License as published by
. the Free Software Foundation; either version 2 of the License, or
. (at your option) any later version.
.
. This program is distributed in the hope that it will be useful,
. but WITHOUT ANY WARRANTY; without even the implied warranty of
. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
. GNU General Public License for more details.
.
. You should have received a copy of the GNU General Public License
. along with this program; if not, write to the Free Software
. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
.
. 09012006 - provide initialization routine for board init
.
----------------------------------------------------------------------------*/
#include <common.h>
#include <command.h>
#include <config.h>
#if defined( CONFIG_DRIVER_KS8841 ) || defined( CONFIG_DRIVER_KS8842 )
#include <net.h>
#if 0
#define DBG
#endif
#if 1
#define INLINE
#endif
#define DEF_LINUX
#define KS_ISA_BUS
#define KS_ISA
#ifdef CONFIG_DRIVER_KS8842
#define DEF_KS8842
#endif
#include "ks884x.h"
#ifndef CONFIG_KS8841_BASE
#define CONFIG_KS8841_BASE 0xb0000300
#endif
#define ETH_ZLEN 60
#define TX_TIMEOUT 5
#ifdef DEF_KS8842
#define DRV_NAME "KS8842"
#else
#define DRV_NAME "KS8841"
#endif
#ifdef SH_32BIT_ACCESS_ONLY
#define BUS_NAME "SH 32-bit only"
#elif defined( SH_32BIT_ALIGNED )
#define BUS_NAME "SH 32-bit"
#else
#define BUS_NAME "SH 16-bit"
#endif
#define DRV_VERSION "1.0.0"
#define DRV_RELDATE "Mar 14, 2006"
static char version[] =
"Micrel " DRV_NAME " " BUS_NAME " " DRV_VERSION " (" DRV_RELDATE ")";
static UCHAR DEFAULT_MAC_ADDRESS[] = { 0x00, 0x10, 0xA1, 0x88, 0x42, 0x01 };
/* -------------------------------------------------------------------------- */
void PrintMacAddress (
PUCHAR bAddr )
{
DBG_PRINT( "%02x:%02x:%02x:%02x:%02x:%02x",
bAddr[ 0 ], bAddr[ 1 ], bAddr[ 2 ],
bAddr[ 3 ], bAddr[ 4 ], bAddr[ 5 ]);
} /* PrintMacAddress */
#if 1
#define LINK_CHECK_FIX
#endif
/* -------------------------------------------------------------------------- */
#ifdef KS_ISA_BUS
ULONG SwapBytes (
ULONG dwData )
{
ULONG dwValue;
PUCHAR pSrc = ( PUCHAR ) &dwData;
PUCHAR pDst = ( PUCHAR ) &dwValue;
pDst[ 0 ] = pSrc[ 3 ];
pDst[ 1 ] = pSrc[ 2 ];
pDst[ 2 ] = pSrc[ 1 ];
pDst[ 3 ] = pSrc[ 0 ];
return( dwValue );
} /* SwapBytes */
#endif
/* -------------------------------------------------------------------------- */
/*
PortConfigGet
Description:
This function checks whether the specified bits of the port register
are set or not.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bPort
The port index.
UCHAR bBank
The bank of the port register.
UCHAR bOffset
The offset of the port register.
UCHAR bBits
ULONG ulBits
The data bits to check.
Return (BOOLEAN):
TRUE if the bits are set; otherwise FALSE.
*/
#ifdef KS_PCI_BUS
BOOLEAN PortConfigGet_PCI (
#else
BOOLEAN PortConfigGet_ISA (
#endif
PHARDWARE pHardware,
UCHAR bPort,
#ifdef KS_ISA_BUS
UCHAR bBank,
#endif
UCHAR bOffset,
UCHAR bBits )
{
UCHAR bData;
#ifdef KS_PCI_BUS
ULONG ulAddr;
PORT_CTRL_ADDR( bPort, ulAddr );
ulAddr += bOffset;
HW_READ_BYTE( pHardware, ulAddr, &bData );
#else
HardwareSelectBank( pHardware, ( UCHAR )( bBank + bPort *
PORT_BANK_INTERVAL ));
HW_READ_BYTE( pHardware, bOffset, &bData );
#endif
if ( ( bData & bBits ) == bBits )
return TRUE;
else
return FALSE;
} /* PortConfigGet */
/*
PortConfigSet
Description:
This routine sets or resets the specified bits of the port register.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bPort
The port index.
UCHAR bBank
The bank of the port register.
UCHAR bOffset
The offset of the port register.
UCHAR bBits
ULONG ulBits
The data bits to set.
BOOLEAN fSet
The flag indicating whether the bits are to be set or not.
Return (None):
*/
#ifdef KS_PCI_BUS
void PortConfigSet_PCI (
#else
void PortConfigSet_ISA (
#endif
PHARDWARE pHardware,
UCHAR bPort,
#ifdef KS_ISA_BUS
UCHAR bBank,
#endif
UCHAR bOffset,
#ifdef SH_16BIT_WRITE
USHORT bBits,
#else
UCHAR bBits,
#endif
BOOLEAN fSet )
{
#ifdef KS_PCI_BUS
ULONG ulAddr;
UCHAR bData;
PORT_CTRL_ADDR( bPort, ulAddr );
ulAddr += bOffset;
HW_READ_BYTE( pHardware, ulAddr, &bData );
if ( fSet )
bData |= bBits;
else
bData &= ~bBits;
HW_WRITE_BYTE( pHardware, ulAddr, bData );
#else
#ifdef SH_16BIT_WRITE
USHORT RegData;
UCHAR bShift = bOffset & 1;
bOffset &= ~1;
bBits <<= ( bShift << 3 );
HardwareSelectBank( pHardware, ( UCHAR )( bBank + bPort *
PORT_BANK_INTERVAL ));
HW_READ_WORD( pHardware, bOffset, &RegData );
if ( fSet )
RegData |= bBits;
else
RegData &= ~bBits;
HW_WRITE_WORD( pHardware, bOffset, RegData );
#else
UCHAR bData;
HardwareSelectBank( pHardware, ( UCHAR )( bBank + bPort *
PORT_BANK_INTERVAL ));
HW_READ_BYTE( pHardware, bOffset, &bData );
if ( fSet )
bData |= bBits;
else
bData &= ~bBits;
HW_WRITE_BYTE( pHardware, bOffset, bData );
#endif
#endif
} /* PortConfigSet */
#ifdef KS_PCI_BUS_
/*
PortConfigGetShift
Description:
This function checks whether the specified bits of the port register
are set or not.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bPort
The port index.
ULONG ulOffset
The offset of the port register.
UCHAR bShift
Number of bits to shift.
Return (BOOLEAN):
TRUE if the bits are set; otherwise FALSE.
*/
BOOLEAN PortConfigGetShift (
PHARDWARE pHardware,
UCHAR bPort,
ULONG ulOffset,
UCHAR bShift )
{
ULONG ulData;
ULONG ulBits = 1UL << bPort;
HW_READ_DWORD( pHardware, ulOffset, &ulData );
ulData >>= bShift;
if ( ( ulData & ulBits ) == ulBits )
return TRUE;
else
return FALSE;
} /* PortConfigGetShift */
/*
PortConfigSetShift
Description:
This routine sets or resets the specified bits of the port register.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bPort
The port index.
ULONG ulOffset
The offset of the port register.
UCHAR bShift
Number of bits to shift.
BOOLEAN fSet
The flag indicating whether the bits are to be set or not.
Return (None):
*/
void PortConfigSetShift (
PHARDWARE pHardware,
UCHAR bPort,
ULONG ulOffset,
UCHAR bShift,
BOOLEAN fSet )
{
ULONG ulData;
ULONG ulBits = 1UL << bPort;
HW_READ_DWORD( pHardware, ulOffset, &ulData );
ulBits <<= bShift;
if ( fSet )
ulData |= ulBits;
else
ulData &= ~ulBits;
HW_WRITE_DWORD( pHardware, ulOffset, ulData );
} /* PortConfigSetShift */
#endif
/*
PortConfigReadByte
Description:
This routine reads a byte from the port register.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bPort
The port index.
UCHAR bBank
The bank of the port register.
UCHAR bOffset
The offset of the port register.
PUCHAR pbData
Buffer to store the data.
Return (None):
*/
#ifdef KS_PCI_BUS
void PortConfigReadByte_PCI
#else
void PortConfigReadByte_ISA
#endif
(
PHARDWARE pHardware,
UCHAR bPort,
#ifdef KS_ISA_BUS
UCHAR bBank,
#endif
UCHAR bOffset,
PUCHAR pbData )
{
#ifdef KS_PCI_BUS
ULONG ulAddr;
PORT_CTRL_ADDR( bPort, ulAddr );
ulAddr += bOffset;
HW_READ_BYTE( pHardware, ulAddr, pbData );
#else
HardwareSelectBank( pHardware, ( UCHAR )( bBank + bPort *
PORT_BANK_INTERVAL ));
HW_READ_BYTE( pHardware, bOffset, pbData );
#endif
} /* PortConfigReadByte */
/*
PortConfigWriteByte
Description:
This routine writes a byte to the port register.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bPort
The port index.
UCHAR bBank
The bank of the port register.
UCHAR bOffset
The offset of the port register.
UCHAR bData
Data to write.
Return (None):
*/
#ifdef KS_PCI_BUS
void PortConfigWriteByte_PCI
#else
void PortConfigWriteByte_ISA
#endif
(
PHARDWARE pHardware,
UCHAR bPort,
#ifdef KS_ISA_BUS
UCHAR bBank,
#endif
UCHAR bOffset,
UCHAR bData )
{
#ifdef KS_PCI_BUS
ULONG ulAddr;
PORT_CTRL_ADDR( bPort, ulAddr );
ulAddr += bOffset;
HW_WRITE_BYTE( pHardware, ulAddr, bData );
#else
#ifdef SH_16BIT_WRITE
ASSERT( FALSE );
#endif
HardwareSelectBank( pHardware, ( UCHAR )( bBank + bPort *
PORT_BANK_INTERVAL ));
HW_WRITE_BYTE( pHardware, bOffset, bData );
#endif
} /* PortConfigWriteByte */
/*
PortConfigReadWord
Description:
This routine reads a word from the port register.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bPort
The port index.
UCHAR bBank
The bank of the port register.
UCHAR bOffset
The offset of the port register.
PUSHORT pwData
Buffer to store the data.
Return (None):
*/
#ifdef KS_PCI_BUS
void PortConfigReadWord_PCI
#else
void PortConfigReadWord_ISA
#endif
(
PHARDWARE pHardware,
UCHAR bPort,
#ifdef KS_ISA_BUS
UCHAR bBank,
#endif
UCHAR bOffset,
PUSHORT pwData )
{
#ifdef KS_PCI_BUS
ULONG ulAddr;
PORT_CTRL_ADDR( bPort, ulAddr );
ulAddr += bOffset;
HW_READ_WORD( pHardware, ulAddr, pwData );
#else
HardwareSelectBank( pHardware, ( UCHAR )( bBank + bPort *
PORT_BANK_INTERVAL ));
HW_READ_WORD( pHardware, bOffset, pwData );
#endif
} /* PortConfigReadWord */
/*
PortConfigWriteWord
Description:
This routine writes a word to the port register.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bPort
The port index.
UCHAR bBank
The bank of the port register.
UCHAR bOffset
The offset of the port register.
USHORT usData
Data to write.
Return (None):
*/
#ifdef KS_PCI_BUS
void PortConfigWriteWord_PCI
#else
void PortConfigWriteWord_ISA
#endif
(
PHARDWARE pHardware,
UCHAR bPort,
#ifdef KS_ISA_BUS
UCHAR bBank,
#endif
UCHAR bOffset,
USHORT usData )
{
#ifdef KS_PCI_BUS
ULONG ulAddr;
PORT_CTRL_ADDR( bPort, ulAddr );
ulAddr += bOffset;
HW_WRITE_WORD( pHardware, ulAddr, usData );
#else
HardwareSelectBank( pHardware, ( UCHAR )( bBank + bPort *
PORT_BANK_INTERVAL ));
HW_WRITE_WORD( pHardware, bOffset, usData );
#endif
} /* PortConfigWriteWord */
/* -------------------------------------------------------------------------- */
/*
SwitchGetAddress
Description:
This function retrieves the MAC address of the switch.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
PUCHAR MacAddr
Buffer to store the MAC address.
Return (None):
*/
#ifdef KS_PCI_BUS
void SwitchGetAddress_PCI (
#else
void SwitchGetAddress_ISA (
#endif
PHARDWARE pHardware,
PUCHAR MacAddr )
{
int i;
ASSERT( pHardware->m_bAcquire );
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_MAC_ADDR_BANK );
#endif
for ( i = 0; i < MAC_ADDRESS_LENGTH; i++ )
{
HW_READ_BYTE( pHardware, ( ULONG )( REG_MAC_ADDR_0_OFFSET + i ),
&MacAddr[ MAC_ADDR_ORDER( i )]);
}
} /* SwitchGetAddress */
/*
SwitchSetAddress
Description:
This function configures the MAC address of the switch.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
PUCHAR MacAddr
The MAC address.
Return (None):
*/
#ifdef KS_PCI_BUS
void SwitchSetAddress_PCI (
#else
void SwitchSetAddress_ISA (
#endif
PHARDWARE pHardware,
PUCHAR MacAddr )
{
int i;
ASSERT( pHardware->m_bAcquire );
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_MAC_ADDR_BANK );
#endif
for ( i = 0; i < MAC_ADDRESS_LENGTH; i++ )
{
#ifdef SH_16BIT_WRITE
if ( ( i & 1 ) )
{
HW_WRITE_WORD( pHardware, (( REG_MAC_ADDR_0_OFFSET + i ) & ~1 ),
( MacAddr[ MAC_ADDR_ORDER( i )] << 8 ) |
MacAddr[ MAC_ADDR_ORDER( i - 1 )]);
}
#else
HW_WRITE_BYTE( pHardware, ( ULONG )( REG_MAC_ADDR_0_OFFSET + i ),
MacAddr[ MAC_ADDR_ORDER( i )]);
#endif
}
} /* SwitchSetAddress */
/*
SwitchGetLinkStatus
Description:
This routine reads PHY registers to determine the current link status
of the switch ports.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void SwitchGetLinkStatus_PCI (
#else
void SwitchGetLinkStatus_ISA (
#endif
PHARDWARE pHardware )
{
PPORT_INFO pInfo;
#ifdef KS_PCI_BUS
ULONG InterruptMask;
#ifdef DEF_KS8841
ULONG Enable;
#endif
#else
USHORT InterruptMask;
#ifdef DEF_KS8841
USHORT Enable;
#endif
#endif
int change = FALSE;
UCHAR bData;
UCHAR bStatus;
UCHAR bLinkStatus;
UCHAR bPort;
/* Save the current interrupt mask and block all interrupts. */
InterruptMask = HardwareBlockInterrupt( pHardware );
#ifdef DEF_KS8842
for ( bPort = 0; bPort < SWITCH_PORT_NUM; bPort++ )
#else
bPort = 0;
#endif
{
pInfo = &pHardware->m_PortInfo[ bPort ];
/* Read Port Control Register */
PortConfigReadByte( pHardware, bPort,
#ifdef KS_ISA_BUS
REG_PORT_LINK_CTRL_BANK,
#endif
REG_PORT_CTRL_4_OFFSET, &bData );
/* Clean previous latch Port Operation Status Register */
PortConfigReadByte( pHardware, bPort,
#ifdef KS_ISA_BUS
REG_PORT_LINK_STATUS_BANK,
#endif
REG_PORT_STATUS_HI_OFFSET, &bStatus );
/* Read Port Operation Status Register */
PortConfigReadByte( pHardware, bPort,
#ifdef KS_ISA_BUS
REG_PORT_LINK_STATUS_BANK,
#endif
REG_PORT_STATUS_HI_OFFSET, &bStatus );
#ifdef LINK_CHECK_FIX
/* bStatus is changing all the time even when there is no cable
connection!
*/
#endif
/* Clean previous latch Port Link Status Register */
PortConfigReadByte( pHardware, bPort,
#ifdef KS_ISA_BUS
REG_PORT_LINK_STATUS_BANK,
#endif
REG_PORT_STATUS_OFFSET, &bLinkStatus );
/* Read Port Link Status Register */
PortConfigReadByte( pHardware, bPort,
#ifdef KS_ISA_BUS
REG_PORT_LINK_STATUS_BANK,
#endif
REG_PORT_STATUS_OFFSET, &bLinkStatus );
#ifdef LINK_CHECK_FIX
/* bLinkStatus is changing all the time even when there is no cable
connection!
*/
bLinkStatus &=
PORT_AUTO_NEG_COMPLETE |
PORT_STATUS_LINK_GOOD;
if ( ( bLinkStatus & (UCHAR)PORT_STATUS_LINK_GOOD ) )
{
if ( MediaStateConnected != pInfo->ulHardwareState )
change = TRUE;
pInfo->ulHardwareState = MediaStateConnected;
}
else
{
if ( MediaStateDisconnected != pInfo->ulHardwareState )
change = TRUE;
pInfo->ulHardwareState = MediaStateDisconnected;
}
#endif
if ( bData != pInfo->bAdvertised ||
bLinkStatus != pInfo->bLinkPartner )
{
#ifndef LINK_CHECK_FIX
pInfo->ulHardwareState = MediaStateDisconnected;
if ( ( bLinkStatus & (UCHAR)PORT_STATUS_LINK_GOOD ) )
pInfo->ulHardwareState = MediaStateConnected;
#endif
#ifdef DBG
DBG_PRINT( "advertised: %02X - %02X; partner: %02X - %02X"
NEWLINE, bData, pInfo->bAdvertised, bLinkStatus,
pInfo->bLinkPartner );
#endif
change = TRUE;
pInfo->ulSpeed = 100000;
#if 1
if ( ( bStatus & (UCHAR)PORT_STAT_SPEED_100MBIT ) )
pInfo->ulSpeed = 1000000;
#else
if ( (( bData & PORT_AUTO_NEG_100BTX ) &&
( bLinkStatus & PORT_REMOTE_100BTX )) ||
(( bData & PORT_AUTO_NEG_100BTX_FD ) &&
( bLinkStatus & PORT_REMOTE_100BTX_FD )) )
pInfo->ulSpeed = 1000000;
#endif
pInfo->bDuplex = 1;
#if 1
if ( ( bStatus & (UCHAR)PORT_STAT_FULL_DUPLEX ) )
pInfo->bDuplex = 2;
#else
if ( (( bData & PORT_AUTO_NEG_100BTX_FD ) &&
( bLinkStatus & PORT_REMOTE_100BTX_FD )) ||
(( bData & PORT_AUTO_NEG_10BT_FD ) &&
( bLinkStatus & PORT_REMOTE_10BT_FD ) &&
( !( bData & PORT_AUTO_NEG_100BTX ) ||
!( bLinkStatus & PORT_REMOTE_100BTX ))) )
pInfo->bDuplex = 2;
#endif
pInfo->bAdvertised = bData;
pInfo->bLinkPartner = bLinkStatus;
}
}
/* Restore the interrupt mask. */
HardwareSetInterrupt( pHardware, InterruptMask );
if ( change )
{
PPORT_INFO pLinked = NULL;
#ifdef DEF_KS8842
for ( bPort = 0; bPort < SWITCH_PORT_NUM; bPort++ )
#else
bPort = 0;
#endif
{
pInfo = &pHardware->m_PortInfo[ bPort ];
if ( MediaStateConnected == pInfo->ulHardwareState )
{
if ( !pLinked )
pLinked = pInfo;
#if ( defined( DEF_LINUX ) || defined( _WIN32 )) && defined( DBG )
DBG_PRINT( "link %d: %d, %d"NEWLINE, bPort,
( int ) pInfo->ulSpeed,
( int ) pInfo->bDuplex );
#endif /* #ifdef DEF_LINUX */
}
else
{
#if ( defined( DEF_LINUX ) || defined( _WIN32 )) && defined( DBG )
DBG_PRINT( "link %d disconnected"NEWLINE, bPort );
#endif /* #ifdef DEF_LINUX */
}
} /* for ( bPort = 0; bPort < SWITCH_PORT_NUM; bPort++ ) */
if ( pLinked )
pInfo = pLinked;
else
pInfo = &pHardware->m_PortInfo[ 0 ];
#ifndef DEF_KS8842
/* Set QMU Flow Control for KS8841 only */
if ( MediaStateConnected == pInfo->ulHardwareState )
{
if ( 1 == pInfo->bDuplex )
{
#ifdef KS_PCI_BUS
if ( ( pHardware->m_dwTransmitConfig &
DMA_TX_CTRL_FLOW_ENABLE ) )
{
pHardware->m_dwTransmitConfig &= ~DMA_TX_CTRL_FLOW_ENABLE;
}
#else
if ( ( pHardware->m_wTransmitConfig &
TX_CTRL_FLOW_ENABLE ) )
{
pHardware->m_wTransmitConfig &= ~TX_CTRL_FLOW_ENABLE;
}
#endif
}
else if ( 2 == pInfo->bDuplex )
{
#ifdef KS_PCI_BUS
#if FLOWCONTROL_DEFAULT
pHardware->m_dwTransmitConfig |= DMA_TX_CTRL_FLOW_ENABLE;
#else
pHardware->m_dwTransmitConfig &= ~DMA_TX_CTRL_FLOW_ENABLE;
#endif
#else
pHardware->m_wTransmitConfig &= ~TX_CTRL_FLOW_ENABLE;
#endif
}
#ifdef KS_PCI_BUS
HW_READ_DWORD( pHardware, REG_DMA_TX_CTRL, &Enable );
if ( ( Enable & DMA_TX_CTRL_ENABLE ) &&
(( Enable ^ pHardware->m_dwTransmitConfig ) &
DMA_TX_CTRL_FLOW_ENABLE ) )
{
HW_WRITE_DWORD( pHardware, REG_DMA_TX_CTRL,
pHardware->m_dwTransmitConfig );
}
#else
HardwareReadRegWord( pHardware, REG_TX_CTRL_BANK,
REG_TX_CTRL_OFFSET, &Enable );
if ( ( Enable & TX_CTRL_ENABLE ) &&
(( Enable ^ pHardware->m_wTransmitConfig ) &
TX_CTRL_FLOW_ENABLE ) )
{
HardwareWriteRegWord( pHardware, REG_TX_CTRL_BANK,
REG_TX_CTRL_OFFSET, pHardware->m_wTransmitConfig );
}
#endif
} /* if ( MediaStateConnected == pInfo->ulHardwareState ) */
#endif /*#ifndef DEF_KS8842 */
pHardware->m_ulHardwareState = pInfo->ulHardwareState;
pHardware->m_ulTransmitRate = pInfo->ulSpeed;
pHardware->m_ulDuplex = pInfo->bDuplex;
} /* if ( change ) */
} /* SwitchGetLinkStatus */
#define PHY_RESET_TIMEOUT 10
/*
SwitchSetLinkSpeed
Description:
This routine sets the link speed of the switch ports.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void SwitchSetLinkSpeed_PCI (
#else
void SwitchSetLinkSpeed_ISA (
#endif
PHARDWARE pHardware )
{
USHORT usData;
UCHAR bPort;
#ifdef DEF_KS8842
for ( bPort = 0; bPort < SWITCH_PORT_NUM; bPort++ )
#else
bPort = 0;
#endif
{
/* Enable Flow control in the full duplex mode */
PortConfigForceFlowCtrl ( pHardware, bPort, TRUE );
/* Enable Back pressure in the half duplex mode */
PortConfigBackPressure ( pHardware, bPort, TRUE );
/* Read Port Control register 4 (PnCR4) */
PortConfigReadWord( pHardware, bPort,
#ifdef KS_ISA_BUS
REG_PORT_LINK_CTRL_BANK,
#endif
REG_PORT_CTRL_4_OFFSET, &usData );
usData |= PORT_AUTO_NEG_ENABLE;
usData |= PORT_AUTO_NEG_SYM_PAUSE;
usData |= PORT_AUTO_NEG_100BTX_FD | PORT_AUTO_NEG_100BTX |
PORT_AUTO_NEG_10BT_FD | PORT_AUTO_NEG_10BT;
/* Check if manual configuration is specified by the user. */
if ( pHardware->m_bSpeed || pHardware->m_bDuplex )
{
if ( 10 == pHardware->m_bSpeed )
{
usData &= ~( PORT_AUTO_NEG_100BTX_FD | PORT_AUTO_NEG_100BTX );
}
else if ( 100 == pHardware->m_bSpeed )
{
usData &= ~( PORT_AUTO_NEG_10BT_FD | PORT_AUTO_NEG_10BT );
}
if ( 1 == pHardware->m_bDuplex )
{
usData &= ~( PORT_AUTO_NEG_100BTX_FD | PORT_AUTO_NEG_10BT_FD );
}
else if ( 2 == pHardware->m_bDuplex )
{
usData &= ~( PORT_AUTO_NEG_100BTX | PORT_AUTO_NEG_10BT );
}
}
/* Write Port Control register 4 (PnCR4) */
PortConfigWriteWord( pHardware, bPort,
#ifdef KS_ISA_BUS
REG_PORT_LINK_CTRL_BANK,
#endif
REG_PORT_CTRL_4_OFFSET, usData );
/* Restart Port auto-negotiation */
usData |= TO_HI_BYTE( PORT_AUTO_NEG_RESTART );
PortConfigWriteWord( pHardware, bPort,
#ifdef KS_ISA_BUS
REG_PORT_LINK_CTRL_BANK,
#endif
REG_PORT_CTRL_4_OFFSET, usData );
}
} /* SwitchSetLinkSpeed */
/*
SwitchSetGlobalControl
Description:
This routine sets the global control of the switch function.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void SwitchSetGlobalControl_PCI (
#else
void SwitchSetGlobalControl_ISA (
#endif
PHARDWARE pHardware )
{
USHORT RegData = 0;
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_SWITCH_CTRL_BANK );
#endif
/*
* Set Switch Global Control Register 3 SGCR3
*/
/* Enable Switch MII Flow Control */
HW_READ_WORD( pHardware, REG_SWITCH_CTRL_3_OFFSET, &RegData );
RegData |= SWITCH_FLOW_CTRL;
HW_WRITE_WORD( pHardware, REG_SWITCH_CTRL_3_OFFSET, RegData );
/*
* Set Switch Global Control Register 1 SGCR1
*/
HW_READ_WORD( pHardware, REG_SWITCH_CTRL_1_OFFSET, &RegData );
/* Enable Aggressive back off algorithm in half duplex mode */
RegData |= SW_BACKOFF_EN;
#ifdef AUTO_FAST_AGING
/* Enable automic fast aging when link changed detected */
RegData |= SW_AUTO_FAST_AGING;
#endif
HW_WRITE_WORD( pHardware, REG_SWITCH_CTRL_1_OFFSET, RegData );
/*
* Set Switch Global Control Register 2 SGCR2
*/
/* Enable No excessive collision drop */
HW_READ_WORD( pHardware, REG_SWITCH_CTRL_2_OFFSET, &RegData );
RegData |= SW_NO_COLLISION_DROP;
HW_WRITE_WORD( pHardware, REG_SWITCH_CTRL_2_OFFSET, RegData );
} /* SwitchSetGlobalControl */
#ifdef DEF_KS8842
/*
* SwitchEnable
* This function is used to enable/disable Switch Engine.
* Only KS8842 has switch function.
*
* Argument(s)
* pHardware Pointer to hardware instance.
* fEnable 1: enable switch, 0: disable switch
*
* Return(s)
* NONE.
*/
#ifdef KS_PCI_BUS
void SwitchEnable_PCI
#else
void SwitchEnable_ISA
#endif
(
PHARDWARE pHardware,
BOOLEAN fEnable
)
{
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_SWITCH_CTRL_BANK );
#endif
/* High byte is read-only. */
if (fEnable)
{
HW_WRITE_WORD( pHardware, REG_CHIP_ID_OFFSET, (UCHAR)SWITCH_START );
}
else
HW_WRITE_WORD( pHardware, REG_CHIP_ID_OFFSET, 0 );
}
#endif /* #ifdef DEF_KS8842 */
/* -------------------------------------------------------------------------- */
#ifdef KS_ISA_BUS
#ifndef INLINE
/*
HardwareSelectBank
Description:
This routine changes the bank of registers and keeps track of current
bank.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bBank
The new bank of registers.
Return (None):
*/
void HardwareSelectBank (
PHARDWARE pHardware,
UCHAR bBank )
{
#ifdef SH_16BIT_WRITE
HW_WRITE_WORD( pHardware, (UCHAR)REG_BANK_SEL_OFFSET, bBank );
#else
HW_WRITE_BYTE( pHardware, (UCHAR)REG_BANK_SEL_OFFSET, bBank );
#endif
pHardware->m_bBank = bBank;
} /* HardwareSelectBank */
/*
HardwareReadRegByte
Description:
This routine reads a byte from specified bank and register. It calls
HardwareSelectBank if the bank is different than the current bank.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bBank
The bank of registers.
UCHAR bOffset
The register offset.
PUCHAR pbData
Pointer to byte to store the data.
Return (None):
*/
void HardwareReadRegByte (
PHARDWARE pHardware,
UCHAR bBank,
UCHAR bOffset,
PUCHAR pbData )
{
if ( bBank != pHardware->m_bBank )
{
HardwareSelectBank( pHardware, bBank );
}
HW_READ_BYTE( pHardware, bOffset, pbData );
} /* HardwareReadRegByte */
/*
HardwareWriteRegByte
Description:
This routine writess a byte to specific bank and register. It calls
HardwareSelectBank if the bank is different than the current bank.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bBank
The bank of registers.
UCHAR bOffset
The register offset.
UCHAR bValue
The data value.
Return (None):
*/
void HardwareWriteRegByte (
PHARDWARE pHardware,
UCHAR bBank,
UCHAR bOffset,
UCHAR bValue )
{
if ( bBank != pHardware->m_bBank )
{
HardwareSelectBank( pHardware, bBank );
}
HW_WRITE_BYTE( pHardware, bOffset, bValue );
} /* HardwareWriteRegByte */
/*
HardwareReadRegWord
Description:
This routine reads a word from specified bank and register. It calls
HardwareSelectBank if the bank is different than the current bank.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bBank
The bank of registers.
UCHAR bOffset
The register offset.
PUSHORT pwData
Pointer to word to store the data.
Return (None):
*/
void HardwareReadRegWord (
PHARDWARE pHardware,
UCHAR bBank,
UCHAR bOffset,
PUSHORT pwData )
{
if ( bBank != pHardware->m_bBank )
{
HardwareSelectBank( pHardware, bBank );
}
HW_READ_WORD( pHardware, bOffset, pwData );
} /* HardwareReadRegWord */
/*
HardwareWriteRegWord
Description:
This routine writess a word to specific bank and register. It calls
HardwareSelectBank if the bank is different than the current bank.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bBank
The bank of registers.
UCHAR bOffset
The register offset.
USHORT wValue
The data value.
Return (None):
*/
void HardwareWriteRegWord (
PHARDWARE pHardware,
UCHAR bBank,
UCHAR bOffset,
USHORT wValue )
{
if ( bBank != pHardware->m_bBank )
{
HardwareSelectBank( pHardware, bBank );
}
HW_WRITE_WORD( pHardware, bOffset, wValue );
} /* HardwareWriteRegWord */
/*
HardwareReadRegDWord
Description:
This routine reads a double word (32-bit) from specified bank and register. It calls
HardwareSelectBank if the bank is different than the current bank.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bBank
The bank of registers.
UCHAR bOffset
The register offset.
PULONG pwData
Pointer to long to store the data.
Return (None):
*/
void HardwareReadRegDWord (
PHARDWARE pHardware,
UCHAR bBank,
UCHAR bOffset,
PULONG pwData )
{
if ( bBank != pHardware->m_bBank )
{
HardwareSelectBank( pHardware, bBank );
}
HW_READ_DWORD( pHardware, bOffset, pwData );
} /* HardwareReadRegDWord */
/*
HardwareWriteRegDWord
Description:
This routine writess a double word (32-bit) to specific bank and register. It calls
HardwareSelectBank if the bank is different than the current bank.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bBank
The bank of registers.
UCHAR bOffset
The register offset.
ULONG wValue
The data value.
Return (None):
*/
void HardwareWriteRegDWord (
PHARDWARE pHardware,
UCHAR bBank,
UCHAR bOffset,
ULONG wValue )
{
if ( bBank != pHardware->m_bBank )
{
HardwareSelectBank( pHardware, bBank );
}
HW_WRITE_DWORD( pHardware, bOffset, wValue );
} /* HardwareWriteRegDWord */
#ifdef SH_32BIT_ACCESS_ONLY
void HardwareWriteIntMask (
PHARDWARE pHardware,
ULONG ulValue )
{
if ( REG_INT_MASK_BANK != pHardware->m_bBank )
{
HardwareSelectBank( pHardware, REG_INT_MASK_BANK );
}
HW_WRITE_DWORD( pHardware, REG_INT_MASK_OFFSET, ulValue );
} /* HardwareWriteIntMask */
void HardwareWriteIntStat (
PHARDWARE pHardware,
ULONG ulValue )
{
ULONG ulIntEnable;
if ( REG_INT_STATUS_BANK != pHardware->m_bBank )
{
HardwareSelectBank( pHardware, REG_INT_STATUS_BANK );
}
HW_READ_DWORD( pHardware, REG_INT_MASK_OFFSET, &ulIntEnable );
ulIntEnable &= 0x0000FFFF;
ulIntEnable |= ulValue;
HW_WRITE_DWORD( pHardware, REG_INT_MASK_OFFSET, ulIntEnable );
} /* HardwareWriteIntStat */
#endif
#endif /* #ifndef INLINE */
/* -------------------------------------------------------------------------- */
/*
HardwareReadBuffer
Description:
This routine is used to read data into a buffer if the operating system
does not provide one.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bOffset
The register offset.
PULONG pdwData
Pointer to word buffer.
USHORT wLength
The length of the buffer.
Return (None):
*/
void HardwareReadBuffer (
PHARDWARE pHardware,
UCHAR bOffset,
PULONG pdwData,
int length )
{
int lengthInDWord = length >> 2;
int remainLengthInByte = length % 4;
HardwareSelectBank( pHardware, REG_DATA_BANK );
while ( lengthInDWord--)
{
HW_READ_DWORD( pHardware, bOffset, pdwData++ );
}
if ( remainLengthInByte > 0 )
{
HW_READ_DWORD( pHardware, bOffset, pdwData++ );
}
} /* HardwareReadBuffer */
/*
HardwareWriteBuffer
Description:
This routine is used to write data from a buffer if the operating system
does not provide one.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bOffset
The register offset.
PULONG pdwData
Pointer to word buffer.
USHORT wLength
The length of the buffer.
Return (None):
*/
void HardwareWriteBuffer (
PHARDWARE pHardware,
UCHAR bOffset,
PULONG pdwData,
int length )
{
int lengthInDWord = length >> 2;
int remainLengthInByte = length % 4;
HardwareSelectBank( pHardware, REG_DATA_BANK );
while ( lengthInDWord-- )
{
HW_WRITE_DWORD( pHardware, bOffset, *pdwData++ );
}
if ( remainLengthInByte > 0 )
{
HW_WRITE_DWORD( pHardware, bOffset, *pdwData++ );
}
} /* HardwareWriteBuffer */
#endif /* #ifdef KS_ISA_BUS */
/* -------------------------------------------------------------------------- */
#define PHY_STAT_SPEED_100MBIT ( PORT_STAT_SPEED_100MBIT << 8 )
#define PHY_STAT_FULL_DUPLEX ( PORT_STAT_FULL_DUPLEX << 8 )
/* Generic Bus Interface */
#define HW_READ_PHY_CTRL( phwi, phy, data ) /
HW_READ_WORD( phwi, REG_PHY_CTRL_OFFSET, &data )
#define HW_WRITE_PHY_CTRL( phwi, phy, data ) /
HW_WRITE_WORD( phwi, REG_PHY_CTRL_OFFSET, data )
#define HW_READ_PHY_LINK_STATUS( phwi, phy, data ) /
HW_READ_WORD( phwi, REG_PHY_STATUS_OFFSET, &data )
#define HW_READ_PHY_AUTO_NEG( phwi, phy, data ) /
HW_READ_WORD( phwi, REG_PHY_AUTO_NEG_OFFSET, &data )
#define HW_WRITE_PHY_AUTO_NEG( phwi, phy, data ) /
HW_WRITE_WORD( phwi, REG_PHY_AUTO_NEG_OFFSET, data )
#define HW_READ_PHY_REM_CAP( phwi, phy, data ) /
HW_READ_WORD( phwi, REG_PHY_REMOTE_CAP_OFFSET, &data )
#define HW_READ_PHY_CROSSOVER( phwi, phy, data ) /
HW_READ_WORD( phwi, REG_PHY_CTRL_OFFSET, &data )
#define HW_WRITE_PHY_CROSSOVER( phwi, phy, data ) /
HW_WRITE_WORD( phwi, REG_PHY_CTRL_OFFSET, data )
#define HW_READ_PHY_POLARITY( phwi, phy, data ) /
HW_READ_WORD( phwi, REG_PHY_PHY_CTRL_1_OFFSET + phy * /
PHY_SPECIAL_INTERVAL, &data )
#define HW_READ_PHY_LINK_MD( phwi, phy, data ) /
HW_READ_WORD( phwi, REG_PHY_LINK_MD_1_OFFSET + phy * /
PHY_SPECIAL_INTERVAL, &data )
#define HW_WRITE_PHY_LINK_MD( phwi, phy, data ) /
HW_WRITE_WORD( phwi, REG_PHY_LINK_MD_1_OFFSET + phy * /
PHY_SPECIAL_INTERVAL, data )
/* -------------------------------------------------------------------------- */
#if defined( KS_ISA_BUS ) && defined( DBG )
void DisplayRegisters (
PHARDWARE pHardware )
{
UCHAR b;
UCHAR i;
USHORT RegData;
UCHAR bBank[ 54 ];
memset( bBank, 0, 54 );
bBank[ 1 ] = 1;
for ( b = 4; b < 16; b++ )
bBank[ b ] = 1;
for ( b = 20; b < 32; b++ )
bBank[ b ] = 1;
for ( b = 0; b < 54; b++ )
{
if ( bBank[ b ] )
continue;
DBG_PRINT( "bank %2d: ", b );
for ( i = 0; i < 0x0E; i += 2 )
{
HardwareReadRegWord( pHardware, b, i, &RegData );
DBG_PRINT( "%04X ", RegData );
}
DBG_PRINT( NEWLINE );
}
} /* DisplayRegisters */
#endif
/*
HardwareInitialize
Description:
This function checks the hardware is correct for this driver and resets
the hardware for proper initialization.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (BOOLEAN):
TRUE if successful; otherwise, FALSE.
*/
#ifdef KS_PCI_BUS
BOOLEAN HardwareInitialize_PCI
#else
BOOLEAN HardwareInitialize_ISA
#endif
(
PHARDWARE pHardware )
{
USHORT RegData;
/*
* Set Bus Speed to 125MHz
*/
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_BUS_CTRL_BANK );
#endif
HW_WRITE_WORD ( pHardware, REG_BUS_CTRL_OFFSET, BUS_SPEED_125_MHZ );
/*
* Check ks884x Chip ID
*/
{
#ifdef KS_ISA_BUS
HardwareReadRegWord( pHardware,
(UCHAR)REG_SWITCH_CTRL_BANK,
(UCHAR)REG_CHIP_ID_OFFSET,
(PUSHORT)&RegData
);
#else
HW_READ_WORD( pHardware, REG_CHIP_ID_OFFSET, &RegData );
#endif
#ifdef DBG
DBG_PRINT( "id: %X"NEWLINE, RegData );
#endif
#ifdef DEF_KS8841
if ( ( RegData & SWITCH_CHIP_ID_MASK_41 ) != REG_CHIP_ID_41 )
#else
if ( ( RegData & SWITCH_CHIP_ID_MASK_41 ) != REG_CHIP_ID_42 )
#endif
{
#ifdef DEBUG_COUNTER
pHardware->m_nBad[ COUNT_BAD_CMD_WRONG_CHIP ]+=1;
#endif
return FALSE;
}
#if defined( KS_ISA_BUS ) && defined( DBG_ )
DisplayRegisters( pHardware );
#endif
return( TRUE );
}
#ifdef DEBUG_COUNTER
pHardware->m_nBad[ COUNT_BAD_CMD_INITIALIZE ]+=1;
#endif
return FALSE;
} /* HardwareInitialize */
/*
HardwareReadChipID
Description:
This function read family/chip ID, and device revision ID.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return: none
*/
void HardwareReadChipID
(
PHARDWARE pHardware,
PUSHORT pChipID,
PUCHAR pDevRevisionID
)
{
USHORT RegData;
/* Read ks884x Chip ID */
#ifdef KS_ISA_BUS
HardwareReadRegWord( pHardware,
(UCHAR)REG_SWITCH_CTRL_BANK,
(UCHAR)REG_CHIP_ID_OFFSET,
(PUSHORT)&RegData
);
#else
HW_READ_WORD( pHardware, REG_CHIP_ID_OFFSET, &RegData );
#endif
*pChipID = RegData & SWITCH_CHIP_ID_MASK;
*pDevRevisionID = RegData & SWITCH_REVISION_MASK;
} /* HardwareReadChipID */
/*
HardwareReset
Description:
This function resets the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (BOOLEAN):
TRUE if successful; otherwise, FALSE.
*/
#ifdef KS_PCI_BUS
BOOLEAN HardwareReset_PCI
#else
BOOLEAN HardwareReset_ISA
#endif
(
PHARDWARE pHardware )
{
/* Write 1 to reset device */
#ifdef KS_ISA_BUS
HardwareWriteRegWord( pHardware, REG_GLOBAL_CTRL_BANK,
REG_GLOBAL_CTRL_OFFSET, GLOBAL_SOFTWARE_RESET );
#endif
#ifdef KS_PCI_BUS
HW_WRITE_WORD( pHardware,
REG_GLOBAL_CTRL_OFFSET, GLOBAL_SOFTWARE_RESET );
#endif
/* Wait for device to reset */
DelayMillisec( 10 );
/* Write 0 to clear device reset */
#ifdef KS_ISA_BUS
HardwareWriteRegWord( pHardware, REG_GLOBAL_CTRL_BANK,
REG_GLOBAL_CTRL_OFFSET, 0 );
#endif
#ifdef KS_PCI_BUS
HW_WRITE_WORD( pHardware,
REG_GLOBAL_CTRL_OFFSET, 0 );
#endif
#ifdef DEBUG_COUNTER
pHardware->m_nGood[ COUNT_GOOD_CMD_RESET ]+=1;
#endif
return TRUE;
} /* HardwareReset */
#ifdef KS_ISA_BUS
/*
HardwareSetBurst
Description:
This function is to setup Burst mode with its burst length.
Note: The burst length should be the same as Host's burst length.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR wBurstLength
burst length (0, 4, 8,16).
Return (BOOLEAN):
TRUE successful; otherwise, FALSE.
*/
BOOLEAN HardwareSetBurst (
PHARDWARE pHardware,
UCHAR bBurstLength )
{
USHORT RegData;
switch (bBurstLength)
{
case 0:
RegData = BURST_LENGTH_0 ;
break;
case 4:
RegData = BURST_LENGTH_4 ;
break;
case 8:
RegData = BURST_LENGTH_8 ;
break;
case 16:
RegData = BURST_LENGTH_16 ;
break;
default:
return (FALSE);
}
HardwareWriteRegWord( pHardware, REG_BUS_BURST_BANK, REG_BUS_BURST_OFFSET,
RegData );
return (TRUE);
} /* HardwareSetBurst */
#endif /* #ifdef KS_ISA_BUS */
/*
HardwareSetup
Description:
This routine setup the hardware for proper operation.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareSetup_PCI
#else
void HardwareSetup_ISA
#endif
(
PHARDWARE pHardware )
{
#if defined( DEF_KS8841 ) && ( defined( EARLY_TRANSMIT ) || defined( EARLY_RECEIVE ))
USHORT RegData;
#endif
/*
* Initialize Tx/Rx control setting.
*/
/* KS_PCI_BUS */
#ifdef KS_PCI_BUS
/* Setup Transmit Control */
#ifdef DEBUG_HARDWARE_SETUP
DBG_PRINT( "HardwareSetup_PCI(): Initialize Tx/Rx control setting"NEWLINE );
#endif
pHardware->m_dwTransmitConfig = ( DMA_TX_CTRL_PAD_ENABLE | DMA_TX_CTRL_CRC_ENABLE |
(PBL_DEFAULT << 24) | DMA_TX_CTRL_ENABLE );
#if FLOWCONTROL_DEFAULT
pHardware->m_dwTransmitConfig |= DMA_TX_CTRL_FLOW_ENABLE;
#else
pHardware->m_dwTransmitConfig &= ~DMA_TX_CTRL_FLOW_ENABLE;
#endif
#if TXCHECKSUM_DEFAULT
/* Hardware cannot handle UDP packet in IP fragments. */
pHardware->m_dwTransmitConfig |= (DMA_TX_CTRL_CSUM_TCP | DMA_TX_CTRL_CSUM_IP);
#else
pHardware->m_dwTransmitConfig &= ~(DMA_TX_CTRL_CSUM_UDP | DMA_TX_CTRL_CSUM_TCP | DMA_TX_CTRL_CSUM_IP);
#endif /* TXCHECKSUM_DEFAULT */
#if 0
pHardware->m_dwTransmitConfig |= DMA_TX_CTRL_LOOPBACK;
#endif
/* Setup Receive Control */
pHardware->m_dwReceiveConfig = ( DMA_RX_CTRL_BROADCAST | DMA_RX_CTRL_UNICAST |
(PBL_DEFAULT << 24) | DMA_RX_CTRL_ENABLE );
#if FLOWCONTROL_DEFAULT
pHardware->m_dwReceiveConfig |= DMA_RX_CTRL_FLOW_ENABLE;
#else
pHardware->m_dwReceiveConfig &= ~DMA_RX_CTRL_FLOW_ENABLE;
#endif
#if RXCHECKSUM_DEFAULT
/* Hardware cannot handle UDP packet in IP fragments. */
pHardware->m_dwReceiveConfig |= (DMA_RX_CTRL_CSUM_TCP | DMA_RX_CTRL_CSUM_IP);
#else
pHardware->m_dwReceiveConfig &= ~(DMA_RX_CTRL_CSUM_UDP | DMA_RX_CTRL_CSUM_TCP | DMA_RX_CTRL_CSUM_IP);
#endif
pHardware->m_dwReceiveConfig |= DMA_RX_CTRL_MULTICAST;
if ( pHardware->m_bAllMulticast )
pHardware->m_dwReceiveConfig |= DMA_RX_CTRL_ALL_MULTICAST;
if ( pHardware->m_bPromiscuous )
pHardware->m_dwReceiveConfig |= DMA_RX_CTRL_PROMISCUOUS;
#ifdef CHECK_RCV_ERRORS
pHardware->m_dwReceiveConfig |= DMA_RX_CTRL_ERROR;
#endif
#else /* #ifdef KS_ISA_BUS */
/* KS_ISA_BUS */
/* Setup Transmit Control */
pHardware->m_wTransmitConfig = TX_CTRL_PAD_ENABLE | TX_CTRL_ENABLE;
#if 0
pHardware->m_wTransmitConfig |= TX_CTRL_EPH_LOOPBACK;
#endif
pHardware->m_wTransmitConfig |= ( TX_CTRL_CRC_ENABLE | TX_CTRL_FLOW_ENABLE );
/* Setup Transmit Frame Data Pointer Auto-Increment */
HardwareWriteRegWord( pHardware, REG_TX_ADDR_PTR_BANK,
REG_TX_ADDR_PTR_OFFSET, ADDR_PTR_AUTO_INC | 0 );
#if defined (EARLY_TRANSMIT) && defined(DEF_KS8841)
/* Setup Early Transmit function */
pHardware->m_wTransmitThreshold = EARLY_TX_MULTIPLE;
HardwareReadRegWord( pHardware, REG_EARLY_TX_BANK, REG_EARLY_TX_OFFSET,
&RegData );
RegData &= ~EARLY_TX_THRESHOLD;
RegData |= pHardware->m_wTransmitThreshold / EARLY_TX_MULTIPLE;
RegData |= EARLY_TX_ENABLE;
HardwareWriteRegWord( pHardware, REG_EARLY_TX_BANK, REG_EARLY_TX_OFFSET,
RegData );
#endif /* #ifdef EARLY_TRANSMIT */
/* Setup Receive Control */
pHardware->m_wReceiveConfig = RX_CTRL_STRIP_CRC | RX_CTRL_ENABLE;
pHardware->m_wReceiveConfig |= ( RX_CTRL_UNICAST | RX_CTRL_BROADCAST | RX_CTRL_FLOW_ENABLE );
pHardware->m_wReceiveConfig |= RX_CTRL_MULTICAST;
if ( pHardware->m_bAllMulticast )
pHardware->m_wReceiveConfig |= RX_CTRL_ALL_MULTICAST;
if ( pHardware->m_bPromiscuous )
pHardware->m_wReceiveConfig |= RX_CTRL_PROMISCUOUS;
/* Setup Receive Frame Data Pointer Auto-Increment */
HardwareWriteRegWord( pHardware, REG_RX_ADDR_PTR_BANK,
REG_RX_ADDR_PTR_OFFSET, ADDR_PTR_AUTO_INC | 0 );
/* Setup Receive High Water Mark to 2KBytes to avoid loss packets (big packet size) under flow control */
HardwareWriteRegWord( pHardware, REG_RX_WATERMARK_BANK,
REG_RX_WATERMARK_OFFSET, RX_HIGH_WATERMARK_2KB );
#if defined (EARLY_RECEIVE) && defined(DEF_KS8841)
/* Setup Early Receive function */
pHardware->m_wReceiveThreshold = EARLY_RX_MULTIPLE;
HardwareReadRegWord( pHardware, REG_EARLY_RX_BANK, REG_EARLY_RX_OFFSET,
&RegData );
RegData &= ~EARLY_RX_THRESHOLD;
RegData |= pHardware->m_wReceiveThreshold / EARLY_RX_MULTIPLE;
RegData |= EARLY_RX_ENABLE;
HardwareWriteRegWord( pHardware, REG_EARLY_RX_BANK, REG_EARLY_RX_OFFSET,
RegData );
#endif /* #if defined ( EARLY_RECEIVE ) && defined( DEF_KS8841 ) */
#endif /* #ifdef KS_PCI_BUS */
/*
* Initialize Port control setting.
*/
SwitchSetGlobalControl( pHardware );
/* Enable WOL by detection of magic packet */
HardwareEnableWolMagicPacket ( pHardware );
HardwareClearWolPMEStatus ( pHardware );
} /* HardwareSetup */
/*
HardwareSwitchSetup
Description:
This routine setup the hardware Switch engine for default operation.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareSwitchSetup
(
PHARDWARE pHardware )
{
/*
* Initialize Port control setting.
*/
SwitchSetLinkSpeed( pHardware );
#ifdef DEF_KS8842
SwitchEnable( pHardware, TRUE );
#endif /* #ifdef DEF_KS8842 */
} /* HardwareSwitchSetup */
/*
HardwareSetupInterrupt
Description:
This routine setup the interrupt mask for proper operation.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareSetupInterrupt_PCI
#else
void HardwareSetupInterrupt_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
pHardware->m_ulInterruptMask = INT_MASK;
pHardware->m_ulInterruptMask |= INT_PHY;
pHardware->m_ulInterruptMask |= INT_RX_OVERRUN;
#else
pHardware->m_wInterruptMask = INT_MASK;
pHardware->m_wInterruptMask |= INT_PHY;
#ifdef DBG
pHardware->m_wInterruptMask |= INT_RX_ERROR;
#endif
#if defined (EARLY_RECEIVE) && defined(DEF_KS8841)
pHardware->m_wInterruptMask |= ( INT_RX_EARLY );
#endif
#if defined (EARLY_TRANSMIT) && defined(DEF_KS8841)
pHardware->m_wInterruptMask |= INT_TX_UNDERRUN;
#endif
#if defined( DEF_LINUX ) && defined( DBG )
pHardware->m_wInterruptMask |= INT_RX_OVERRUN;
#endif
/* Acknowledge PHY interrupt after PHY reset. */
HardwareAcknowledgeInterrupt( pHardware, INT_PHY );
#endif
} /* HardwareSetupInterrupt */
/*
HardwareClearCounters
Description:
This routine resets all hardware counters to zero.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#if defined( KS_ISA_BUS ) || !defined( KS_ISA )
void HardwareClearCounters (
PHARDWARE pHardware )
{
memset(( void* ) pHardware->m_cnCounter, 0,
SWITCH_PORT_NUM * ( sizeof( ULONGLONG ) * OID_COUNTER_LAST ) );
#if 0
PortInitCounters( pHardware, pHardware->m_bPortSelect );
#endif
} /* HardwareClearCounters */
#endif
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*
Link processing primary routines
*/
#ifndef INLINE
/*
HardwareAcknowledgeLink
Description:
This routine acknowledges the link change interrupt.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareAcknowledgeLink_PCI
#else
void HardwareAcknowledgeLink_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_STATUS, INT_PHY );
#else
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntStat( pHardware, INT_STATUS( INT_PHY ));
#else
HardwareWriteRegWord( pHardware, REG_INT_STATUS_BANK, REG_INT_STATUS_OFFSET,
INT_PHY );
#endif
#endif
} /* HardwareAcknowledgeLink */
#endif
/*
HardwareCheckLink
Description:
This routine checks the link status.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareCheckLink_PCI
#else
void HardwareCheckLink_ISA
#endif
(
PHARDWARE pHardware )
{
SwitchGetLinkStatus( pHardware );
} /* HardwareCheckLink */
/* -------------------------------------------------------------------------- */
/*
Receive processing primary routines
*/
#ifndef INLINE
/*
HardwareReleaseReceive
Description:
This routine release the receive packet memory.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareReleaseReceive_PCI
#else
void HardwareReleaseReceive_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_ISA_BUS
#ifdef SH_16BIT_WRITE
HardwareWriteRegWord( pHardware, REG_RXQ_CMD_BANK, REG_RXQ_CMD_OFFSET,
RXQ_CMD_FREE_PACKET );
#else
HardwareWriteRegByte( pHardware, REG_RXQ_CMD_BANK, REG_RXQ_CMD_OFFSET,
RXQ_CMD_FREE_PACKET );
#endif
#endif /* KS_ISA_BUS */
} /* HardwareReleaseReceive */
/*
HardwareAcknowledgeReceive
Description:
This routine acknowledges the receive interrupt.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareAcknowledgeReceive_PCI
#else
void HardwareAcknowledgeReceive_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_STATUS, INT_RX );
#else
/* Acknowledge the Receive interrupt. */
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntStat( pHardware, INT_STATUS( INT_RX ));
#else
HardwareWriteRegWord( pHardware, REG_INT_STATUS_BANK, REG_INT_STATUS_OFFSET,
INT_RX );
#endif
#endif
} /* HardwareAcknowledgeReceive */
#endif
/*
HardwareStartReceive
Description:
This routine starts the receive function of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareStartReceive_PCI
#else
void HardwareStartReceive_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
HW_WRITE_DWORD( pHardware, REG_DMA_RX_CTRL,
pHardware->m_dwReceiveConfig );
/* Notify when the receive stops. */
pHardware->m_ulInterruptMask |= INT_RX_STOPPED;
HW_WRITE_DWORD( pHardware, REG_DMA_RX_START, DMA_START );
pHardware->m_bReceiveStop++;
/* Variable overflows. */
if ( 0 == pHardware->m_bReceiveStop )
pHardware->m_bReceiveStop = 2;
#else
HardwareWriteRegWord( pHardware, REG_RX_CTRL_BANK, REG_RX_CTRL_OFFSET,
pHardware->m_wReceiveConfig );
/* Clear the receive stopped interrupt status. */
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntStat( pHardware, INT_STATUS( INT_RX_STOPPED ));
#else
HardwareWriteRegWord( pHardware, REG_INT_STATUS_BANK,
REG_INT_STATUS_OFFSET, INT_RX_STOPPED );
#endif
#ifdef DBG
/* Notify when the receive stops. */
pHardware->m_wInterruptMask |= INT_RX_STOPPED;
#endif
#endif
} /* HardwareStartReceive */
/*
HardwareStopReceive
Description:
This routine stops the receive function of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareStopReceive_PCI
#else
void HardwareStopReceive_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
pHardware->m_bReceiveStop = 0;
HW_WRITE_DWORD( pHardware, REG_DMA_RX_CTRL,
(pHardware->m_dwReceiveConfig & ~DMA_RX_CTRL_ENABLE ) );
#else
/* Interrupt will always trigger if not stopped. */
HardwareTurnOffInterrupt( pHardware, INT_RX_STOPPED );
HardwareDisableInterruptBit( pHardware, INT_RX_STOPPED );
HardwareWriteRegWord( pHardware, REG_RX_CTRL_BANK, REG_RX_CTRL_OFFSET,
0 );
#endif
} /* HardwareStopReceive */
/* -------------------------------------------------------------------------- */
/*
Transmit processing primary routines
*/
#ifndef INLINE
/*
HardwareAcknowledgeTransmit
Description:
This routine acknowledges the trasnmit interrupt.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareAcknowledgeTransmit_PCI
#else
void HardwareAcknowledgeTransmit_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_STATUS, INT_TX );
#else
/* Acknowledge the interrupt and remove the packet from TX FIFO. */
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntStat( pHardware, INT_STATUS( INT_TX ));
#else
HardwareWriteRegWord( pHardware, REG_INT_STATUS_BANK, REG_INT_STATUS_OFFSET,
INT_TX );
#endif
#endif
} /* HardwareAcknowledgeTransmit */
#endif
/*
HardwareStartTransmit
Description:
This routine starts the transmit function of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareStartTransmit_PCI
#else
void HardwareStartTransmit_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
HW_WRITE_DWORD( pHardware, REG_DMA_TX_CTRL,
pHardware->m_dwTransmitConfig );
#ifdef DEVELOP
{
PTDescInfo pDescInfo = &pHardware->m_TxDescInfo;
ULONG ulIntStatus;
int i;
int timeout;
PTDesc pCurrent = pDescInfo->pRing;
/* Find out the current descriptor pointed by hardware. */
for ( i = 0; i < pDescInfo->cnAlloc - 1; i++ )
{
/* This descriptor will be skipped. */
pCurrent->phw->BufSize.ulData = 0;
pCurrent->sw.Control.tx.fHWOwned = TRUE;
pCurrent->phw->Control.ulData =
CPU_TO_LE32( pCurrent->sw.Control.ulData );
pCurrent++;
}
/* Stop at the last descriptor. */
pCurrent->sw.Control.tx.fHWOwned = FALSE;
pCurrent->phw->Control.ulData =
CPU_TO_LE32( pCurrent->sw.Control.ulData );
/* Let the hardware goes through the descriptors. */
HW_WRITE_DWORD( pHardware, REG_DMA_TX_START, DMA_START );
timeout = 10;
do {
DelayMillisec( 10 );
HardwareReadInterrupt( pHardware, &ulIntStatus );
} while ( !( ulIntStatus & INT_TX_EMPTY ) && timeout-- );
if ( !( ulIntStatus & INT_TX_EMPTY ) ) {
DBG_PRINT( "Tx not working! Reset the hardware!"NEWLINE );
}
/* Acknowledge the interrupt. */
HardwareAcknowledgeEmpty( pHardware );
/* Last descriptor */
pCurrent->sw.BufSize.tx.wBufSize = 0;
pCurrent->phw->BufSize.ulData =
CPU_TO_LE32( pCurrent->sw.BufSize.ulData );
pCurrent->sw.Control.tx.fHWOwned = TRUE;
pCurrent->phw->Control.ulData = CPU_TO_LE32( pCurrent->sw.Control.ulData );
/* First descriptor */
pCurrent = pDescInfo->pRing;
pCurrent->sw.Control.tx.fHWOwned = FALSE;
pCurrent->phw->Control.ulData =
CPU_TO_LE32( pCurrent->sw.Control.ulData );
/* Let the hardware goes to the first descriptor. */
HW_WRITE_DWORD( pHardware, REG_DMA_TX_START, DMA_START );
timeout = 10;
do {
DelayMillisec( 10 );
HardwareReadInterrupt( pHardware, &ulIntStatus );
} while ( !( ulIntStatus & INT_TX_EMPTY ) && timeout-- );
if ( !( ulIntStatus & INT_TX_EMPTY ) ) {
DBG_PRINT( "Tx not working! Reset the hardware!"NEWLINE );
}
/* Acknowledge the interrupt. */
HardwareAcknowledgeEmpty( pHardware );
/* Reset all the descriptors. */
pCurrent = pDescInfo->pRing;
for ( i = 0; i < pDescInfo->cnAlloc; i++ )
{
pCurrent->sw.Control.tx.fHWOwned = FALSE;
pCurrent->phw->Control.ulData =
CPU_TO_LE32( pCurrent->sw.Control.ulData );
pCurrent++;
}
pDescInfo->pCurrent = pDescInfo->pRing;
}
#endif
#else
HardwareWriteRegWord( pHardware, REG_TX_CTRL_BANK, REG_TX_CTRL_OFFSET,
pHardware->m_wTransmitConfig );
/* Clear the transmit stopped interrupt status. */
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntStat( pHardware, INT_STATUS( INT_TX_STOPPED ));
#else
HardwareWriteRegWord( pHardware, REG_INT_STATUS_BANK,
REG_INT_STATUS_OFFSET, INT_TX_STOPPED );
#endif
#endif
} /* HardwareStartTransmit */
/*
HardwareStopTransmit
Description:
This routine stops the transmit function of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareStopTransmit_PCI
#else
void HardwareStopTransmit_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
HW_WRITE_DWORD( pHardware, REG_DMA_TX_CTRL,
(pHardware->m_dwTransmitConfig & ~DMA_TX_CTRL_ENABLE ) );
#else
HardwareWriteRegWord( pHardware, REG_TX_CTRL_BANK, REG_TX_CTRL_OFFSET,
0 );
#endif
} /* HardwareStopTransmit */
/* -------------------------------------------------------------------------- */
/*
Interrupt processing primary routines
*/
#ifndef INLINE
/*
HardwareAcknowledgeInterrupt
Description:
This routine acknowledges the specified interrupts.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
USHORT wInterrupt
ULONG ulInterrupt
The interrupt masks to be acknowledged.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareAcknowledgeInterrupt_PCI
#else
void HardwareAcknowledgeInterrupt_ISA
#endif
(
PHARDWARE pHardware,
#ifdef KS_PCI_BUS
ULONG ulInterrupt )
#else
USHORT wInterrupt )
#endif
{
#ifdef KS_PCI_BUS
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_STATUS, ulInterrupt );
#else
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntStat( pHardware, INT_STATUS( wInterrupt ));
#else
HardwareWriteRegWord( pHardware, REG_INT_STATUS_BANK, REG_INT_STATUS_OFFSET,
wInterrupt );
#endif
#endif
} /* HardwareAcknowledgeInterrupt */
/*
HardwareDisableInterrupt
Description:
This routine disables the interrupts of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareDisableInterrupt_PCI
#else
void HardwareDisableInterrupt_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_ENABLE, 0 );
pHardware->m_ulInterruptSet = 0;
#else
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntMask( pHardware, 0 );
#else
HardwareWriteRegWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
0 );
#endif
#endif
} /* HardwareDisableInterrupt */
/*
HardwareEnableInterrupt
Description:
This routine enables the interrupts of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareEnableInterrupt_PCI
#else
void HardwareEnableInterrupt_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
pHardware->m_ulInterruptSet = pHardware->m_ulInterruptMask;
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_ENABLE,
pHardware->m_ulInterruptMask );
#else
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntMask( pHardware, pHardware->m_wInterruptMask );
#else
HardwareWriteRegWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
pHardware->m_wInterruptMask );
#endif
#endif
} /* HardwareEnableInterrupt */
/*
HardwareDisableInterruptBit
Description:
This routine disables the individual interrupt bit of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
USHORT wInterrupt
ULONG ulInterrupt
The interrupt masks bit to be disabled.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareDisableInterruptBit_PCI
#else
void HardwareDisableInterruptBit_ISA
#endif
(
PHARDWARE pHardware,
#ifdef KS_PCI_BUS
ULONG ulInterrupt
#else
USHORT wInterrupt
#endif
)
{
#ifdef KS_PCI_BUS
ULONG ulReadInterrupt;
HW_READ_DWORD( pHardware, REG_INTERRUPTS_ENABLE,
&ulReadInterrupt );
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_ENABLE,
( ulReadInterrupt & ~ulInterrupt) );
#else
#ifdef SH_32BIT_ACCESS_ONLY
ULONG dwReadInterrupt;
HardwareReadRegDWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
&dwReadInterrupt );
dwReadInterrupt &= 0x0000FFFF;
dwReadInterrupt &= ~wInterrupt;
HW_WRITE_DWORD( pHardware, REG_INT_MASK_OFFSET, dwReadInterrupt );
#else
USHORT wReadInterrupt;
HardwareReadRegWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
&wReadInterrupt );
HardwareWriteRegWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
(USHORT) (wReadInterrupt & ~wInterrupt) );
#endif
#endif
} /* HardwareDisableInterruptBit */
/*
HardwareEnableInterruptBit
Description:
This routine enables the individual interrupt bit of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
USHORT wInterrupt
ULONG ulInterrupt
The interrupt masks bit to be enabled.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareEnableInterruptBit_PCI
#else
void HardwareEnableInterruptBit_ISA
#endif
(
PHARDWARE pHardware,
#ifdef KS_PCI_BUS
ULONG ulInterrupt
#else
USHORT wInterrupt
#endif
)
{
#ifdef KS_PCI_BUS
ULONG ulReadInterrupt;
HW_READ_DWORD( pHardware, REG_INTERRUPTS_ENABLE,
&ulReadInterrupt );
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_ENABLE,
( ulReadInterrupt | ulInterrupt) );
#else
#ifdef SH_32BIT_ACCESS_ONLY
ULONG dwReadInterrupt;
HardwareReadRegDWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
&dwReadInterrupt );
dwReadInterrupt &= 0x0000FFFF;
dwReadInterrupt |= wInterrupt;
HW_WRITE_DWORD( pHardware, REG_INT_MASK_OFFSET, dwReadInterrupt );
#else
USHORT wReadInterrupt;
HardwareReadRegWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
&wReadInterrupt );
HardwareWriteRegWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
(USHORT) (wReadInterrupt | wInterrupt) );
#endif
#endif
} /* HardwareEnableInterruptBit */
/*
HardwareReadInterrupt
Description:
This routine reads the current interrupts of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
PUSHORT pwStatus
PULONG pulStatus
Buffer to store the interrupt mask.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareReadInterrupt_PCI
#else
void HardwareReadInterrupt_ISA
#endif
(
PHARDWARE pHardware,
#ifdef KS_PCI_BUS
PULONG pulStatus )
#else
PUSHORT pwStatus )
#endif
{
#ifdef KS_PCI_BUS
HW_READ_DWORD( pHardware, REG_INTERRUPTS_STATUS, pulStatus );
#else
HardwareReadRegWord( pHardware, REG_INT_STATUS_BANK, REG_INT_STATUS_OFFSET,
pwStatus );
#endif
} /* HardwareReadInterrupt */
/*
HardwareSetInterrupt
Description:
This routine enables the specified interrupts of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
USHORT wInterrupt
ULONG ulInterrupt
The interrupt mask to enable.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareSetInterrupt_PCI
#else
void HardwareSetInterrupt_ISA
#endif
(
PHARDWARE pHardware,
#ifdef KS_PCI_BUS
ULONG ulInterrupt )
#else
USHORT wInterrupt )
#endif
{
#ifdef KS_PCI_BUS
pHardware->m_ulInterruptSet = ulInterrupt;
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_ENABLE, ulInterrupt );
#else
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntMask( pHardware, wInterrupt );
#else
HardwareWriteRegWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
wInterrupt );
#endif
#endif
} /* HardwareSetInterrupt */
#endif
/*
HardwareBlockInterrupt
Description:
This function blocks all interrupts of the hardware and returns the
current interrupt enable mask so that interrupts can be restored later.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (USHORT):
Return (ULONG):
The current interrupt enable mask.
*/
#ifdef KS_PCI_BUS
ULONG HardwareBlockInterrupt_PCI
#else
USHORT HardwareBlockInterrupt_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
ULONG Interrupt;
HW_READ_DWORD( pHardware, REG_INTERRUPTS_ENABLE, &Interrupt );
#else
USHORT Interrupt;
HardwareReadRegWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
&Interrupt );
#endif
HardwareDisableInterrupt( pHardware );
return( Interrupt );
} /* HardwareBlockInterrupt */
/* -------------------------------------------------------------------------- */
/*
Other interrupt primary routines
*/
#ifndef INLINE
/*
HardwareTurnOffInterrupt
Description:
This routine turns off the specified interrupts in the interrupt mask
so that those interrupts will not be enabled.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
USHORT wInterruptBit
ULONG ulInterruptBit
The interrupt bits to be off.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareTurnOffInterrupt_PCI
#else
void HardwareTurnOffInterrupt_ISA
#endif
(
PHARDWARE pHardware,
#ifdef KS_PCI_BUS
ULONG ulInterruptBit )
#else
USHORT wInterruptBit )
#endif
{
#ifdef KS_PCI_BUS
pHardware->m_ulInterruptMask &= ~ulInterruptBit;
#else
pHardware->m_wInterruptMask &= ~wInterruptBit;
#endif
} /* HardwareTurnOffInterrupt */
#endif
/*
HardwareTurnOnInterrupt
Description:
This routine turns on the specified interrupts in the interrupt mask so
that those interrupts will be enabled.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
USHORT wInterruptBit
ULONG ulInterruptBit
The interrupt bits to be on.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareTurnOnInterrupt_PCI
#else
void HardwareTurnOnInterrupt_ISA
#endif
(
PHARDWARE pHardware,
#ifdef KS_PCI_BUS
ULONG ulInterruptBit,
PULONG pulInterruptMask )
#else
USHORT wInterruptBit,
PUSHORT pwInterruptMask )
#endif
{
#ifdef KS_PCI_BUS
pHardware->m_ulInterruptMask |= ulInterruptBit;
/* An interrupt mask is previously retrieved to be set later. */
if ( pulInterruptMask )
{
*pulInterruptMask |= ulInterruptBit;
}
else
{
pHardware->m_ulInterruptSet = pHardware->m_ulInterruptMask;
HW_WRITE_DWORD( pHardware, REG_INTERRUPTS_ENABLE,
pHardware->m_ulInterruptMask );
}
#else
pHardware->m_wInterruptMask |= wInterruptBit;
/* An interrupt mask is previously retrieved to be set later. */
if ( pwInterruptMask )
{
*pwInterruptMask |= wInterruptBit;
}
else
{
#ifdef SH_32BIT_ACCESS_ONLY
HardwareWriteIntMask( pHardware, pHardware->m_wInterruptMask );
#else
HardwareWriteRegWord( pHardware, REG_INT_MASK_BANK, REG_INT_MASK_OFFSET,
pHardware->m_wInterruptMask );
#endif
}
#endif
} /* HardwareTurnOnInterrupt */
/* -------------------------------------------------------------------------- */
/*
Register saving routines
*/
#ifdef KS_ISA_BUS
#ifndef INLINE
/*
HardwareRestoreBank
Description:
This routine restores the current register bank saved during interrupt
processing.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareRestoreBank (
PHARDWARE pHardware )
{
HardwareSelectBank( pHardware, pHardware->m_bSavedBank );
} /* HardwareRestoreBank */
/*
HardwareSaveBank
Description:
This routine saves the current register bank during interrupt
processing to be restored later.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareSaveBank (
PHARDWARE pHardware )
{
HW_READ_BYTE( pHardware, REG_BANK_SEL_OFFSET, &pHardware->m_bBank );
pHardware->m_bSavedBank = pHardware->m_bBank;
} /* HardwareSaveBank */
/*
HardwareRestoreRegs
Description:
This routine restores the registers saved during interrupt processing.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareRestoreRegs (
PHARDWARE pHardware )
{
HardwareRestoreBank( pHardware );
} /* HardwareRestoreRegs */
/*
HardwareSaveRegs
Description:
This routine saves the registers during interrupt processing to be
restored later.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareSaveRegs (
PHARDWARE pHardware )
{
HardwareSaveBank( pHardware );
} /* HardwareSaveRegs */
#endif
#endif
/* -------------------------------------------------------------------------- */
/*
HardwareDisable
Description:
This routine disables the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareDisable_PCI
#else
void HardwareDisable_ISA
#endif
(
PHARDWARE pHardware )
{
HardwareStopReceive( pHardware );
HardwareStopTransmit( pHardware );
pHardware->m_bEnabled = FALSE;
} /* HardwareDisable */
/*
HardwareEnable
Description:
This routine enables the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareEnable_PCI
#else
void HardwareEnable_ISA
#endif
(
PHARDWARE pHardware )
{
HardwareStartTransmit( pHardware );
HardwareStartReceive( pHardware );
pHardware->m_bEnabled = TRUE;
#if defined( KS_ISA_BUS ) && defined( DBG_ )
DisplayRegisters( pHardware );
#endif
} /* HardwareEnable */
/* -------------------------------------------------------------------------- */
/*
Receive processing routines
*/
#ifdef KS_ISA_BUS
/*
HardwareReceiveEarly
Description:
This routine handles the receive early interrupt processing.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareReceiveEarly (
PHARDWARE pHardware )
{
/* Setup read address pointer. */
HardwareWriteRegWord( pHardware, REG_RX_ADDR_PTR_BANK,
REG_RX_ADDR_PTR_OFFSET, ADDR_PTR_AUTO_INC | 4 );
HW_READ_BUFFER( pHardware, REG_DATA_OFFSET, pHardware->m_bLookahead,
pHardware->m_wReceiveThreshold );
/* Hardware continues to generate interrupts as more data are received in the
packet already acknowledged.
*/
#if 1
HardwareTurnOffEarlyInterrupt( pHardware );
#endif
} /* HardwareReceiveEarly */
/*
HardwareReceiveMoreDataAvailable
Description:
This function returns the remain packet length of the received packet
in the RXQ. If remain packet length is not zero, there are more
packets waiting in the RXQ.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (USHORT):
The length of the total received packet in the RXQ.
*/
USHORT HardwareReceiveMoreDataAvailable (
PHARDWARE pHardware )
{
USHORT wMoreDataLength=0;
/* Read from the RXMIR. */
HardwareReadRegWord( pHardware, REG_RX_MEM_INFO_BANK,
REG_RX_MEM_INFO_OFFSET, &wMoreDataLength );
wMoreDataLength &= MEM_AVAILABLE_MASK;
return ( wMoreDataLength );
} /* HardwareReceiveMoreDataAvailable */
/*
HardwareReceiveStatus
Description:
This function checks the Receive Status.
information.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
PUSHORT pwStatus
Pointer to a USHORT with Receive Status.
PUSHORT pwLength
Pointer to a USHORT with Receive Packet Length.
Return (BOOLEAN):
TRUE if received packet is valid and good packet; otherwise, FALSE.
*/
BOOLEAN HardwareReceiveStatus (
PHARDWARE pHardware,
PUSHORT pwStatus,
PUSHORT pwLength )
{
USHORT wStatus;
BOOLEAN fStatus=TRUE;
int port = 0;
/* Read Receive Status */
HardwareReadRegWord( pHardware, REG_RX_STATUS_BANK, REG_RX_STATUS_OFFSET,
pwStatus );
wStatus = *pwStatus;
/* Read Receive Status */
HardwareReadRegWord( pHardware, REG_RX_BYTE_CNT_BANK, REG_RX_BYTE_CNT_OFFSET,
pwLength );
*pwLength &= RX_BYTE_CNT_MASK;
#ifdef DEF_KS8842
/* only valid if Switch enagine enabled (under ks8842) */
pHardware->m_bPortRX = ( wStatus & RX_SRC_PORTS ) >> RX_SRC_PORTS_SHIFT;
#else
pHardware->m_bPortRX = 1;
#endif /* #ifdef DEF_KS8842 */
if ( pHardware->m_bPortRX > 0)
port = pHardware->m_bPortRX - 1;
/*
* Receive Valid Frame.
*/
if ( ( wStatus & RX_VALID ) )
{
/*
* Receive with error.
*/
if ( ( wStatus & RX_ERRORS ) )
{
/* Update receive error statistics. */
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR ]+=1;
if ( (wStatus & RX_PHY_ERROR) == RX_PHY_ERROR )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_MII ]+=1;
if ( (wStatus & RX_BAD_CRC) == RX_BAD_CRC )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_CRC ]+=1;
if ( (wStatus & RX_TOO_SHORT) == RX_TOO_SHORT )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_RUNT ]+=1;
if ( (wStatus & RX_TOO_LONG) == RX_TOO_LONG )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_TOOLONG ]+=1;
fStatus = FALSE;
}
/*
* Receive without error.
*/
else
{
if ( ( (wStatus & RX_MULTICAST) == RX_MULTICAST ) ||
( (wStatus & RX_BROADCAST) == RX_BROADCAST ) )
{
if ( (wStatus & RX_BROADCAST) == RX_BROADCAST )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_BROADCAST_FRAMES_RCV ]+=1;
else
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_MULTICAST_FRAMES_RCV ]+=1;
}
if ( (wStatus & RX_UNICAST) == RX_UNICAST )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_UNICAST_FRAMES_RCV ]+=1;
}
}
/*
* Receive Invalid Frame.
*/
else
{
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR ]+=1;
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_INVALID_FRAME ]+=1;
fStatus = FALSE;
}
return ( fStatus );
} /* HardwareReceiveStatus */
/*
HardwareReceiveLength
Description:
This function returns the length of the received packet.
No matter switch is Direct mode or Lookup mode, when
m_bPortRX is 1 : Receive packet from Port1,
m_bPortRX is 2 : Receive packet from Port2.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (int):
The length of the received packet.
*/
int HardwareReceiveLength (
PHARDWARE pHardware )
{
ULONG dwStatus;
int wLength;
int wStatus;
int port = 0;
/* Setup read address pointer. */
HardwareReadRegDWord( pHardware, REG_DATA_BANK,
REG_DATA_OFFSET, &dwStatus );
wStatus = dwStatus & 0xFFFF;
wLength = dwStatus >> 16;
#ifdef DEF_KS8842
/* only valid if Switch enagine enabled (under ks8842) */
pHardware->m_bPortRX = ( wStatus & RX_SRC_PORTS ) >> RX_SRC_PORTS_SHIFT;
#else
pHardware->m_bPortRX = 1;
#endif /* #ifdef DEF_KS8842 */
if ( pHardware->m_bPortRX > 0)
port = pHardware->m_bPortRX - 1;
/*
* Receive without error.
*/
if ( !( wStatus & RX_ERRORS ) )
{
#ifdef DEBUG_RX
DBG_PRINT( " RX: %04X %u ", wStatus, wLength );
#endif
/* exclude 4-BYTE CRC if Receive Strip CRC is disable */
if ( !(pHardware->m_wReceiveConfig & RX_CTRL_STRIP_CRC) )
wLength -= 4;
pHardware->m_nPacketLen = wLength;
#ifdef DEBUG_RX
DBG_PRINT( "%u"NEWLINE, wLength );
#endif
return( wLength );
}
/*
* Receive with error.
*/
else
{
pHardware->m_nPacketLen = 0;
#ifdef DEBUG_RX
DBG_PRINT( " RX: %04X"NEWLINE, wStatus );
#endif
#ifdef DEBUG_COUNTER
pHardware->m_nBad[ COUNT_BAD_RCV_FRAME ]+=1;
#endif
#if defined( _WIN32 ) || defined( DEF_LINUX )
#ifdef SH_16BIT_WRITE
HW_WRITE_WORD( pHardware, REG_RXQ_CMD_OFFSET, RXQ_CMD_FREE_PACKET );
#else
HW_WRITE_BYTE( pHardware, REG_RXQ_CMD_OFFSET, RXQ_CMD_FREE_PACKET );
#endif
#endif
return( 0 );
}
} /* HardwareReceiveLength */
/*
HardwareReceiveBuffer
Description:
This routine reads the received packet into system memory.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
void* pBuffer
Buffer to store the packet.
int length
The length of the packet.
Return (None):
*/
void HardwareReceiveBuffer (
PHARDWARE pHardware,
void* pBuffer,
int length )
{
#ifdef SH_32BIT_ALIGNED
HW_READ_BUFFER( pHardware, REG_DATA_OFFSET, pHardware->m_bLookahead,
length );
memcpy( pBuffer, pHardware->m_bLookahead, length );
#else
HW_READ_BUFFER( pHardware, REG_DATA_OFFSET, pBuffer, length );
#endif
#if defined( _WIN32 ) || defined( DEF_LINUX )
#ifdef SH_16BIT_WRITE
HW_WRITE_WORD( pHardware, REG_RXQ_CMD_OFFSET, RXQ_CMD_FREE_PACKET );
#else
HW_WRITE_BYTE( pHardware, REG_RXQ_CMD_OFFSET, RXQ_CMD_FREE_PACKET );
#endif
#endif
#ifdef EARLY_RECEIVE
#ifdef DEBUG_COUNTER
if ( pHardware->m_bReceiveDiscard )
pHardware->m_nGood[ COUNT_GOOD_RCV_NOT_DISCARD ]+=1;
#endif
pHardware->m_bReceiveDiscard = FALSE;
HardwareTurnOnEarlyInterrupt( pHardware, &pHardware->m_wInterruptMask );
#endif
#ifdef DEBUG_RX_DATA
do {
int nLength;
UCHAR* bData = ( PUCHAR ) pBuffer;
//if ( 0xFF == bData[ 0 ] )
// break;
for ( nLength = 0; nLength < 0x40; nLength++ )
{
DBG_PRINT( "%02X ", bData[ nLength ]);
if ( ( nLength % 16 ) == 15 )
{
DBG_PRINT( NEWLINE );
}
}
DBG_PRINT( NEWLINE );
} while ( 0 );
#endif
} /* HardwareReceiveBuffer */
#endif
/*
HardwareReceive
Description:
This routine handles the receive processing. The packet is read into
the m_Lookahead buffer and its length is indicated in m_nPacketLen.
No matter switch is Direct mode or Lookup mode, when
m_bPortRX is 1 : Receive packet from Port1,
m_bPortRX is 2 : Receive packet from Port2.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareReceive_PCI
#else
void HardwareReceive_ISA
#endif
(
PHARDWARE pHardware )
{
/* PCI_BUS */
#ifdef KS_PCI_BUS
TDescStat status;
PTDesc pDesc = pHardware->m_RxDescInfo.pCurrent;
int port = 0;
/* Assume error. */
pHardware->m_nPacketLen = 0;
status.ulData = pDesc->sw.Control.ulData;
/* Status valid only when last descriptor bit is set. */
if ( status.rx.fLastDesc )
{
#ifdef CHECK_RCV_ERRORS
/*
* Receive without error. With receive errors disabled, packets with
* receive errors will be dropped, so no need to check the error bit.
*/
if ( !status.rx.fError )
#endif
{
/* Get received port number */
pHardware->m_bPortRX = ( UCHAR ) status.rx.ulSourePort;
if ( pHardware->m_bPortRX > 0 )
port = pHardware->m_bPortRX - 1;
#ifdef DEBUG_RX
DBG_PRINT( "m_bPortRX: %d"NEWLINE, pHardware->m_bPortRX );
#endif
if ( status.rx.fMulticast )
{
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_MULTICAST_FRAMES_RCV ]+=1;
#ifdef DEBUG_RX
DBG_PRINT( "M " );
#endif
}
/* received length includes 4-byte CRC */
pHardware->m_nPacketLen = status.rx.wFrameLen - 4;
}
#ifdef CHECK_RCV_ERRORS
/*
* Receive with error.
*/
else {
/* Update receive error statistics. */
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR ]+=1;
if ( status.rx.fErrCRC )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_CRC ]+=1;
if ( status.rx.fErrRunt )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_RUNT ]+=1;
if ( status.rx.fErrTooLong )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_TOOLONG ]+=1;
if ( status.rx.fErrPHY )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_MII ]+=1;
#ifdef DEBUG_RX
DBG_PRINT( " RX: %08lX"NEWLINE, status.ulData );
#endif
#ifdef DEBUG_COUNTER
pHardware->m_nBad[ COUNT_BAD_RCV_FRAME ]+=1;
#endif
}
/* Hardware checksum errors are not associated with receive errors. */
#if RXCHECKSUM_DEFAULT
/* Hardware cannot handle UDP packet in IP fragments. */
#if 0
if ( status.rx.fCsumErrUDP )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_UDP ]+=1;
#endif
if ( status.rx.fCsumErrTCP )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_TCP ]+=1;
if ( status.rx.fCsumErrIP )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_RCV_ERROR_IP ]+=1;
#endif
#endif
}
/* ISA_BUS */
#else
ULONG dwStatus;
int wLength;
int wStatus;
int port = 0;
HardwareSelectBank( pHardware, REG_DATA_BANK );
HW_READ_DWORD( pHardware, REG_DATA_OFFSET, &dwStatus );
wStatus = dwStatus & 0xFFFF;
wLength = dwStatus >> 16;
#ifdef DEF_KS8842
/* only valid if Switch enagine enabled (under ks8842) */
pHardware->m_bPortRX = ( wStatus & RX_SRC_PORTS ) >> RX_SRC_PORTS_SHIFT;
#else
pHardware->m_bPortRX = 1;
#endif /* #ifdef DEF_KS8842 */
if ( pHardware->m_bPortRX > 0)
port = pHardware->m_bPortRX - 1;
/*
* Receive without error.
*/
if ( !( wStatus & RX_ERRORS ) )
{
if ( ( wStatus & RX_BROADCAST ) == RX_BROADCAST )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_BROADCAST_FRAMES_RCV ]+=1;
if ( ( wStatus & RX_MULTICAST ) == RX_MULTICAST )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_MULTICAST_FRAMES_RCV ]+=1;
if ( ( wStatus & RX_UNICAST ) == RX_UNICAST )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_UNICAST_FRAMES_RCV ]+=1;
/* exclude 4-BYTE CRC if Receive Strip CRC is disable */
if ( !(pHardware->m_wReceiveConfig & RX_CTRL_STRIP_CRC) )
wLength -= 4;
HW_READ_BUFFER( pHardware, REG_DATA_OFFSET,
pHardware->m_bLookahead, wLength );
#if defined( _WIN32 ) || defined( DEF_LINUX )
#ifdef SH_16BIT_WRITE
HW_WRITE_WORD( pHardware, REG_RXQ_CMD_OFFSET, RXQ_CMD_FREE_PACKET );
#else
HW_WRITE_BYTE( pHardware, REG_RXQ_CMD_OFFSET, RXQ_CMD_FREE_PACKET );
#endif
#endif
pHardware->m_nPacketLen = wLength;
#ifdef DEBUG_RX
DBG_PRINT( "%u"NEWLINE, wLength );
if ( pHardware->m_bReceiveDiscard )
{
for ( wLength = 0; wLength < 16; wLength++ )
DBG_PRINT( "%02X ", pHardware->m_bLookahead[ wLength ]);
DBG_PRINT( NEWLINE );
}
#endif /* #ifdef DEBUG_RX */
#ifdef DEBUG_RX_DATA
for ( wLength = 0; wLength < pHardware->m_nPacketLen; wLength++ )
{
DBG_PRINT( "%02X ",
pHardware->m_bLookahead[ wLength ]);
if ( ( wLength % 16 ) == 15 )
{
DBG_PRINT( NEWLINE );
}
}
DBG_PRINT( NEWLINE );
#endif /* #ifdef DEBUG_RX_DATA */
}
/*
* Receive with error.
*/
else
{
pHardware->m_nPacketLen = 0;
#ifdef DEBUG_RX
DBG_PRINT( " RX: %04X"NEWLINE, wStatus );
#endif
#ifdef DEBUG_COUNTER
pHardware->m_nBad[ COUNT_BAD_RCV_FRAME ]+=1;
#endif
}
#ifdef EARLY_RECEIVE
#ifdef DEBUG_COUNTER
if ( pHardware->m_bReceiveDiscard )
pHardware->m_nGood[ COUNT_GOOD_RCV_NOT_DISCARD ]+=1;
#endif
pHardware->m_bReceiveDiscard = FALSE;
HardwareTurnOnEarlyInterrupt( pHardware, &pHardware->m_wInterruptMask );
#endif /* #ifdef EARLY_RECEIVE */
#endif /* #ifdef KS_PCI_BUS */
} /* HardwareReceive */
/* -------------------------------------------------------------------------- */
/*
Transmit processing routines
*/
#ifdef KS_PCI_BUS
#define MIN_TX_BUFFER_SIZE 128
#define TX_PACKET_ARRAY_SIZE 8
#define RX_PACKET_ARRAY_SIZE 64
#endif
/*
HardwareAllocPacket
Description:
This function allocates a packet for transmission.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
int length
The length of the packet.
int physical
Number of descriptors required in PCI version.
Return (int):
0 if not successful; 1 for buffer copy; otherwise, can use descriptors.
*/
#ifdef KS_PCI_BUS
int HardwareAllocPacket_PCI
#else
int HardwareAllocPacket_ISA
#endif
(
PHARDWARE pHardware,
#ifdef KS_PCI_BUS
int length,
int physical )
#else
int length )
#endif
{
int port = 0;
/* PCI_BUS */
#ifdef KS_PCI_BUS
/* Always leave one descriptor free. */
if ( pHardware->m_TxDescInfo.cnAvail <= 1 )
{
/* Update transmit statistics. */
pHardware->m_cnCounter[ port ][ OID_COUNTER_XMIT_ALLOC_FAIL ]+=1;
return( 0 );
}
#ifdef DEF_LINUX
if ( physical > pHardware->m_TxDescInfo.cnAvail )
{
return( 0 );
}
#endif
/* Allocate a descriptor for transmission and mark it current. */
GetTxPacket( &pHardware->m_TxDescInfo, pHardware->m_TxDescInfo.pCurrent );
pHardware->m_TxDescInfo.pCurrent->sw.BufSize.tx.fFirstSeg = TRUE;
if ( length < MIN_TX_BUFFER_SIZE ||
physical > TX_PACKET_ARRAY_SIZE ||
physical > pHardware->m_TxDescInfo.cnAvail )
{
return( 1 );
}
return( physical + 1 );
/* ISA_BUS */
#else
USHORT wStatus;
HardwareReadRegWord( pHardware, REG_TX_MEM_INFO_BANK,
REG_TX_MEM_INFO_OFFSET, &wStatus );
if ( wStatus < length + 4 )
{
/* Update transmit statistics. */
pHardware->m_cnCounter[ port ][ OID_COUNTER_XMIT_ALLOC_FAIL ]+=1;
#ifdef DEBUG_COUNTER
pHardware->m_nBad[ COUNT_BAD_ALLOC ]+=1;
#endif
return FALSE;
}
/* Transmit Frame ID consisted of Transmit Packet Number (bit 4~0) and Port Number (bit 5) */
pHardware->m_bTransmitPacket++;
pHardware->m_bTransmitPacket &= TX_FRAME_ID_MAX;
/* if Tx to port 2, set bit_5 to 1; otherwise, set bit_5 to 0 */
if ( (pHardware->m_bPortTX == 2) || (pHardware->m_bPortTX == 3) )
pHardware->m_bTransmitPacket |= ( 1 << TX_FRAME_ID_PORT_SHIFT );
return TRUE;
#endif /* #ifdef KS_PCI_BUS */
} /* HardwareAllocPacket */
/*
HardwareSendPacket
Description:
This function transmits the packet marked by m_bTransmitPacket.
This function marks the packet for transmission in PCI version.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (BOOLEAN):
TRUE if successful; otherwise, FALSE.
*/
#ifdef KS_PCI_BUS
BOOLEAN HardwareSendPacket_PCI
#else
BOOLEAN HardwareSendPacket_ISA
#endif
(
PHARDWARE pHardware )
{
#ifdef KS_PCI_BUS
PTDesc pCurrent = pHardware->m_TxDescInfo.pCurrent;
pCurrent->sw.BufSize.tx.fLastSeg = TRUE;
#if 1
pCurrent->sw.BufSize.tx.fInterrupt = TRUE;
#endif
pCurrent->sw.BufSize.tx.ulDestPort = pHardware->m_bPortTX;
ReleasePacket( pCurrent );
HW_WRITE_DWORD( pHardware, REG_DMA_TX_START, 0 );
#else
#ifdef SH_16BIT_WRITE
HardwareWriteRegWord( pHardware, REG_TXQ_CMD_BANK, REG_TXQ_CMD_OFFSET,
TXQ_CMD_ENQUEUE_PACKET );
#else
HardwareWriteRegByte( pHardware, REG_TXQ_CMD_BANK, REG_TXQ_CMD_OFFSET,
TXQ_CMD_ENQUEUE_PACKET );
#endif
#endif
return( TRUE );
} /* HardwareSendPacket */
#if defined( KS_ISA_BUS ) || !defined( INLINE )
/*
HardwareSetTransmitLength
Description:
This routine prepares the transmit length before buffer copying.
This routine sets the transmit length in PCI version.
If Switch is already set to Dircet mode, when
m_bPortTX is 0 : Transmit packet by loopkup mode,
m_bPortTX is 1 : Transmit packet to Port1,
m_bPortTX is 2 : Transmit packet to Port2,
m_bPortTX is 3 : Transmit packet to Port1 and Port2.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
int length
The length of the packet.
Return (None):
*/
#ifdef KS_PCI_BUS
ULONG HardwareSetTransmitLength_PCI
#else
ULONG HardwareSetTransmitLength_ISA
#endif
(
PHARDWARE pHardware,
int length )
{
ULONG dwLength=0;
/* PCI_BUS */
#ifdef KS_PCI_BUS
pHardware->m_TxDescInfo.pCurrent->sw.BufSize.tx.wBufSize = length;
/* ISA_BUS */
#else
ULONG dwDestPort=0;
dwLength = length;
dwLength <<= 16;
/* transmit packet using direct mode if m_bPortTX is not zero, otherwise using lookup mode */
dwDestPort = pHardware->m_bPortTX;
dwLength |= (dwDestPort << TX_DEST_PORTS_SHIFT );
dwLength |= pHardware->m_bTransmitPacket;
dwLength |= TX_CTRL_INTERRUPT_ON;
HardwareWriteRegDWord( pHardware, REG_DATA_BANK,
REG_DATA_OFFSET, dwLength );
#endif /* #ifdef KS_PCI_BUS */
return (dwLength);
} /* HardwareSetTransmitLength */
#endif /* #if defined( KS_ISA_BUS ) || !defined( INLINE ) */
/*
HardwareTransmitDone
Description:
This function handles the transmit done interrupt processing.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (BOOLEAN):
TRUE if packet is sent successful; otherwise, FALSE.
*/
#ifdef KS_PCI_BUS
BOOLEAN HardwareTransmitDone_PCI
#else
BOOLEAN HardwareTransmitDone_ISA
#endif
(
PHARDWARE pHardware )
{
/* ISA_BUS */
#ifdef KS_ISA_BUS
USHORT wStatus;
UCHAR bPacket;
int port = 0;
HardwareReadRegWord( pHardware, REG_TX_STATUS_BANK, REG_TX_STATUS_OFFSET,
&wStatus );
bPacket = ( UCHAR )( wStatus & TX_FRAME_ID_MASK );
pHardware->m_bSentPacket = bPacket;
#ifdef DEBUG_TX
if ( bPacket != pHardware->m_bTransmitPacket )
{
DBG_PRINT( "sent != transmit: %x, %x"NEWLINE, bPacket,
pHardware->m_bTransmitPacket );
}
#endif
port = bPacket >> TX_FRAME_ID_PORT_SHIFT;
#ifdef DEBUG_TX
DBG_PRINT( "send status: %x"NEWLINE, wStatus );
#endif
if ( ( wStatus & TX_STAT_ERRORS ) )
{
/* Update transmit error statistics. */
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_XMIT_ERROR ]+=1;
if ( ( wStatus & TX_STAT_MAX_COL ) )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_XMIT_MORE_COLLISIONS ]+=1;
if ( ( wStatus & TX_STAT_LATE_COL ) )
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_XMIT_LATE_COLLISION ]+=1;
if ( ( wStatus & TX_STAT_UNDERRUN ) )
{
pHardware->m_cnCounter
[ port ]
[ OID_COUNTER_XMIT_UNDERRUN ]+=1;
DBG_PRINT( "tx underrun!"NEWLINE );
}
/* Restart the transmit. */
HardwareStartTransmit( pHardware );
#ifdef DEBUG_COUNTER
pHardware->m_nBad[ COUNT_BAD_SEND ]+=1;
#endif
return FALSE;
}
#endif /* #ifdef KS_ISA_BUS */
return TRUE;
} /* HardwareTransmitDone */
/* -------------------------------------------------------------------------- */
/*
HardwareSetAddress
Description:
This routine programs the MAC address of the hardware when the address
is overrided.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareSetAddress_PCI
#else
void HardwareSetAddress_ISA
#endif
(
PHARDWARE pHardware )
{
UCHAR i;
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_ADDR_0_BANK );
#endif
for ( i = 0; i < MAC_ADDRESS_LENGTH; i++ )
{
#ifdef SH_16BIT_WRITE
if ( ( i & 1 ) )
{
HW_WRITE_WORD( pHardware, (( REG_ADDR_0_OFFSET + i ) & ~1 ),
( pHardware->m_bOverrideAddress[ MAC_ADDR_ORDER( i )] << 8 ) |
pHardware->m_bOverrideAddress[ MAC_ADDR_ORDER( i - 1 )]);
}
#else
HW_WRITE_BYTE( pHardware, ( ULONG )( REG_ADDR_0_OFFSET + i ),
( UCHAR ) pHardware->m_bOverrideAddress[ MAC_ADDR_ORDER( i )]);
#endif
}
#ifdef DBG
DBG_PRINT( "set addr: " );
PrintMacAddress( pHardware->m_bOverrideAddress );
DBG_PRINT( NEWLINE );
#endif
SwitchSetAddress( pHardware, pHardware->m_bOverrideAddress );
} /* HardwareSetAddress */
/*
HardwareReadAddress
Description:
This function retrieves the MAC address of the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (BOOLEAN):
TRUE to indicate successful.
*/
#ifdef KS_PCI_BUS
BOOLEAN HardwareReadAddress_PCI
#else
BOOLEAN HardwareReadAddress_ISA
#endif
(
PHARDWARE pHardware )
{
UCHAR i;
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_ADDR_0_BANK );
#endif
for ( i = 0; i < MAC_ADDRESS_LENGTH; i++ )
{
HW_READ_BYTE( pHardware, ( ULONG )( REG_ADDR_0_OFFSET + i ),
( PUCHAR ) &pHardware->m_bPermanentAddress[ MAC_ADDR_ORDER( i )]);
}
#ifdef DBG
DBG_PRINT( "get addr: " );
PrintMacAddress( pHardware->m_bPermanentAddress );
DBG_PRINT( NEWLINE );
#endif
if ( !pHardware->m_bMacOverrideAddr )
{
MOVE_MEM( pHardware->m_bOverrideAddress,
pHardware->m_bPermanentAddress, MAC_ADDRESS_LENGTH );
#ifdef DEVELOP_
memset( pHardware->m_bOverrideAddress, 0, MAC_ADDRESS_LENGTH );
#endif
if ( 0 == pHardware->m_bOverrideAddress[ 0 ] &&
0 == pHardware->m_bOverrideAddress[ 1 ] &&
0 == pHardware->m_bOverrideAddress[ 2 ] &&
0 == pHardware->m_bOverrideAddress[ 3 ] &&
0 == pHardware->m_bOverrideAddress[ 4 ] &&
0 == pHardware->m_bOverrideAddress[ 5 ] )
{
MOVE_MEM( pHardware->m_bPermanentAddress,
DEFAULT_MAC_ADDRESS, MAC_ADDRESS_LENGTH );
MOVE_MEM( pHardware->m_bOverrideAddress,
DEFAULT_MAC_ADDRESS, MAC_ADDRESS_LENGTH );
HardwareSetAddress( pHardware );
}
else
SwitchSetAddress( pHardware, pHardware->m_bOverrideAddress );
}
else
{
HardwareSetAddress( pHardware );
}
return TRUE;
} /* HardwareReadAddress */
#ifdef KS_PCI_BUS
/*
* HardwareAddrFilterClear
* This routine clears all the MAC Additional Station Address filter.
*
* Argument(s)
* pHardware Pointer to hardware instance.
*
* Return(s)
* NONE.
*/
void HardwareAddrFilterClear
(
PHARDWARE pHardware
)
{
ULONG macAddrLow, macAddrHigh;
int i;
/* Clear MAC address filter */
macAddrLow = REG_ADD_ADDR_0_LO;
macAddrHigh = REG_ADD_ADDR_0_HI;
for (i=0; i<16;i++)
{
HW_WRITE_DWORD(pHardware, macAddrLow, 0);
HW_WRITE_DWORD(pHardware, macAddrHigh, 0);
macAddrLow += 0x08;
macAddrHigh += 0x08;
}
} /* HardwareAddrFilterClear */
/*
* HardwareAddrFilterAdd
* This function adds MAC address to the switch's MAC address filter.
*
* Argument(s)
* pHardware Pointer to hardware instance.
* pMacAddress pointer to a byte array to hold MAC address (at least 6 bytes long)
*
* Return(s)
* NONE.
*/
int HardwareAddrFilterAdd
(
PHARDWARE pHardware,
UCHAR *pMacAddress
)
{
ULONG uLow, uHigh;
ULONG macAddrLow, macAddrHigh;
UCHAR macFilterIndex;
ULONG uData;
uLow = ((ULONG)pMacAddress[2] << 24);
uLow += ((ULONG)pMacAddress[3] << 16);
uLow += ((ULONG)pMacAddress[4] << 8);
uLow += pMacAddress[5];
uHigh = ((ULONG)pMacAddress[0] << 8) + pMacAddress[1];
/* Search for avaiable entry from the MAC Additional Station Address */
for ( macFilterIndex=0; macFilterIndex < 16; macFilterIndex++)
{
macAddrHigh = ( REG_ADD_ADDR_0_HI + (macFilterIndex * 0x08) );
/* check if this entry is avaiable */
HW_READ_DWORD(pHardware, macAddrHigh, &uData);
if ( (uData & MAC_ADDR_ENABLE) != MAC_ADDR_ENABLE)
break;
}
/* this entry is not avaiable */
if (macFilterIndex >= 16)
return (FALSE);
/* this entry is not avaiable */
macAddrLow = ( REG_ADD_ADDR_0_LO + (macFilterIndex * 0x08) );
macAddrHigh = ( REG_ADD_ADDR_0_HI + (macFilterIndex * 0x08) );
HW_WRITE_DWORD(pHardware, macAddrLow, uLow);
HW_WRITE_DWORD(pHardware, macAddrHigh, (uHigh | MAC_ADDR_ENABLE));
return (TRUE);
} /* HardwareAddrFilterAdd */
/*
* HardwareAddrFilterDel
* This function deletes MAC address from the switch's MAC address filter.
*
* Argument(s)
* pHardware Pointer to hardware instance.
* pMacAddress pointer to a byte array to hold MAC address (at least 6 bytes long)
*
* Return(s)
* NONE.
*/
int HardwareAddrFilterDel
(
PHARDWARE pHardware,
UCHAR *pMacAddress
)
{
ULONG uLow, uHigh;
ULONG macAddrLow, macAddrHigh;
UCHAR macFilterIndex;
ULONG uDataLow, uDataHigh;
uLow = ((ULONG)pMacAddress[2] << 24);
uLow += ((ULONG)pMacAddress[3] << 16);
uLow += ((ULONG)pMacAddress[4] << 8);
uLow += pMacAddress[5];
uHigh = ((ULONG)pMacAddress[0] << 8) + pMacAddress[1];
/* Search for the entry from the MAC Additional Station Address
that match MAC address to be deleted */
for ( macFilterIndex=0; macFilterIndex < 16; macFilterIndex++)
{
macAddrLow = ( REG_ADD_ADDR_0_LO + (macFilterIndex * 0x08) );
macAddrHigh = ( REG_ADD_ADDR_0_HI + (macFilterIndex * 0x08) );
/* check if this entry's MAC match */
HW_READ_DWORD(pHardware, macAddrLow, &uDataLow);
HW_READ_DWORD(pHardware, macAddrHigh, &uDataHigh);
uDataHigh &= ~MAC_ADDR_ENABLE;
if ( (uDataLow ==uLow) && (uDataHigh == uHigh) )
break;
}
/* not found */
if (macFilterIndex >= 16)
return (FALSE);
/* found the entry that match MAC address to be deleted */
macAddrLow = ( REG_ADD_ADDR_0_LO + (macFilterIndex * 0x08) );
macAddrHigh = ( REG_ADD_ADDR_0_HI + (macFilterIndex * 0x08) );
HW_WRITE_DWORD(pHardware, macAddrLow, 0);
HW_WRITE_DWORD(pHardware, macAddrHigh, 0);
return (TRUE);
} /* HardwareAddrFilterDel */
#endif /* #ifdef KS_PCI_BUS */
/*
HardwareClearMulticast
Description:
This routine removes all multicast addresses set in the hardware.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareClearMulticast_PCI
#else
void HardwareClearMulticast_ISA
#endif
(
PHARDWARE pHardware )
{
UCHAR i;
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_MULTICAST_BANK );
#endif
for ( i = 0; i < HW_MULTICAST_SIZE; i++ )
{
pHardware->m_bMulticastBits[ i ] = 0;
#ifdef SH_16BIT_WRITE
if ( ( i & 1 ) )
{
HW_WRITE_WORD( pHardware, ( ULONG )(( REG_MULTICAST_0_OFFSET + i )
& ~1 ), 0 );
}
#else
HW_WRITE_BYTE( pHardware, ( ULONG )( REG_MULTICAST_0_OFFSET + i ), 0 );
#endif
}
} /* HardwareClearMulticast */
#if 0
/* The little-endian AUTODIN II ethernet CRC calculation.
N.B. Do not use for bulk data, use a table-based routine instead.
This is common code and should be moved to net/core/crc.c */
static unsigned const ethernet_polynomial_le = 0xedb88320U;
static unsigned ether_crc_le (
int length,
unsigned char *data )
{
unsigned int crc = 0xffffffff; /* Initial value. */
while ( --length >= 0 ) {
unsigned char current_octet = *data++;
int bit;
for ( bit = 8; --bit >= 0; current_octet >>= 1 ) {
if ( ( crc ^ current_octet ) & 1 ) {
crc >>= 1;
crc ^= ethernet_polynomial_le;
}
else
crc >>= 1;
}
}
return crc;
} /* ether_crc_le */
#endif
/*
ether_crc
Description:
This function generates a CRC-32 from the data block.
It is used to calculate values for the hardware multicast filter hash table,
or wake up frame CRC value.
Parameters:
int length,
the length of the block data
unsigned char * data
Pointer to the block data.
Return:
The computed CRC of the data.
*/
static unsigned long const ethernet_polynomial = 0x04c11db7U;
unsigned long ether_crc
(
int length,
unsigned char *data
)
{
long crc = -1;
while ( --length >= 0 )
{
unsigned char current_octet = *data++;
int bit;
for ( bit = 0; bit < 8; bit++, current_octet >>= 1 )
{
crc = ( crc << 1 ) ^
(( crc < 0 ) ^ ( current_octet & 1 ) ?
ethernet_polynomial : 0 );
}
}
return crc;
} /* ether_crc */
/*
HardwareSetGroupAddress
Description:
This function programs multicast addresses for the hardware to accept
those addresses.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (BOOLEAN):
TRUE to indicate success.
*/
#ifdef KS_PCI_BUS
BOOLEAN HardwareSetGroupAddress_PCI
#else
BOOLEAN HardwareSetGroupAddress_ISA
#endif
(
PHARDWARE pHardware )
{
UCHAR i;
int index;
int position;
int value;
memset( pHardware->m_bMulticastBits, 0,
sizeof( UCHAR ) * HW_MULTICAST_SIZE );
#ifdef DEVELOP
DBG_PRINT( "set multicast:"NEWLINE );
{
UCHAR spanning_tree[] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 };
position = ( ether_crc( 6, spanning_tree ) >> 26 ) & 0x3f;
index = position >> 3;
value = 1 << ( position & 7 );
pHardware->m_bMulticastBits[ index ] |= ( UCHAR ) value;
}
#endif
for ( i = 0; i < pHardware->m_bMulticastListSize; i++ )
{
#ifdef DBG
PrintMacAddress( pHardware->m_bMulticastList[ i ]);
DBG_PRINT( NEWLINE );
#endif
position = ( ether_crc( 6, pHardware->m_bMulticastList[ i ]) >> 26 ) &
0x3f;
index = position >> 3;
value = 1 << ( position & 7 );
pHardware->m_bMulticastBits[ index ] |= ( UCHAR ) value;
}
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_MULTICAST_BANK );
#endif
for ( i = 0; i < HW_MULTICAST_SIZE; i++ )
{
#ifdef SH_16BIT_WRITE
if ( ( i & 1 ) )
{
HW_WRITE_WORD( pHardware, ( ULONG )(( REG_MULTICAST_0_OFFSET + i )
& ~1 ),
( pHardware->m_bMulticastBits[ i ] << 8 ) |
pHardware->m_bMulticastBits[ i - 1 ]);
}
#else
HW_WRITE_BYTE( pHardware, ( ULONG )( REG_MULTICAST_0_OFFSET + i ),
pHardware->m_bMulticastBits[ i ]);
#endif
}
return TRUE;
} /* HardwareSetGroupAddress */
/*
HardwareSetMulticast
Description:
This function enables/disables the hardware to accept all multicast
packets.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bMulticast
To turn on or off the all multicast feature.
Return (BOOLEAN):
TRUE to indicate success.
*/
#ifdef KS_PCI_BUS
BOOLEAN HardwareSetMulticast_PCI
#else
BOOLEAN HardwareSetMulticast_ISA
#endif
(
PHARDWARE pHardware,
UCHAR bMulticast )
{
pHardware->m_bAllMulticast = bMulticast;
HardwareStopReceive( pHardware ); /* Stop receiving for reconfiguration */
#ifdef KS_PCI_BUS
if ( bMulticast )
pHardware->m_dwReceiveConfig |= DMA_RX_CTRL_ALL_MULTICAST;
else
pHardware->m_dwReceiveConfig &= ~DMA_RX_CTRL_ALL_MULTICAST;
#else
if ( bMulticast )
pHardware->m_wReceiveConfig |= RX_CTRL_ALL_MULTICAST;
else
pHardware->m_wReceiveConfig &= ~RX_CTRL_ALL_MULTICAST;
#endif
if ( pHardware->m_bEnabled )
HardwareStartReceive( pHardware );
return TRUE;
} /* HardwareSetMulticast */
/*
HardwareSetPromiscuous
Description:
This function enables/disables the hardware to accept all packets.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UCHAR bMulticast
To turn on or off the promiscuous feature.
Return (BOOLEAN):
TRUE to indicate success.
*/
#ifdef KS_PCI_BUS
BOOLEAN HardwareSetPromiscuous_PCI
#else
BOOLEAN HardwareSetPromiscuous_ISA
#endif
(
PHARDWARE pHardware,
UCHAR bPromiscuous )
{
pHardware->m_bPromiscuous = bPromiscuous;
HardwareStopReceive( pHardware ); /* Stop receiving for reconfiguration */
#ifdef KS_PCI_BUS
if ( bPromiscuous )
pHardware->m_dwReceiveConfig |= DMA_RX_CTRL_PROMISCUOUS;
else
pHardware->m_dwReceiveConfig &= ~DMA_RX_CTRL_PROMISCUOUS;
#else /* ISA_BUS */
if ( bPromiscuous )
pHardware->m_wReceiveConfig |= RX_CTRL_PROMISCUOUS;
else
pHardware->m_wReceiveConfig &= ~RX_CTRL_PROMISCUOUS;
#endif
if ( pHardware->m_bEnabled )
HardwareStartReceive( pHardware );
return TRUE;
} /* HardwareSetPromiscuous */
/* -------------------------------------------------------------------------- */
#ifdef KS_ISA_BUS
/*
HardwareGenerateInterrupt
Description:
This routine is used to generate an interrupt so that the actual
interrupt number can be detected by the operating system.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareGenerateInterrupt (
PHARDWARE pHardware )
{
USHORT wInterruptMask;
wInterruptMask = HardwareBlockInterrupt( pHardware );
/* Turn on receive stopped interrupt. */
HardwareSetInterrupt( pHardware, INT_RX_STOPPED );
/* Turn off receive to generate interrupts. */
HardwareWriteRegWord( pHardware, REG_RX_CTRL_BANK, REG_RX_CTRL_OFFSET,
0 );
/* Wait for interrupt to be registered. */
DelayMillisec( 10 );
/* Restore original interrupt mask. */
HardwareSetInterrupt( pHardware, wInterruptMask );
} /* HardwareGenerateInterrupt */
/*
HardwareServiceInterrupt
Description:
This routine is called after HardwareGenerateInterrupt() to service the
pending interrupt.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareServiceInterrupt (
PHARDWARE pHardware )
{
USHORT wStatus;
HardwareReadInterrupt( pHardware, &wStatus );
/* Clear the receive stopped interrupt status. */
HardwareAcknowledgeInterrupt( pHardware, INT_RX_STOPPED );
} /* HardwareServiceInterrupt */
#endif
/* -------------------------------------------------------------------------- */
enum {
CABLE_UNKNOWN,
CABLE_GOOD,
CABLE_CROSSED,
CABLE_REVERSED,
CABLE_CROSSED_REVERSED,
CABLE_OPEN,
CABLE_SHORT
};
#define STATUS_FULL_DUPLEX 0x01
#define STATUS_CROSSOVER 0x02
#define STATUS_REVERSED 0x04
#define LINK_10MBPS_FULL 0x00000001
#define LINK_10MBPS_HALF 0x00000002
#define LINK_100MBPS_FULL 0x00000004
#define LINK_100MBPS_HALF 0x00000008
#define LINK_1GBPS_FULL 0x00000010
#define LINK_1GBPS_HALF 0x00000020
#define LINK_10GBPS_FULL 0x00000040
#define LINK_10GBPS_HALF 0x00000080
#define LINK_SYM_PAUSE 0x00000100
#define LINK_ASYM_PAUSE 0x00000200
#define LINK_AUTO_MDIX 0x00010000
#define LINK_MDIX 0x00020000
#define LINK_AUTO_POLARITY 0x00040000
#define CABLE_LEN_MAXIMUM 15000
#define CABLE_LEN_MULTIPLIER 41
/*
HardwareGetCableStatus
Description:
This routine is used to get the cable status.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
void* pBuffer
Buffer to store the cable status.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareGetCableStatus_PCI
#else
void HardwareGetCableStatus_ISA
#endif
(
PHARDWARE pHardware,
UCHAR bPhy,
void* pBuffer )
{
PULONG pulData = ( PULONG ) pBuffer;
USHORT Control;
USHORT Crossover;
USHORT Data;
USHORT LowSpeed;
ULONG ulStatus;
ULONG ulLength[ 5 ];
UCHAR bStatus[ 5 ];
int i;
int cnTimeOut;
int phy;
phy = bPhy;
#ifdef KS_PCI_BUS
phy = REG_PHY_1_CTRL_OFFSET + bPhy * PHY_CTRL_INTERVAL;
#else
HardwareSelectBank( pHardware, ( UCHAR )( REG_PHY_1_CTRL_BANK + phy *
PHY_BANK_INTERVAL ));
#endif
HW_READ_PHY_LINK_STATUS( pHardware, phy, Data );
bStatus[ 4 ] = CABLE_UNKNOWN;
if ( ( Data & PHY_LINK_STATUS ) )
{
bStatus[ 4 ] = CABLE_GOOD;
ulLength[ 4 ] = 1;
bStatus[ 0 ] = CABLE_GOOD;
ulLength[ 0 ] = 1;
bStatus[ 1 ] = CABLE_GOOD;
ulLength[ 1 ] = 1;
#ifdef KS_PCI_BUS
phy = REG_PHY_SPECIAL_OFFSET + bPhy * PHY_SPECIAL_INTERVAL;
#else
HardwareSelectBank( pHardware, REG_PHY_SPECIAL_BANK );
#endif
HW_READ_PHY_POLARITY( pHardware, phy, Data );
ulStatus = 0;
if ( ( Data & PHY_STAT_MDIX ) )
ulStatus |= STATUS_CROSSOVER;
if ( ( Data & PHY_STAT_REVERSED_POLARITY ) )
ulStatus |= STATUS_REVERSED;
if ( ( ulStatus & ( STATUS_CROSSOVER | STATUS_REVERSED )) ==
( STATUS_CROSSOVER | STATUS_REVERSED ) )
bStatus[ 4 ] = CABLE_CROSSED_REVERSED;
else if ( ( ulStatus & STATUS_CROSSOVER ) == STATUS_CROSSOVER )
bStatus[ 4 ] = CABLE_CROSSED;
else if ( ( ulStatus & STATUS_CROSSOVER ) == STATUS_REVERSED )
bStatus[ 4 ] = CABLE_REVERSED;
goto GetCableStatusDone;
}
/* Put in 10 Mbps mode. */
HW_READ_PHY_CTRL( pHardware, phy, Control );
Data = Control;
Data &= ~( PHY_AUTO_NEG_ENABLE | PHY_SPEED_100MBIT | PHY_FULL_DUPLEX );
LowSpeed = Data;
HW_WRITE_PHY_CTRL( pHardware, phy, Data );
Crossover = Data;
for ( i = 0; i < 2; i++ )
{
#ifdef KS_PCI_BUS
phy = REG_PHY_1_CTRL_OFFSET + bPhy * PHY_CTRL_INTERVAL;
#else
HardwareSelectBank( pHardware, ( UCHAR )( REG_PHY_1_CTRL_BANK + phy *
PHY_BANK_INTERVAL ));
#endif
Data = Crossover;
/* Disable auto MDIX. */
Data |= PHY_AUTO_MDIX_DISABLE;
if ( 0 == i )
Data &= ~PHY_FORCE_MDIX;
else
Data |= PHY_FORCE_MDIX;
HW_WRITE_PHY_CROSSOVER( pHardware, phy, Data );
/* Disable transmitter. */
Data |= PHY_TRANSMIT_DISABLE;
HW_WRITE_PHY_CTRL( pHardware, phy, Data );
/* Wait at most 1 second.*/
DelayMillisec( 100 );
/* Enable transmitter. */
Data &= ~PHY_TRANSMIT_DISABLE;
HW_WRITE_PHY_CTRL( pHardware, phy, Data );
/* Start cable diagnostic test. */
#ifdef KS_PCI_BUS
phy = REG_PHY_SPECIAL_OFFSET + bPhy * PHY_SPECIAL_INTERVAL;
#else
HardwareSelectBank( pHardware, REG_PHY_SPECIAL_BANK );
#endif
HW_READ_PHY_LINK_MD( pHardware, phy, Data );
Data |= PHY_START_CABLE_DIAG;
HW_WRITE_PHY_LINK_MD( pHardware, phy, Data );
cnTimeOut = PHY_RESET_TIMEOUT;
do
{
if ( !--cnTimeOut )
{
break;
}
DelayMillisec( 10 );
HW_READ_PHY_LINK_MD( pHardware, phy, Data );
} while ( ( Data & PHY_START_CABLE_DIAG ) );
ulLength[ i ] = 0;
bStatus[ i ] = CABLE_UNKNOWN;
if ( !( Data & PHY_START_CABLE_DIAG ) )
{
ulLength[ i ] = ( Data & PHY_CABLE_FAULT_COUNTER ) *
CABLE_LEN_MULTIPLIER;
Data &= PHY_CABLE_DIAG_RESULT;
switch ( Data )
{
case PHY_CABLE_STAT_NORMAL:
bStatus[ i ] = CABLE_GOOD;
break;
case PHY_CABLE_STAT_OPEN:
bStatus[ i ] = CABLE_OPEN;
break;
case PHY_CABLE_STAT_SHORT:
bStatus[ i ] = CABLE_SHORT;
break;
}
}
if ( CABLE_GOOD == bStatus[ i ] )
{
ulLength[ i ] = 1;
}
}
#ifdef KS_PCI_BUS
phy = REG_PHY_1_CTRL_OFFSET + bPhy * PHY_CTRL_INTERVAL;
#else
HardwareSelectBank( pHardware, ( UCHAR )( REG_PHY_1_CTRL_BANK + phy *
PHY_BANK_INTERVAL ));
#endif
HW_WRITE_PHY_CROSSOVER( pHardware, phy, Crossover );
HW_WRITE_PHY_CTRL( pHardware, phy, Control );
Control |= PHY_AUTO_NEG_RESTART;
HW_WRITE_PHY_CTRL( pHardware, phy, Control );
ulLength[ 4 ] = ulLength[ 0 ];
bStatus[ 4 ] = bStatus[ 0 ];
for ( i = 1; i < 2; i++ )
{
if ( CABLE_GOOD == bStatus[ 4 ] )
{
if ( bStatus[ i ] != CABLE_GOOD )
{
bStatus[ 4 ] = bStatus[ i ];
ulLength[ 4 ] = ulLength[ i ];
break;
}
}
}
GetCableStatusDone:
/* Overall status */
*pulData++ = ulLength[ 4 ];
*pulData++ = bStatus[ 4 ];
/* Pair 1-2 */
*pulData++ = ulLength[ 0 ];
*pulData++ = bStatus[ 0 ];
/* Pair 3-6 */
*pulData++ = ulLength[ 1 ];
*pulData++ = bStatus[ 1 ];
/* Pair 4-5 */
*pulData++ = 0;
*pulData++ = CABLE_UNKNOWN;
/* Pair 7-8 */
*pulData++ = 0;
*pulData++ = CABLE_UNKNOWN;
} /* HardwareGetCableStatus */
/*
HardwareGetLinkStatus
Description:
This routine is used to get the link status.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
void* pBuffer
Buffer to store the link status.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareGetLinkStatus_PCI
#else
void HardwareGetLinkStatus_ISA
#endif
(
PHARDWARE pHardware,
UCHAR bPhy,
void* pBuffer )
{
PULONG pulData = ( PULONG ) pBuffer;
ULONG ulStatus;
USHORT Capable;
USHORT Crossover;
USHORT Data;
USHORT Link;
USHORT Polarity;
USHORT Status;
int phy;
phy = bPhy;
#ifdef KS_PCI_BUS
phy = REG_PHY_1_CTRL_OFFSET + bPhy * PHY_CTRL_INTERVAL;
#else
HardwareSelectBank( pHardware, ( UCHAR )( REG_PHY_1_CTRL_BANK + phy *
PHY_BANK_INTERVAL ));
#endif
HW_READ_PHY_LINK_STATUS( pHardware, phy, Capable );
ulStatus = 0;
if ( ( Capable & PHY_LINK_STATUS ) )
ulStatus = 1;
/* Link status */
*pulData++ = ulStatus;
#ifdef KS_PCI_BUS
{
ULONG ulAddr;
PORT_CTRL_ADDR( bPhy, ulAddr );
ulAddr += REG_PORT_STATUS_OFFSET;
HW_READ_WORD( pHardware, ulAddr, &Link );
}
#else
{
UCHAR bBank;
bBank = REG_PORT_LINK_STATUS_BANK + phy * PORT_BANK_INTERVAL;
HardwareSelectBank( pHardware, bBank );
HW_READ_WORD( pHardware, REG_PORT_STATUS_OFFSET, &Link );
HardwareSelectBank( pHardware, ( UCHAR )( REG_PHY_1_CTRL_BANK + phy *
PHY_BANK_INTERVAL ));
}
#endif
HW_READ_PHY_AUTO_NEG( pHardware, phy, Data );
HW_READ_PHY_REM_CAP( pHardware, phy, Status );
HW_READ_PHY_CROSSOVER( pHardware, phy, Crossover );
#ifdef KS_PCI_BUS
phy = REG_PHY_SPECIAL_OFFSET + bPhy * PHY_SPECIAL_INTERVAL;
#else
HardwareSelectBank( pHardware, REG_PHY_SPECIAL_BANK );
#endif
HW_READ_PHY_POLARITY( pHardware, phy, Polarity );
ulStatus = 100000;
if ( ( Link & PHY_STAT_SPEED_100MBIT ) )
ulStatus = 1000000;
/* Link speed */
*pulData++ = ulStatus;
ulStatus = 0;
if ( ( Link & PHY_STAT_FULL_DUPLEX ) )
ulStatus |= STATUS_FULL_DUPLEX;
if ( ( Polarity & PHY_STAT_MDIX ) )
ulStatus |= STATUS_CROSSOVER;
if ( ( Polarity & PHY_STAT_REVERSED_POLARITY ) )
ulStatus |= STATUS_REVERSED;
/* Duplex mode with crossover and reversed polarity */
*pulData++ = ulStatus;
ulStatus = 0;
if ( ( Capable & PHY_100BTX_FD_CAPABLE ) )
ulStatus |= LINK_100MBPS_FULL;
if ( ( Capable & PHY_100BTX_CAPABLE ) )
ulStatus |= LINK_100MBPS_HALF;
if ( ( Capable & PHY_10BT_FD_CAPABLE ) )
ulStatus |= LINK_10MBPS_FULL;
if ( ( Capable & PHY_10BT_CAPABLE ) )
ulStatus |= LINK_10MBPS_HALF;
ulStatus |= LINK_SYM_PAUSE;
/* Capability */
*pulData++ = ulStatus;
ulStatus = 0;
#if 0
if ( ( Data & PHY_AUTO_NEG_ASYM_PAUSE ) )
ulStatus |= LINK_ASYM_PAUSE;
#endif
if ( ( Data & PHY_AUTO_NEG_SYM_PAUSE ) )
ulStatus |= LINK_SYM_PAUSE;
if ( ( Data & PHY_AUTO_NEG_100BTX_FD ) )
ulStatus |= LINK_100MBPS_FULL;
if ( ( Data & PHY_AUTO_NEG_100BTX ) )
ulStatus |= LINK_100MBPS_HALF;
if ( ( Data & PHY_AUTO_NEG_10BT_FD ) )
ulStatus |= LINK_10MBPS_FULL;
if ( ( Data & PHY_AUTO_NEG_10BT ) )
ulStatus |= LINK_10MBPS_HALF;
if ( !( Crossover & PHY_AUTO_MDIX_DISABLE ) )
ulStatus |= LINK_AUTO_MDIX;
else if ( ( Crossover & PHY_FORCE_MDIX ) )
ulStatus |= LINK_MDIX;
ulStatus |= LINK_AUTO_POLARITY;
/* Auto-Negotiation advertisement */
*pulData++ = ulStatus;
ulStatus = 0;
#if 0
if ( ( Status & PHY_REMOTE_ASYM_PAUSE ) )
ulStatus |= LINK_ASYM_PAUSE;
#endif
if ( ( Status & PHY_REMOTE_SYM_PAUSE ) )
ulStatus |= LINK_SYM_PAUSE;
if ( ( Status & PHY_REMOTE_100BTX_FD ) )
ulStatus |= LINK_100MBPS_FULL;
if ( ( Status & PHY_REMOTE_100BTX ) )
ulStatus |= LINK_100MBPS_HALF;
if ( ( Status & PHY_REMOTE_10BT_FD ) )
ulStatus |= LINK_10MBPS_FULL;
if ( ( Status & PHY_REMOTE_10BT ) )
ulStatus |= LINK_10MBPS_HALF;
/* Link parnter capabilities */
*pulData++ = ulStatus;
} /* HardwareGetLinkStatus */
/*
HardwareSetCapabilities
Description:
This routine is used to set the link capabilities.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
ULONG ulCapabilities
A set of flags indicating different capabilities.
Return (None):
*/
#ifdef KS_PCI_BUS
void HardwareSetCapabilities_PCI
#else
void HardwareSetCapabilities_ISA
#endif
(
PHARDWARE pHardware,
UCHAR bPhy,
ULONG ulCapabilities )
{
#ifdef KS_PCI_BUS
ULONG InterruptMask;
#else
USHORT InterruptMask;
#endif
USHORT Data;
int phy;
int cnTimeOut = PHY_RESET_TIMEOUT;
InterruptMask = HardwareBlockInterrupt( pHardware );
HardwareDisable( pHardware );
phy = bPhy;
#ifdef KS_PCI_BUS
phy = REG_PHY_1_CTRL_OFFSET + bPhy * PHY_CTRL_INTERVAL;
#else
HardwareSelectBank( pHardware, ( UCHAR )( REG_PHY_1_CTRL_BANK + phy *
PHY_BANK_INTERVAL ));
#endif
HW_READ_PHY_AUTO_NEG( pHardware, phy, Data );
#if 0
if ( ( ulCapabilities & LINK_ASYM_PAUSE ) )
Data |= PHY_AUTO_NEG_ASYM_PAUSE;
else
Data &= ~PHY_AUTO_NEG_ASYM_PAUSE;
#endif
if ( ( ulCapabilities & LINK_SYM_PAUSE ) )
Data |= PHY_AUTO_NEG_SYM_PAUSE;
else
Data &= ~PHY_AUTO_NEG_SYM_PAUSE;
if ( ( ulCapabilities & LINK_100MBPS_FULL ) )
Data |= PHY_AUTO_NEG_100BTX_FD;
else
Data &= ~PHY_AUTO_NEG_100BTX_FD;
if ( ( ulCapabilities & LINK_100MBPS_HALF ) )
Data |= PHY_AUTO_NEG_100BTX;
else
Data &= ~PHY_AUTO_NEG_100BTX;
if ( ( ulCapabilities & LINK_10MBPS_FULL ) )
Data |= PHY_AUTO_NEG_10BT_FD;
else
Data &= ~PHY_AUTO_NEG_10BT_FD;
if ( ( ulCapabilities & LINK_10MBPS_HALF ) )
Data |= PHY_AUTO_NEG_10BT;
else
Data &= ~PHY_AUTO_NEG_10BT;
HW_WRITE_PHY_AUTO_NEG( pHardware, phy, Data );
HW_READ_PHY_CROSSOVER( pHardware, phy, Data );
if ( ( ulCapabilities & LINK_AUTO_MDIX ) )
Data &= ~( PHY_AUTO_MDIX_DISABLE | PHY_FORCE_MDIX );
else
{
Data |= PHY_AUTO_MDIX_DISABLE;
if ( ( ulCapabilities & LINK_MDIX ) )
Data |= PHY_FORCE_MDIX;
else
Data &= ~PHY_FORCE_MDIX;
}
HW_WRITE_PHY_CROSSOVER( pHardware, phy, Data );
HW_READ_PHY_CTRL( pHardware, phy, Data );
Data |= PHY_AUTO_NEG_RESTART;
HW_WRITE_PHY_CTRL( pHardware, phy, Data );
/* Wait for auto negotiation to complete. */
DelayMillisec( 1500 );
HW_READ_PHY_LINK_STATUS( pHardware, phy, Data );
while ( !( Data & PHY_LINK_STATUS ) )
{
if ( !--cnTimeOut )
{
break;
}
DelayMillisec( 100 );
HW_READ_PHY_LINK_STATUS( pHardware, phy, Data );
}
#ifdef DEBUG_TIMEOUT
cnTimeOut = PHY_RESET_TIMEOUT - cnTimeOut;
if ( pHardware->m_nWaitDelay[ WAIT_DELAY_AUTO_NEG ] < cnTimeOut )
{
DBG_PRINT( "phy auto neg: %d = %x"NEWLINE, cnTimeOut, ( int ) Data );
pHardware->m_nWaitDelay[ WAIT_DELAY_AUTO_NEG ] = cnTimeOut;
}
#endif
/* Check for disconnect. */
HardwareCheckLink( pHardware );
/* Check for connect. */
HardwareCheckLink( pHardware );
HardwareEnable( pHardware );
HardwareSetInterrupt( pHardware, InterruptMask );
} /* HardwareSetCapabilities */
/* -------------------------------------------------------------------------- */
/* #ifdef DEF_KS8841 */
/******************************************************************************
* void ks_byteNumberToBytelist
*
* DESCRIPTION:
* Convert byte number into a ByteList bit map.
*
* Byte numbers are zero-based up to 63
* The ByteList specifies a set of eight bytes, with the first octect specifying
* byte 0 through 7, the second octet specifying byte 8 though 15, and so on.
* The MSB of the octet represents the lowest numbered byte and LSB represents
* the hightest numbered byte.
*
* eg. if byte number 0 are configured (byte 0 is first byte),
* the byteNumber value is 0 ( byte 0 ), after convert,
* the *byteList value will be 80:00:00:00 (b31 is byte 0)
*
* PARAMETERS:
* DWORD byteNumber
* byte number (0 - byte 0, ... 63 - byte 63).
*
* BYTE *byteList
* pointer to a byte array.
*
* RETURNS: STATUS.
*
*/
static
void ks_byteNumberToBytelist
(
PHARDWARE pHardware,
BYTE byteNumber,
BYTE *byteList
)
{
/* swap the MSW with the LSW of a 32 bit integer */
#define LLSB(x) ((x) & 0xff)
#define LNLSB(x) (((x) >> 8) & 0xff)
#define LNMSB(x) (((x) >> 16) & 0xff)
#define LMSB(x) (((x) >> 24) & 0xff)
#define SWAPLONG(x) ((LLSB(x) << 24) | /
(LNLSB(x) << 16) | /
(LNMSB(x) << 8) | /
(LMSB(x)))
BYTE * dList;
BYTE byteIndex, byteIndexInByte, i;
BYTE bitMasks[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
UINT32 * pdwData = (UINT32 *)byteList;
for (byteIndex = 0; byteIndex < 32; byteIndex++)
{
/* get an octet */
i = byteIndex / 8;
dList = &byteList[i];
if ( byteNumber == byteIndex )
{
byteIndexInByte = byteIndex % 8;
/* set bit */
*dList |= bitMasks[8 - (byteIndexInByte + 1)];
}
}
/* host is big endian system */
if ( pHardware->m_boardBusEndianMode & 1 )
{
*pdwData = SWAPLONG(*pdwData);
}
} /* ks_byteNumberToBytelist */
/*
HardwareEnableWolMagicPacket
Description:
This routine is used to enable the Wake-on-LAN that wake-up signal is caused by
receipting of a Magic Packet.
KS8841 device can support D1, D2, or D3 power state by EEPROM setting.
By default, device supports D3 power state without EEPROM setting.
The example here is by default D3 power state.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareEnableWolMagicPacket
(
PHARDWARE pHardware
)
{
USHORT RegData=0;
/* Set power management capabilities */
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_POWER_CNTL_BANK );
HW_READ_WORD( pHardware, REG_POWER_CNTL_OFFSET, &RegData );
#else /* PCI bus */
HW_PCI_READ_WORD( pHardware, (CPMC), &RegData );
#endif
RegData &= POWER_STATE_MASK;
RegData |= ( POWER_PME_ENABLE | POWER_STATE_D3 );
#ifdef KS_ISA_BUS
HW_WRITE_WORD( pHardware, REG_POWER_CNTL_OFFSET, RegData );
#else /* PCI bus */
HW_PCI_WRITE_WORD( pHardware, (CPMC), RegData );
#endif
/* Enables the magic packet pattern detection */
RegData = 0;
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_WOL_CTRL_BANK );
#endif
HW_READ_WORD( pHardware, REG_WOL_CTRL_OFFSET, &RegData );
RegData |= ( WOL_MAGIC_ENABLE );
HW_WRITE_WORD( pHardware, REG_WOL_CTRL_OFFSET, RegData );
}
/*
HardwareEnableWolFrame
Description:
This routine is used to enable the Wake-on-LAN that wake-up signal is caused by
receipting of a 'wake-up' packet. The device can support four different
'wake-up' frames.
KS8841 device can support D1, D2, or D3 power state by EEPROM setting.
By default, device supports D3 power state without EEPROM setting.
The example here is by default D3 power state.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UINT32 dwFrame
whose wake up frame to be enabled (0 - Frame 0, 1 - Frame 1, 2 - Frame 2, 3 - Frame 3).
Return (None):
*/
void HardwareEnableWolFrame
(
PHARDWARE pHardware,
UINT32 dwFrame
)
{
USHORT RegData;
/* Set power management capabilities */
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_POWER_CNTL_BANK );
HW_READ_WORD( pHardware, REG_POWER_CNTL_OFFSET, &RegData );
#else /* PCI bus */
HW_PCI_READ_WORD( pHardware, (CPMC), &RegData );
#endif
RegData &= POWER_STATE_MASK;
RegData |= ( POWER_PME_ENABLE | POWER_STATE_D3 );
#ifdef KS_ISA_BUS
HW_WRITE_WORD( pHardware, REG_POWER_CNTL_OFFSET, RegData );
#else /* PCI bus */
HW_PCI_WRITE_WORD( pHardware, (CPMC), RegData );
#endif
/* Enables the wake up frame pattern detection */
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_WOL_CTRL_BANK );
#endif
HW_READ_WORD( pHardware, REG_WOL_CTRL_OFFSET, &RegData );
switch (dwFrame)
{
case 0:
RegData |= ( WOL_FRAME0_ENABLE );
break;
case 1:
RegData |= ( WOL_FRAME1_ENABLE );
break;
case 2:
RegData |= ( WOL_FRAME2_ENABLE );
break;
case 3:
RegData |= ( WOL_FRAME3_ENABLE );
break;
}
HW_WRITE_WORD( pHardware, REG_WOL_CTRL_OFFSET, RegData );
}
/*
HardwareSetWolFrameCRC
Description:
This routine is used to set the expected 32-bit CRC value of the 'Wake up'
frame pattern.
The device can support four different 'wake-up' frames.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UINT32 dwFrame
whose wake up frame CRC to be set (0 - Frame 0, 1 - Frame 1, 2 - Frame 2, 3 - Frame 3).
UINT32 dwCRC
expected 32bit CRC value.
Return (None):
*/
void HardwareSetWolFrameCRC
(
PHARDWARE pHardware,
UINT32 dwFrame,
UINT32 dwCRC
)
{
#ifdef KS_ISA_BUS
UCHAR bWolBank;
#endif
if ( dwFrame > 3 )
return;
/* Set expected 32bit CRC value Frame # register */
#ifdef KS_ISA_BUS
bWolBank = ( REG_WOL_FRAME_0_BANK + dwFrame );
HardwareSelectBank( pHardware, bWolBank );
#endif
HW_WRITE_DWORD( pHardware, WOL_FRAME_CRC_OFFSET, dwCRC );
}
/*
HardwareSetWolFrameByteMask
Description:
This routine is used to set the byte mask within 64 byte of the 'Wake up'
frame pattern to calculate CRC value.
The device can support four different 'wake-up' frames.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
UINT32 dwFrame
whose wake up frame byte mask to be set (0 - Frame 0, 1 - Frame 1, 2 - Frame 2, 3 - Frame 3).
UINT8 bByteMask
byte number to mask to calculate CRC value (0 - byte 0, 63 - byte 63).
Return (None):
*/
void HardwareSetWolFrameByteMask
(
PHARDWARE pHardware,
UINT32 dwFrame,
UINT8 bByteMask
)
{
UINT32 RegData=0;
UINT32 * pdwData;
UCHAR byteList[4];
#ifdef KS_ISA_BUS
UCHAR bWolBank;
UCHAR bWolFrameOffset;
#else
USHORT bWolFrameOffset;
#endif
if ( dwFrame > 3 )
return;
if ( bByteMask > 63 )
return;
if ( bByteMask > 31 )
{
bWolFrameOffset = WOL_FRAME_BYTE2_OFFSET;
bByteMask -= 32;
}
else
{
bWolFrameOffset = WOL_FRAME_BYTE0_OFFSET;
}
pdwData = (UINT32 *)byteList;
memset ( &byteList[0], 0, 4);
ks_byteNumberToBytelist( pHardware, bByteMask, byteList );
/* Set byte mask for the device to calculate 32bit CRC value from the Frame pattern */
#ifdef KS_ISA_BUS
bWolBank = ( REG_WOL_FRAME_0_BANK + dwFrame );
HardwareSelectBank( pHardware, bWolBank );
#endif
HW_READ_DWORD( pHardware, bWolFrameOffset, &RegData );
RegData |= *pdwData;
HW_WRITE_DWORD( pHardware, bWolFrameOffset, RegData );
}
/*
HardwareCheckWolPMEStatus
Description:
This function is used to check PMEN pin is asserted.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (BOOLEAN):
TRUE if PMEN pin is asserted; otherwise, FALSE.
*/
BOOLEAN HardwareCheckWolPMEStatus
(
PHARDWARE pHardware
)
{
USHORT RegData = 0;
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_POWER_CNTL_BANK );
HW_READ_WORD( pHardware, REG_POWER_CNTL_OFFSET, &RegData );
#else /* PCI bus */
HW_PCI_READ_WORD( pHardware, (CPMC), &RegData );
#endif
return(( RegData & POWER_PME_STATUS ) == POWER_PME_STATUS );
} /* HardwareCheckWolPMEStatus */
/*
HardwareClearWolPMEStatus
Description:
This routine is used to clear PME_Status to deassert PMEN pin.
Parameters:
PHARDWARE pHardware
Pointer to hardware instance.
Return (None):
*/
void HardwareClearWolPMEStatus
(
PHARDWARE pHardware
)
{
USHORT RegData=0;
/* Clear PME_Status to deassert PMEN pin */
#ifdef KS_ISA_BUS
HardwareSelectBank( pHardware, REG_POWER_CNTL_BANK );
HW_READ_WORD( pHardware, REG_POWER_CNTL_OFFSET, &RegData );
#else /* PCI bus */
HW_PCI_READ_WORD( pHardware, (CPMC), &RegData );
#endif
RegData |= ( POWER_PME_STATUS );
#ifdef KS_ISA_BUS
HW_WRITE_WORD( pHardware, REG_POWER_CNTL_OFFSET, RegData );
#else /* PCI bus */
HW_PCI_WRITE_WORD( pHardware, (CPMC), RegData );
#endif
}
/* #endif *//* #ifdef DEF_KS8841 */
/* -------------------------------------------------------------------------- */
static UCHAR TestPacket[] =
{
/* 0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* ff:ff:ff:ff:ff:ff (DA) */
/* 6 */ 0x08, 0x00, 0x70, 0x22, 0x44, 0x55, /* 08:00:70:22:44:55 (SA) */
/* 12 */ 0x08, 0x06, /* ARP */
/* 14 */ 0x00, 0x01, /* Ethernet */
/* 16 */ 0x08, 0x00, /* IP */
/* 18 */ 0x06, 0x04,
/* 20 */ 0x00, 0x01, /* Request */
/* 22 */ 0x08, 0x00, 0x70, 0x22, 0x44, 0x55, /* 08:00:70:22:44:55 (SA) */
/* 28 */ 0xC0, 0xA8, 0x01, 0x01, /* 192.168.1.1 (Source IP) */
/* 32 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00:00:00:00:00:00 (DA) */
/* 38 */ 0xC0, 0xA8, 0x01, 0x1E, /* 192.168.1.30 (Dest IP) */
/* 42 */ 0x5A, 0xA5, /* Data */
};
/* -------------------------------------------------------------------------- */
/*-----------------------------------------------------------------
.
. The driver can be entered at any of the following entry points.
.
.------------------------------------------------------------------ */
extern int eth_init(bd_t *bd);
extern void eth_halt(void);
extern int eth_rx(void);
extern int eth_send(volatile void *packet, int length);
static HARDWARE hw;
static PHARDWARE pHardware = &hw;
static int poll4int ( WORD mask, int timeout ) { int tmo = get_timer( 0 ) +
timeout * CFG_HZ; int is_timeout = 0; WORD IntEnable;
HardwareReadInterrupt( pHardware, &IntEnable );
while ( ( IntEnable & mask ) == 0 ) {
if ( get_timer( 0 ) >= tmo ) {
is_timeout = 1;
break;
}
HardwareReadInterrupt( pHardware, &IntEnable );
}
if ( ( IntEnable & INT_TX ) ) {
HardwareAcknowledgeInterrupt( pHardware, INT_TX );
}
if ( ( IntEnable & INT_PHY ) ) {
SwitchGetLinkStatus( pHardware );
HardwareAcknowledgeInterrupt( pHardware, INT_PHY );
}
if ( is_timeout )
return 1;
else
return 0;
} /* poll4int */
static int atoi (int i)
{
if( i >= '0' && i <= '9' )
return i-'0';
else if( i >= 'a' && i <= 'f' )
return i - 'a' + 10;
else if( i >= 'A' && i <= 'F' )
return i - 'A' + 10;
else {
printf("Input for ASCII conversion is wrong[0x%x]/n",i);
return i;
}
} /* atoi */
void ks884x_getmac ( void )
{
unsigned char *fp;
unsigned char temp[ 32 ];
memset( temp, 0x00, sizeof( temp ));
fp = (unsigned char *)getenv( "ethaddr" );
if ( fp != NULL ) {
pHardware->m_bOverrideAddress[ 0 ] =
( atoi( *( fp + 0 )) << 4 | atoi( *( fp + 1 )) );
pHardware->m_bOverrideAddress[ 1 ] =
( atoi( * (fp + 3 )) << 4 | atoi( *( fp + 4 )) );
pHardware->m_bOverrideAddress[ 2 ] =
( atoi( *( fp + 6 )) << 4 | atoi( *( fp + 7 )) );
pHardware->m_bOverrideAddress[ 3 ] =
( atoi( *( fp + 9 )) << 4 | atoi( *( fp + 10 )) );
pHardware->m_bOverrideAddress[ 4 ] =
( atoi( *( fp + 12 )) << 4 | atoi( *( fp + 13 )) );
pHardware->m_bOverrideAddress[ 5 ] =
( atoi( *( fp + 15 )) << 4 | atoi( *( fp + 16 )) );
pHardware->m_bMacOverrideAddr = TRUE;
}
} /* ks884x_getmac */
/*
. ks884x_enable
.
. This lets the chip talk to the outside world
.
. Method:
. 1. Enable the transmitter
. 2. Enable the receiver
. 3. Enable interrupts
*/
static void ks884x_enable ( void )
{
HardwareEnable( pHardware );
HardwareEnableInterrupt( pHardware );
#if defined(DEF_KS8841)
poll4int( INT_PHY, TX_TIMEOUT );
#endif
} /* ks884x_enable */
/*
. ks884x_halt
.
. This closes down the KS884X chip.
.
. Method:
. 1. zero the interrupt mask
. 2. clear the enable receive flag
. 3. clear the enable xmit flags
*/
static void ks884x_halt ( void )
{
HardwareDisableInterrupt( pHardware );
HardwareDisable( pHardware );
} /* ks884x_shutdown */
static struct hw_fn _ks8842_fn_;
static struct hw_fn* ks8842_fn = &_ks8842_fn_;
static int ks884x_initialised = 0;
int ks884x_init ( bd_t *bd )
{
if ( !ks884x_initialised ) {
ks884x_initialised = 1;
DBG_PRINT( "%s"NEWLINE, version );
ks8842_fn->m_fPCI = FALSE;
memset( &hw, 0, sizeof( HARDWARE ));
hw.m_ulVIoAddr = CONFIG_KS8841_BASE;
hw.m_pVirtualMemory = ( void* ) CONFIG_KS8841_BASE;
hw.m_wPhyAddr = 0;
HardwareInitialize( &hw );
hw.m_hwfn = ks8842_fn;
ks884x_getmac();
HardwareReadAddress( &hw );
/* update global address to match env (allows env changing) */
memcpy( bd->bi_enetaddr, hw.m_bOverrideAddress, 6 );
hw.m_bPort = MAIN_PORT;
pHardware->m_bPromiscuous = TRUE;
pHardware->m_bAllMulticast = FALSE;
pHardware->m_bMulticastListSize = 0;
HardwareReset( pHardware );
HardwareSetup( pHardware );
HardwareSwitchSetup( pHardware );
if ( pHardware->m_bMacOverrideAddr )
HardwareSetAddress( pHardware );
HardwareSetupInterrupt( pHardware );
}
ks884x_enable();
return TRUE;
} /* KS884X_Init */
int ks884x_rcv ( void )
{
int packet_length;
WORD rx_mem;
/* Acknowledge the interrupt. */
HardwareAcknowledgeReceive( pHardware );
HardwareReadRegWord( pHardware, REG_RX_MEM_INFO_BANK,
REG_RX_MEM_INFO_OFFSET, &rx_mem );
if ( rx_mem ) {
packet_length = HardwareReceiveLength( pHardware );
if ( packet_length ) {
HardwareReceiveBuffer( pHardware, pHardware->m_bLookahead,
packet_length );
/* Notify upper layer for received packet. */
/* Pass the packet up to the protocol layers. */
MOVE_MEM(( void* )NetRxPackets[ 0 ], pHardware->m_bLookahead, packet_length );
NetReceive( NetRxPackets[ 0 ], packet_length );
}
return packet_length;
}
return 0;
} /* ks884x_rcv */
int ks884x_send (volatile void *packet, int packet_length)
{
int len;
int rc = 0;
len = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;
if ( HardwareAllocPacket( pHardware, len ) ) {
MOVE_MEM( pHardware->m_bLookahead, ( void* ) packet, len );
HardwareSetTransmitLength( pHardware, len );
HW_WRITE_BUFFER( pHardware, REG_DATA_OFFSET, pHardware->m_bLookahead,
len );
#ifdef SH_16BIT_WRITE
HW_WRITE_WORD( pHardware, REG_TXQ_CMD_OFFSET, TXQ_CMD_ENQUEUE_PACKET );
#else
HW_WRITE_BYTE( pHardware, REG_TXQ_CMD_OFFSET, TXQ_CMD_ENQUEUE_PACKET );
#endif
rc = len;
/* poll for TX INT */
if ( poll4int( INT_TX, TX_TIMEOUT ) ) {
/* sending failed */
DBG_PRINT( "%s: TX timeout, sending failed..."NEWLINE, DRV_NAME );
return 0;
}
}
return rc;
} /* ks884x_send */
int eth_init (bd_t *bd)
{
return ks884x_init( bd );
}
void eth_halt()
{
ks884x_halt();
}
int eth_rx()
{
return ks884x_rcv();
}
int eth_send(volatile void *packet, int length)
{
return ks884x_send(packet, length);
}
#endif /* defined( CONFIG_DRIVER_KS8841 ) || defined( CONFIG_DRIVER_KS8842 ) */