📄 smc9218.c
字号:
if ( lp->mii.force_media ) {
smc911x_phy_fixed( ei_local );
goto smc911x_phy_configure_exit;
}
/* Copy our capabilities from MII_BMSR to MII_ADVERTISE */
SMC_GET_PHY_BMSR( phyaddr, my_phy_caps );
if (!( my_phy_caps & BMSR_ANEGCAPABLE )) {
smc911x_phy_fixed( ei_local );
goto smc911x_phy_configure_exit;
}
/* CSMA capable w/ both pauses */
my_ad_caps = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
if ( my_phy_caps & BMSR_100BASE4 )
my_ad_caps |= ADVERTISE_100BASE4;
if ( my_phy_caps & BMSR_100FULL )
my_ad_caps |= ADVERTISE_100FULL;
if ( my_phy_caps & BMSR_100HALF )
my_ad_caps |= ADVERTISE_100HALF;
if ( my_phy_caps & BMSR_10FULL )
my_ad_caps |= ADVERTISE_10FULL;
if ( my_phy_caps & BMSR_10HALF )
my_ad_caps |= ADVERTISE_10HALF;
/* Disable capabilities not selected by our user */
if ( lp->ctl_rspeed != 100 )
my_ad_caps &= ~( ADVERTISE_100BASE4 | ADVERTISE_100FULL | ADVERTISE_100HALF );
if (! lp->ctl_rfduplx )
my_ad_caps &= ~( ADVERTISE_100FULL | ADVERTISE_10FULL );
/* Update our Auto-Neg Advertisement Register */
SMC_SET_PHY_MII_ADV( phyaddr, my_ad_caps );
lp->mii.advertising = my_ad_caps;
/*
* Read the register back. Without this, it appears that when
* auto-negotiation is restarted, sometimes it isn't ready and
* the link does not come up.
*/
udelay( 10 );
SMC_GET_PHY_MII_ADV( phyaddr, status );
/* Restart auto-negotiation process in order to advertise my caps */
SMC_SET_PHY_BMCR( phyaddr, BMCR_ANENABLE | BMCR_ANRESTART );
smc911x_phy_check_media( ei_local, 1 );
smc911x_phy_configure_exit:
smc911x_phy_configure_exit_nolock:
lp->work_pending = 0;
}
/*
* Enable Interrupts, Receive, and Transmit
*/
static void smc911x_enable( struct ei_device* ei_local )
{
unsigned int ioaddr = ei_local->base;
unsigned int mask, cfg, cr;
/* 装入MAC地址 */
SMC_SET_MAC_ADDR( ei_local->paddr);
/* Enable TX */
cfg = SMC_GET_HW_CFG();
cfg &= HW_CFG_TX_FIF_SZ_ | 0xFFF; /* 配置 */
cfg |= HW_CFG_SF_;
SMC_SET_HW_CFG( cfg );
SMC_SET_FIFO_TDA( 0xFF ); /* FIFO中断配置 */
SMC_SET_FIFO_TSL( 64 ); /* Update TX stats on every 64 packets received or every 1 sec */
//SMC_SET_GPT_CFG( GPT_CFG_TIMER_EN_ | 10000 ); /* 定时器设置 */
SMC_GET_MAC_CR( cr );
cr &= ~ MAC_CR_PRMS_;
cr |= MAC_CR_TXEN_ | MAC_CR_FDPX_ /*| MAC_CR_HBDIS_ */;
SMC_SET_MAC_CR( cr );
SMC_SET_TX_CFG( TX_CFG_TX_ON_ );
/* Add 2 byte padding to start of packets */
SMC_SET_RX_CFG( RX_CFG_RX_END_ALGN4_ | (( 2 << 8 ) & RX_CFG_RXDOFF_ ));
//SMC_SET_TX_CFG((2<<8) & RX_CFG_RXDOFF_);
/* Turn on receiver and enable RX */
cr = cr | MAC_CR_RXEN_ ;
SMC_SET_MAC_CR( cr );
/* Interrupt on every received packet */
SMC_SET_FIFO_RSA( 0x01 ); /* RSA */
SMC_SET_FIFO_RSL( 0x00 ); /* RSL */
#if 0
/* now, enable interrupts */
mask = INT_EN_RSFL_EN_ | INT_EN_RXE_EN_ ;
// mask = INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_ | INT_EN_RSFL_EN_ |
// INT_EN_GPT_INT_EN_ | INT_EN_RXDFH_INT_EN_ | INT_EN_RXE_EN_ |
// INT_EN_PHY_INT_EN_;
if ( IS_REV_A( lp->revision ))
mask |= INT_EN_RDFL_EN_;
else {
mask |= INT_EN_RXDF_EN_;
}
#endif
mask = 0x6008; /* 中断掩码 */
/* 使能LED */
SMC_SET_GPIO_CFG( 7 << 28 );
SMC_ENABLE_INT( mask );
}
/*******************************************************************************
**初始化网络控制芯片控制结构接口
*******************************************************************************/
static void smc9218_init_prep( struct ei_device * ei_local )
{
unsigned int ioaddr; /* IO基地址 */
struct smc911x_local * lp; /* 私有控制结构 */
ioaddr = ei_local->base; /* 获取基地址 */
lp = ( struct smc911x_local *)malloc( sizeof( struct smc911x_local ));
memset( lp, 0, sizeof( struct smc911x_local )); /* 初始化 */
ei_local->data = (void*)lp;
lp->netdev = ei_local;
lp->version = SMC_GET_PN();
lp->revision = SMC_GET_REV();
lp->tx_fifo_kb = tx_fifo_kb;
/* Reverse calculate the RX FIFO size from the TX */
lp->tx_fifo_size = ( lp->tx_fifo_kb << 10 ) - 512; /* 缺省设置 */
lp->rx_fifo_size = (( 0x4000 - 512 - lp->tx_fifo_size ) / 16 ) * 15; /* 缺省设置 */
/* Set the automatic flow control values */
switch( lp->tx_fifo_kb ) {
/*
* AFC_HI is about ((Rx Data Fifo Size)*2/3)/64
* AFC_LO is AFC_HI/2
* BACK_DUR is about 5uS*(AFC_LO) rounded down
*/
case 2:/* 13440 Rx Data Fifo Size */
lp->afc_cfg = 0x008C46AF; break; /* 13440 Rx Data Fifo Size */
case 3:/* 12480 Rx Data Fifo Size */
lp->afc_cfg = 0x0082419F; break; /* 12480 Rx Data Fifo Size */
case 4:/* 11520 Rx Data Fifo Size */
lp->afc_cfg = 0x00783C9F; break; /* 11520 Rx Data Fifo Size */
case 5:/* 10560 Rx Data Fifo Size */
lp->afc_cfg = 0x006E374F; break; /* 10560 Rx Data Fifo Size */
case 6:/* 9600 Rx Data Fifo Size */
lp->afc_cfg = 0x0064328F; break; /* 9600 Rx Data Fifo Size */
case 7:/* 8640 Rx Data Fifo Size */
lp->afc_cfg = 0x005A2D7F; break; /* 8640 Rx Data Fifo Size */
case 8:/* 7680 Rx Data Fifo Size */
lp->afc_cfg = 0x0050287F; break; /* 7680 Rx Data Fifo Size */
case 9:/* 6720 Rx Data Fifo Size */
lp->afc_cfg = 0x0046236F; break; /* 6720 Rx Data Fifo Size */
case 10:/* 5760 Rx Data Fifo Size */
lp->afc_cfg = 0x003C1E6F; break; /* 5760 Rx Data Fifo Size */
case 11:/* 4800 Rx Data Fifo Size */
lp->afc_cfg = 0x0032195F; break; /* 4800 Rx Data Fifo Size */
/*
* AFC_HI is ~1520 bytes less than RX Data Fifo Size
* AFC_LO is AFC_HI/2
* BACK_DUR is about 5uS*(AFC_LO) rounded down
*/
case 12:/* 3840 Rx Data Fifo Size */
lp->afc_cfg = 0x0024124F; break; /* 3840 Rx Data Fifo Size */
case 13:/* 2880 Rx Data Fifo Size */
lp->afc_cfg = 0x0015073F; break; /* 2880 Rx Data Fifo Size */
case 14:/* 1920 Rx Data Fifo Size */
lp->afc_cfg = 0x0006032F; break; /* 1920 Rx Data Fifo Size */
default:
break;
}
/* MII初始化 */
lp->mii.phy_id_mask = 0x1f; /* 缺省设置 */
lp->mii.reg_num_mask = 0x1f; /* 缺省设置 */
lp->mii.force_media = 0; /* 缺省设置 */
lp->mii.full_duplex = 1; /* 缺省设置 */
lp->mii.dev = lp->netdev;
lp->mii.mdio_read = smc911x_phy_read;
lp->mii.mdio_write = smc911x_phy_write;
//smc911x_reset( iface );
/*
* Locate the phy, if any.
*/
smc911x_phy_detect( ei_local );
lp->msg_enable = 1; /* MSG_ENABLE */
lp->ctl_rfduplx = 1; /* 缺省设置 */
lp->ctl_rspeed = 100; /* 缺省设置 */
}
/* 初始化芯片,然后启动运行 */
static int smc9218_init( struct ei_device * ei_local )
{
/* Configure the PHY, initialize the link state */
smc911x_phy_configure( ei_local );
/* Turn on Tx + Rx */
smc911x_enable( ei_local );
return 0;
}
/* 发送处理函数
iface : 网络接口
buffer: 待发送的数据
len: 待发送的数据长度
*/
static void smc9218_send_packet( struct ei_device * ei_local, char * buffer, unsigned int length )
{
unsigned int ioaddr = ei_local->base;
struct smc911x_local * lp = ( struct smc911x_local *)ei_local->data;
unsigned int cmdA, cmdB, len;
unsigned int free;
unsigned status;
unsigned char * buf;
IRQ_disable( 6 ); /* 关闭中断 */
while((( SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_ ) >> 16 ) != 0 ) /* TX FIFO */
{
status = SMC_GET_TX_STS_FIFO();
lp->stat.tx_packets ++;
lp->stat.tx_bytes += ( status >> 16 ); /* 发送数据长度 */
}
free = SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TDFREE_;
/* Turn off the flow when running out of space in FIFO */
#if 0
if ( free <= SMC911X_TX_FIFO_LOW_THRESHOLD ) {
/* Reenable when at least 1 packet of size MTU present */
SMC_SET_FIFO_TDA(( SMC911X_TX_FIFO_LOW_THRESHOLD )/ 64 ); /* 重新设置可用发送区 */
lp->tx_throttle = 1;
}
#endif
/* Drop packets when we run out of space in TX FIFO
* Account for overhead required for:
*
* Tx command words 8 bytes
* Start offset 15 bytes
* End padding 15 bytes
*/
if ( free < ( length + 8 + 15 + 15 )) { /* 比较空闲位置 */
lp->stat.tx_errors ++;
lp->stat.tx_dropped ++;
IRQ_enable( 6 ); /* 开启中断 */
return ;
}
/* 计数缓存地址 */
buf = ( unsigned char *)(( unsigned int )( buffer + 2 ) & ~ 0x3 );
/* 计数发送长度 */
len = ( length + 3 + (( unsigned int )( buffer + 2 ) & 3 )) & ~ 0x3;
/* 填写命令A */
cmdA = ((( unsigned int )( buffer + 2 ) & 0x3 ) << 16 ) | TX_CMD_A_INT_FIRST_SEG_
| TX_CMD_A_INT_LAST_SEG_ | length ;
/* tag is packet length so we can use this in stats update later */
cmdB = ( length << 16 ) | ( length & 0x7FF ); /* COMMAND B 构造 */
SMC_SET_TX_FIFO( cmdA );
SMC_SET_TX_FIFO( cmdB );
SMC_PUSH_DATA(( unsigned int *)buf, len );
IRQ_enable( 6 );/* 开启中断 */
}
static void smc911x_drop_pkt( struct ei_device* ei_local )
{
unsigned int ioaddr = ei_local->base;
unsigned int fifo_count, timeout, reg;
fifo_count = SMC_GET_RX_FIFO_INF() & 0xFFFF; /* 当前接收FIFO数目 */
if ( fifo_count <= 4 ) { /* 如果数目小于4 */
/* Manually dump the packet data */
while ( fifo_count --)
SMC_GET_RX_FIFO();
} else {
/* Fast forward through the bad packet */
SMC_SET_RX_DP_CTRL( RX_DP_CTRL_FFWD_BUSY_ );
timeout = 50; /* 超时设置 */
do {
// udelay( 10 ); /* 延时 */
reg = SMC_GET_RX_DP_CTRL() & RX_DP_CTRL_FFWD_BUSY_;
} while ( timeout -- && reg );
}
}
extern far SWI_Obj NET_swi;
extern far SWI_Handle NET_swi_handle = & NET_swi;
/* 接收数据 */
static void smc9218_rcv( struct ei_device * ei_local )
{
unsigned int ioaddr = ei_local->base;
struct smc911x_local * lp = ( struct smc911x_local *)ei_local->data;
unsigned int pkt_len, status;
void * skb; /* 网络缓冲区结构指针 */
unsigned char * data;
char times = 10; /* 循环10次 */
int recved = 0;
/* 查询接收FIFO */
status = SMC_GET_RX_FIFO_INF() >> 16;
/* 没有数据 */
while( status != 0 && times -- )
{
status = SMC_GET_RX_STS_FIFO();
pkt_len = ( status & RX_STS_PKT_LEN_ ) >> 16; /* 报文长度 */
if ( status & RX_STS_ES_ ) {
/* Deal with a bad packet */
lp->stat.rx_errors ++;
if ( status & RX_STS_CRC_ERR_ )
lp->stat.rx_crc_errors ++;
else {
if ( status & RX_STS_LEN_ERR_ )
lp->stat.rx_length_errors ++;
if ( status & RX_STS_MCAST_ )
lp->stat.multicast ++;
}
/* Remove the bad packet data from the RX FIFO */
smc911x_drop_pkt( ei_local );
}
else {
/* Receive a valid packet */
/* Alloc a buffer with extra room for DMA alignment */
skb = get_skb( pkt_len, ( char **)& data );
if ( skb == NULL )
{
lp->stat.rx_dropped ++;
smc911x_drop_pkt( ei_local );
break;
}
SMC_SET_RX_CFG( RX_CFG_RX_END_ALGN4_ | (( 2 << 8 ) & RX_CFG_RXDOFF_ )); /* RX 配置*/
//FCT_WordToByte(( void *)data, ( void *)ioaddr, ( int )(( pkt_len + 3 )>> 2 ));/* 接收数据 */
SMC_PULL_DATA( ( unsigned int *)data, pkt_len + 2 + 3 ); /* 接收数据 */
set_skb( ei_local->iface, skb, pkt_len - 18 ); /* 设置skb结构 */
lp->stat.rx_packets ++;
lp->stat.rx_bytes += pkt_len - 18; /* 统计收到的字节数目 */
recved ++;
}
status = SMC_GET_RX_FIFO_INF() >> 16;/* 读取状态字 */
}
if( recved )
SWI_post( NET_swi_handle );
}
/* 中断处理函数 */
void Smc9218Int( voide )
{
unsigned int ioaddr;
unsigned int status, dummy;
unsigned int iface;
for( iface = 0; iface < iface_num; iface++)
{
if( devs[iface].func_table != lan9218_driver)
continue;
/* 如果属于该驱动 */
ioaddr = devs[iface].base;
dummy = SMC_GET_IRQ_CFG();
dummy &= 0xfffffeff; /* 关闭中断 */
SMC_SET_IRQ_CFG( dummy );
SMC_ACK_INT( 0xffffffff ); /* 回应中断 */
status = SMC_GET_INT();
if ( status & INT_STS_RSFL_ )
smc9218_rcv( &devs[iface] );
dummy |= 0x100; /* 重新打开中断 */
SMC_SET_IRQ_CFG( dummy );
}
return;
}
unsigned int mii_check_media ( struct mii_if_info * mii,
int init_media )
{
unsigned int old_carrier, new_carrier;
int advertise, lpa, media, duplex;
int lpa2 = 0;
/* if forced media, go no further */
if ( mii->force_media )
return 0; /* duplex did not change */
/* check current and old link status */
old_carrier = 0;
new_carrier = 1;
/* if carrier state did not change, this is a "bounce",
* just exit as everything is already set correctly
*/
if ((! init_media ) && ( old_carrier == new_carrier ))
return 0; /* duplex did not change */
/*
* we have carrier, see who's on the other end
*/
/* get MII advertise and LPA values */
if ((! init_media ) && ( mii->advertising ))
advertise = mii->advertising;
else {
advertise = mii->mdio_read( mii->dev, mii->phy_id, MII_ADVERTISE );
mii->advertising = advertise;
}
lpa = mii->mdio_read( mii->dev, mii->phy_id, MII_LPA );
if ( mii->supports_gmii )
lpa2 = mii->mdio_read( mii->dev, mii->phy_id, MII_STAT1000 );
/* figure out media and duplex from advertise and LPA values */
media = mii_nway_result( lpa & advertise );
duplex = ( media & ADVERTISE_FULL ) ? 1 : 0;
if ( lpa2 & LPA_1000FULL )
duplex = 1;
if (( init_media ) || ( mii->full_duplex != duplex )) {
mii->full_duplex = duplex;
return 1; /* duplex changed */
}
return 0; /* duplex did not change */
}
static inline unsigned int mii_nway_result ( unsigned int negotiated )
{
unsigned int ret;
if ( negotiated & LPA_100FULL )
ret = LPA_100FULL;
else if ( negotiated & LPA_100BASE4 )
ret = LPA_100BASE4;
else if ( negotiated & LPA_100HALF )
ret = LPA_100HALF;
else if ( negotiated & LPA_10FULL )
ret = LPA_10FULL;
else
ret = LPA_10HALF;
return ret;
}
static int set_promisc( struct ei_device * ei_local )
{
unsigned int cr;
unsigned int ioaddr = ei_local->base;
SMC_GET_MAC_CR( cr );
cr |= MAC_CR_PRMS_;
SMC_SET_MAC_CR( cr );
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -