📄 i82559.c
字号:
printf("i82559 CBL Configure Command Timed Out\n");
return CBL_CMD_CFG_TIMEOUT;
}
return 0;
}
//--------------------------------------------------------------------------
// i82559_send()
//
// This function tells the i82559 to send the tx buffer pointed to by tx_buf
//
vulong i82559_send(uchar *txbuf, vulong length)
{
vulong i, timeout;
vushort temp16;
vuchar *from_p, *to_p;
if (i82559_found == 0) return 0;
// build the header
WR_SM16(i82559_tfd_base + CBL_STAT, 0);
WR_SM16(i82559_tfd_base + CBL_CMD, (CBL_CMD_TX | CBL_CMD_EL));
WR_SM32(i82559_tfd_base + CBL_LINK, (i82559_tfd_base & 0x0fffffff));
WR_SM32(i82559_tfd_base + CBL_TxCB_TBD, 0xffffffff);
WR_SM16(i82559_tfd_base + CBL_TxCB_CNT, (length | CBL_TxCB_CNT_EOF));
WR_SM8(i82559_tfd_base + CBL_TxCB_THRESH, 16);
WR_SM8(i82559_tfd_base + CBL_TxCB_TBD_NUM, 0);
from_p = txbuf;
to_p = (vuchar *)(i82559_tfd_base + CBL_TxCB_DATA);
// copy the data into the shared memory area
for (i = 0; i < length; i++){
WR_SM8(to_p++, *from_p++);
}
// wait for the CU to be idle
i82559_wait_for_cu_cmd();
// issue the command to the i82559
WR_SM32(i82559_scb + SCB_PTR, (i82559_tfd_base & 0x0fffffff));
WR_SM16(i82559_scb + SCB_CMD, SCB_CU_START | SCB_IM_M);
// wait for the CU to be idle
i82559_wait_for_cu_cmd();
// Now check the CBL Status word
timeout = 10000;
while(timeout){
// delay before each check
udelay(10);
RD_SM16(i82559_cbl + CBL_STAT, temp16);
if (temp16 & CBL_STAT_C){
if (temp16 & CBL_STAT_OK){
return 0;
}
else {
return CBL_CMD_TX_ERR;
}
}
timeout--;
}
if (timeout == 0){
return CBL_CMD_TX_TIMEOUT;
}
return 0;
}
//--------------------------------------------------------------------------
// i82559_rx_get()
//
// This function checks the list of rx buffers to see if any of them are
// ready to be received. If so, it copies the first ready buffer to
// pktbuf. It then resumes the RU if it was suspended and returns the
// packet length. This function also acts to start the receiver when
// called for the first time.
//
vushort i82559_rx_get(vuchar *pktbuf)
{
vulong i, x, rfd;
vushort temp16, rx_cmd, length;
vuchar *from_p, *to_p;
if (i82559_found == 0) return 0;
rfd = i82559_rfd_base;
// scan the rx list looking for ready buffers
for (i = 0; i < RBUFCNT; i++){
RD_SM16(rfd + RFD_STAT, temp16);
// check the OK and Complete bits first
if(temp16 & (RFD_STAT_C | RFD_STAT_OK)){
// get the size
RD_SM16(rfd + RFD_CNT, length);
// check the data valid flag
if (length & RFD_CNT_EOF){
length = length & RFD_CNT_MASK;
// copy the data into pktbuf
from_p = (vuchar *)(rfd + RFD_DATA);
to_p = (vuchar *)(pktbuf);
for(x = 0; x < length; x++){
RD_SM8(from_p++, *to_p++);
}
// fixup this rfd for re-use
WR_SM16(rfd + RFD_STAT, 0);
WR_SM16(rfd + RFD_CNT, 0);
break;
}
}
rfd = rfd + RBUFSIZE;
length = 0;
}
// Check the state of the RU before we leave
RD_SM16(i82559_scb + SCB_STAT, temp16);
temp16 = (temp16 & SCB_STAT_RU_MASK) >> SCB_STAT_RU_SHIFT;
// Issue an RU command appropriate to the state.
switch(temp16) {
case RUS_IDLE: rx_cmd = (SCB_RU_START | SCB_IM_M); break;
case RUS_SUSP: rx_cmd = (SCB_RU_RESUME | SCB_IM_M); break;
case RUS_NORES: rx_cmd = (SCB_RU_START | SCB_IM_M); break;
case RUS_SUSP_NO_RBD: rx_cmd = (SCB_RU_RESUME_RBD | SCB_IM_M); break;
case RUS_NO_RES_NO_RBD: rx_cmd = (SCB_RU_RESUME_RBD | SCB_IM_M); break;
case RUS_READY_NO_RBD: rx_cmd = (SCB_RU_START | SCB_IM_M); break;
default: rx_cmd = (SCB_RU_NOP | SCB_IM_M);
}
// make sure the RU is ready to receive a command
i82559_wait_for_ru_cmd();
// issue the command
WR_SM32(i82559_scb + SCB_PTR, (i82559_rfd_base & 0x0fffffff));
WR_SM16(i82559_scb + SCB_CMD, rx_cmd);
return length;
}
//--------------------------------------------------------------------------
// i82559_rx_init()
//
// This function builds/rebuilds the rx buffer list, then enables the i82559
// for receive
//
void i82559_rx_init()
{
vulong i, rfd;
rfd = i82559_rfd_base;
for (i = 0; i < RBUFCNT - 1; i++){
WR_SM16(rfd + RFD_CMD, 0);
WR_SM16(rfd + RFD_STAT, 0);
WR_SM32(rfd + RFD_LINK, ((rfd + RBUFSIZE) & 0x0fffffff));
WR_SM16(rfd + RFD_CNT, 0);
WR_SM16(rfd + RFD_SIZE, RBUFSIZE);
rfd = rfd + RBUFSIZE;
}
// mark the last one as End Of List
WR_SM16(rfd + RFD_CMD, RFD_CMD_EL);
WR_SM16(rfd + RFD_STAT, 0);
WR_SM32(rfd + RFD_LINK, ((rfd + RBUFSIZE) & 0x0fffffff));
WR_SM16(rfd + RFD_CNT, 0);
WR_SM16(rfd + RFD_SIZE, RBUFSIZE);
}
//--------------------------------------------------------------------------
// i82559_wait_for_cu_cmd()
//
// This function polls the SCB Status word waiting for the CU
// command to be accepted, then for the CU status to go idle
//
vulong i82559_wait_for_cu_cmd(void)
{
vulong timeout;
vushort temp16;
timeout = 10000;
while(timeout){
// delay before each check
udelay(10);
RD_SM16(i82559_scb + SCB_CMD, temp16);
temp16 = temp16 & SCB_CMD_CU_MASK;
if(temp16 == 0) break;
timeout--;
}
if(timeout == 0){
// Issue a selective reset to the i82559 and check again
WR_SM32(i82559_scb + SCB_PORT, SCB_PORT_SEL_RST);
udelay(10);
timeout = 10000;
while(timeout){
// delay before each check
udelay(10);
RD_SM16(i82559_scb + SCB_CMD, temp16);
temp16 = temp16 & SCB_CMD_CU_MASK;
if(temp16 == 0) break;
timeout--;
}
if (timeout == 0){
return CU_CMD_TIMEOUT;
}
}
if(timeout == 0){
// Issue a selective reset to the i82559 and check again
WR_SM32(i82559_scb + SCB_PORT, SCB_PORT_SEL_RST);
udelay(10);
timeout = 10000;
while(timeout){
// delay before each check
udelay(10);
RD_SM16(i82559_scb + SCB_CMD, temp16);
temp16 = temp16 & SCB_CMD_CU_MASK;
if(temp16 == 0) break;
timeout--;
}
if (timeout == 0){
return CU_STAT_TIMEOUT;
}
}
return 0;
}
//--------------------------------------------------------------------------
// i82559_wait_for_ru_cmd()
//
// This function polls the SCB Status word waiting for the RU
// command to be accepted
//
vulong i82559_wait_for_ru_cmd(void)
{
vulong timeout;
vushort temp16;
timeout = 100000;
while(timeout){
// delay before each check
udelay(10);
RD_SM16(i82559_scb + SCB_CMD, temp16);
temp16 = temp16 & SCB_CMD_RU_MASK;
if(temp16 == 0) break;
timeout--;
}
if (timeout == 0){
return RU_CMD_TIMEOUT;
}
return 0;
}
//--------------------------------------------------------------------------
// i82559_reset()
//
// This function issues a selective reset, then a full reset to the i82559.
// It then clears the CU and RU base pointers
//
void i82559_reset()
{
// if (i82559_found == 0) return;
// First issue a selective reset to the i82559 to force the i82559
// off the pci bus
WR_SM32(i82559_scb + SCB_PORT, SCB_PORT_SEL_RST);
udelay(10);
// Do hard reset now that the controller is off the PCI bus.
WR_SM32(i82559_scb + SCB_PORT, SCB_PORT_RST);
udelay(10);
// zero the base addresses in the Command Unit and the Receive Unit.
WR_SM32(i82559_scb + SCB_PTR, 0x00000000);
WR_SM16(i82559_scb + SCB_CMD, SCB_CU_BASE_ADD | SCB_IM_M);
udelay(10);
// wait for the RU to be ready
i82559_wait_for_ru_cmd();
WR_SM32(i82559_scb + SCB_PTR, 0x00000000);
WR_SM16(i82559_scb + SCB_CMD, SCB_RU_BASE_ADD | SCB_IM_M);
udelay(10);
}
#endif // INCLUDE_ETHERNET
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -