📄 ne2000.c
字号:
}
/* signal IP layer or driver that send is done */
//ks_invoke_output(/*pi*/);
NU_Activate_HISR(&Ether_Xmit);
} /* pkt xmit or xmit error */
/* ****** */
/* Handle receiver interrupts. */
if (isr & (NE2000_ISR_PRX | NE2000_ISR_RXE | NE2000_ISR_OVW))
{
/*
* Overwrite warning. In order to make sure that a
* lockup of the local DMA hasn't occurred, we reset
* and re-init the NIC. The NSC manual suggests only a
* partial reset/re-init is necessary - but some chips
* seem to want more. The DMA lockup has been seen
* only with early rev chips - Methinks this bug was
* fixed in later revs. -DG
*/
if (isr & NE2000_ISR_OVW)
{
sc->stats.rx_overwrite_errors++;
sc->stats.rx_other_errors++;
sc->stats.errors_in++;
/* Recover from ring buffer overflow. */
/* disable sends and receives while recovery in progress */
sc->do_recovery = NU_Retrieve_Clock();//ks_get_ticks();
/* disable all interrupts */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_IMR), 0);
/* save whether xmit is in progress */
sc->tpx = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR)) & NE2000_CR_TXP;
/* STOP command to NIC; also set to page 0 */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_STP | NE2000_CR_PAGE_0);
/* Timer task will do the rest */
}
else
{
/* Process Receiver Error. One or more of: */
/* CRC error, */
/* frame alignment error */
/* FIFO overrun, or */
/* missed packet. */
/* */
if (isr & NE2000_ISR_RXE)
{
sc->stats.errors_in++;
sc->stats.rx_other_errors++;
}
/* Go get the packet(s). */
/* - Doing this on an error is dubious */
/* because there shouldn't be any data to get */
/* (we've configured the interface to not */
/* accept packets with errors). */
/* */
/* process the receiver interrupt */
if (!sc->do_recovery)
{
ne2000_read_ring_pkt(sc, TRUE);
}
}
} /* end receive interrupts */
/*
* Return NIC CR to standard state: page 0, remote DMA
* complete, start (toggling the TXP bit off, even if was just
* set in the transmit routine, is *okay* - it is 'edge'
* triggered from low to high).
*/
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STA);
/*
* If the Network Talley Counters overflow, read them to reset
* them. It appears that old 8390's won't clear the ISR flag
* otherwise - resulting in an infinite loop.
*/
if (isr & NE2000_ISR_CNT)
{
(void) INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CNTR0));
(void) INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CNTR1));
(void) INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CNTR2));
}
/* get isr for next loop */
isr = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_ISR));
} /* end of while(isr) */
}
/* ******************************************************************** */
/*
* Retreive packet from shared memory and send to the next level up via
* the input list.
*/
UINT8 TEMP_BUF_R[2000];
void ne2000_get_packet(PNE2000_SOFTC sc, UINT16 nic_buf, int len, BOOLEAN rint)
{
PFBYTE msgdata;
int tmp_amount;
DV_DEVICE_ENTRY *device;
int blen = len;
msgdata = TEMP_BUF_R;
/* Allocate a packet to write the ethernet packet in. */
//msg = os_alloc_packet_input(len, DRIVER_ALLOC);
//if (!msg)
//{
//DEBUG_ERROR("ne2000_get_packet() - out of DCUs", NOVAR, 0, 0);
//if (rint)
// sc->stats.packets_lost++;
//return;
//}
/* write ethernet header to packet */
//msgdata = DCUTODATA(msg);
ne2000_pio_readmem(sc, nic_buf, msgdata, sizeof(struct _ether));
nic_buf = (UINT16)(nic_buf + sizeof(struct _ether));
msgdata += sizeof(struct _ether);
//DCUTOPACKET(msg)->length = len;
/* Pull packet off interface and put into packet. */
len -= sizeof(struct _ether);
/* Handle wrap here */
if (nic_buf + len > sc->mem_end)
{
tmp_amount = sc->mem_end - nic_buf;
/* Copy amount up to end of NIC memory. */
ne2000_pio_readmem(sc, nic_buf, msgdata, tmp_amount);
len -= tmp_amount;
nic_buf = sc->mem_ring;
msgdata += tmp_amount;
}
ne2000_pio_readmem(sc, nic_buf, msgdata, len);
if (rint)
{
/* Pull packet off interface and put into packet. */
sc->stats.packets_in++;
sc->stats.bytes_in += len;
et_data_ptr = (UINT32)TEMP_BUF_R;
et_data_len = blen;
#if RTL8019_LOOPBACK_TEST
device = DEV_Get_Dev_By_Name("loopback");
#else
device = DEV_Get_Dev_By_Name("RTL8019");
#endif
device->dev_receive(device);
}
//else
// os_free_packet(msg);
}
/* ******************************************************************** */
/* Ethernet interface receiver interrupt. */
/* ******************************************************************** */
void ne2000_read_ring_pkt(PNE2000_SOFTC sc, BOOLEAN rint)
{
UINT16 boundary;
int len;
struct ne2000_ring packet_hdr;
UINT16 nic_packet_ptr;
/* Set NIC to page 1 registers to get 'current' pointer. */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_1 | NE2000_CR_STA);
/*
* 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
* it points to where new data has been buffered. The 'CURR' (current)
* register points to the logical end of the ring-buffer - i.e. it
* points to where additional new data will be added. We loop here
* until the logical beginning equals the logical end (or in other
* words, until the ring-buffer is empty).
*/
while (sc->next_packet != INBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_CURR)))
{
/* Get pointer to this buffer's header structure. */
nic_packet_ptr = (UINT16)(sc->mem_ring +
(sc->next_packet - sc->rec_page_start) *
NE2000_PAGE_SIZE);
/*
* The UINT8 count includes a 4 UINT8 header that was added by
* the NIC.
*/
ne2000_pio_readmem(sc, nic_packet_ptr, (PFBYTE) &packet_hdr,
sizeof(packet_hdr));
len = (int)packet_hdr.count;
/* Go get packet from shared memory, put it in a DCU and send it to
input exchange. */
/* Adjust the pointer to the data to point past the header and
Subtract the size of the CRC from the length */
if (len <= ETHER_MAX_LEN)
{
ne2000_get_packet(sc,
(UINT16)(nic_packet_ptr + sizeof(struct ne2000_ring)),
len - CRC_LEN, rint);
}
/* Update next packet pointer. */
sc->next_packet = packet_hdr.next_packet;
/*
* Update NIC boundary pointer - being careful to keep it one
* buffer behind (as recommended by NS databook).
*/
boundary = (UINT16) (sc->next_packet - 1);
if (boundary < sc->rec_page_start)
boundary = (UINT16) (sc->rec_page_stop - 1);
/* Set NIC to page 0 registers to update boundary register. */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STA);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_BNRY), boundary);
/*
* Set NIC to page 1 registers before looping to top (prepare
* to get 'CURR' current pointer).
*/
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_1 | NE2000_CR_STA);
}
}
/* ******************************************************************** */
/* RING BUFFER OVERFLOW RECOVERY */
/* ******************************************************************** */
/* perform recovery for ring buffer overflow as suggested by */
/* National Semiconductor DP8390D/NS32490D NIC Network Interface */
/* Controller (September 1992) Document */
/* NOTE: the rest of the recovery definatly cannot be done during */
/* the interrupt due to the delay within the recovery code, therefore, */
/* it is broken off in this routine just in case recovery ever attempted */
/* at the interrupt level */
void ne2000_ring_overflow_recovery2(void) /*__fn__*/
{
int resend;
PNE2000_SOFTC sc;
int softc_off;
//for (softc_off=0; softc_off<CFG_NUM_NE2000; softc_off++)
{
sc = (PNE2000_SOFTC) &ne2000softc[softc_off];
//if (sc->do_recovery)
// break;
}
/* we have to wait at least 1.6 miliseconds to do ring overflow
here we assume that 2 ticks is at least 1.6 milliseconds to
save space on calculating time elapsed
*/
//if (!sc->do_recovery || ( (ks_get_ticks() - sc->do_recovery) < 2))
// return;
#if (DEBUG_RING)
DEBUG_ERROR("ring buffer recovery 2 start", NOVAR, 0, 0);
#endif
#if (DEBUG_RING)
DEBUG_ERROR("ring buffer recovery 2 start", NOVAR, 0, 0);
#endif
/* clear the remote UINT8 count registers */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_RBCR0), 0);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_RBCR1), 0);
/* set resend variable */
if (!sc->tpx)
resend = 0;
else
{
if ( INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_ISR)) & (NE2000_ISR_PTX | NE2000_ISR_TXE) )
resend = 0;
else
resend = 1;
}
/* set to mode 1 loopback */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TCR), NE2000_TCR_LB0);
/* issue start command */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_STA);
/* remove one or more packets from the receive buffer */
//ne2000_read_ring_pkt(sc->iface, sc, FALSE);
/* set to page 0 in case ne2000_read_ring_pkt changed page */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_PAGE_0);
/* reset the overwrite warning */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_ISR), NE2000_ISR_OVW);
#if RTL8019_LOOPBACK_TEST
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TCR), LOOPBACK_TEST_MODE);
#else
/* Take interface out of loopback. */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TCR), 0);
#endif
/* if resend is 1, reissue xmit command */
if (resend)
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_TXP | NE2000_CR_STA);
/* enable interrupts again */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_IMR), NORMAL_NE2000_INTS);
#if (DEBUG_RING)
recovery_count++;
DEBUG_ERROR("ring buffer recovery done", EBS_INT1, recovery_count, 0);
#endif
/* do not clear flag until recovery done; xmit and receive are disable */
/* via this flag until the recovery is done */
sc->do_recovery = 0;
}
/* ******************************************************************** */
/* Supporting routines. */
/* ******************************************************************** */
/*
* Given a NIC memory source address and a host memory destination address,
* copy 'amount' from NIC to host using Programmed I/O. The 'amount' is
* rounded up to a UINT16 - okay as long as mbufs are UINT16 sized.
* This routine is currently Novell-specific.
*/
void ne2000_pio_readmem(PNE2000_SOFTC sc, UINT16 src, PFBYTE dst, int amount)
{
/* Select page 0 registers. */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STA);
/* Round up to a word. */
if (amount & 1)
++amount;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -