📄 ne2000.c
字号:
* Counter overflow and Remote DMA complete are *not* enabled.
*/
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_IMR), NORMAL_NE2000_INTS);
/* Program command register for page 1. */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_1 | NE2000_CR_STP);
/* Copy out our station (ethernet) address. */
for (i = 0; i < ETH_ALEN; ++i)
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_PAR0) + i, my_hw_addr[i]);
/* Set current page pointer to next_packet (initialized above). */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_CURR), sc->next_packet);
/* Set multicast filter on chip. */
/* If none needed lenmclist will be zero */
//ne2000_getmcaf((PFBYTE) pi->mcast.mclist, pi->mcast.lenmclist,
// mcaf);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR0), mcaf[0]);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR1), mcaf[1]);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR2), mcaf[2]);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR3), mcaf[3]);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR4), mcaf[4]);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR5), mcaf[5]);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR6), mcaf[6]);
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR7), mcaf[7]);
/* ==================== */
/* Program command register for page 0. */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STP);
/* set broadcast mode */
/* NOTE: promiscous mode is not supported */
/* i = NE2000_RCR_AB; */
/* Accept multicasts and broadcasts */
// i = NE2000_RCR_AB | NE2000_RCR_AM;
i = NE2000_RCR_AB | NE2000_RCR_AM | NE2000_RCR_PRO;
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_RCR), i);
/* Take interface out of loopback. */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TCR), 0);
/* Fire up the interface. */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STA);
NU_Control_Interrupts(previous_int_value);
}
/* ******************************************************************** */
/* INTERRUPT routines. */
/* ******************************************************************** */
/* handle interrupts - this is the interrupt routine */
void ne2000_interrupt(int minor_no) /*__fn__*/
{
PNE2000_SOFTC sc;
UINT8 isr;
int error;
sc = off_to_softc();
if (!sc)
return;
//ks_enable();
/* Set NIC to page 0 registers. */
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STA);
/* get interrupt status register */
isr = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_ISR));
/* Loop until there are no more new interrupts. */
while (isr)
{
/*
* Reset all the bits in the interrupt status register that we
* are 'acknowledging' by writing a '1' to each bit position
* that was set. (Writing a '1' *clears* the bit.)
*/
OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_ISR), isr);
/* ****** */
/*
* Handle transmitter interrupts. Handle these first because
* the receiver will reset the board under some conditions.
*/
if (isr & (NE2000_ISR_PTX | NE2000_ISR_TXE)) /* pkt xmit or xmit error */
{
int collisions = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_NCR)) & 0x0f;
/*
* Check for transmit error. If a TX completed with an
* error, we end up throwing the packet away. Really
* the only error that is possible is excessive
* collisions, and in this case it is best to allow the
* automatic mechanisms of TCP to backoff the flow. Of
* course, with UDP we're screwed, but this is expected
* when a network is heavily loaded.
*/
error = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TSR));
if ( (isr & NE2000_ISR_TXE) ||
(error & (NE2000_TSR_CDH | NE2000_TSR_CRS)) )
{
/* if transmit aborted (NE2000_TSR_ABT) due to excessive collisions, */
/* if collisions is 0 it really is 16 (excessive collisions) */
if (error & NE2000_TSR_ABT)
{
sc->stats.collision_errors++;
}
/* Update output errors counter. */
sc->stats.errors_out++;
//pi->xmit_status = ENETDOWN;
}
else /* no transmit error */
{
/* check for out of window collsions */
if (INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TSR)) & NE2000_TSR_OWC)
sc->stats.owc_collision++;
if (collisions == 1)
sc->stats.one_collision++;
else if (collisions >= 1)
sc->stats.multiple_collisions++;
if (INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TSR)) & NE2000_TSR_CRS)
sc->stats.tx_carrier_errors++;
}
/* 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;
device = DEV_Get_Dev_By_Name("RTL8019");
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -