📄 if_snnew.c
字号:
* I wonder...
*/
x = splimp();
/* Clear the watchdog.
*/
ifp->if_timer = 0;
SMC_SELECT_BANK(2);
/* Obtain the current interrupt mask and clear the hardware
* mask while servicing interrupts.
*/
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = inw( BASE + INTR_MASK_REG_W );
mask = (u_char)(tmp_reg >> 8);
outw( BASE + INTR_MASK_REG_W, 0x0000 );
#else
mask = inb( BASE + INTR_MASK_REG_B );
outb( BASE + INTR_MASK_REG_B, 0x00 );
#endif
/* Get the set of interrupts which occurred and eliminate any
* which are masked.
*/
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = inw( BASE + INTR_STAT_REG_W );
interrupts = (u_char)(tmp_reg & 0x00FF);
#else
interrupts = inb( BASE + INTR_STAT_REG_B );
#endif
status = interrupts & mask;
/* Now, process each of the interrupt types.
*/
/* Receive Overrun.
*/
if (status & IM_RX_OVRN_INT) {
/* Acknowlege Interrupt
*/
SMC_SELECT_BANK(2);
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = (u_short)IM_RX_OVRN_INT & 0x00FF;
outw( BASE + INTR_ACK_REG_W, tmp_reg );
#else
outb(BASE + INTR_ACK_REG_B, IM_RX_OVRN_INT);
#endif
++sc->arpcom.ac_if.if_ierrors;
}
/* Got a packet.
*/
if (status & IM_RCV_INT) {
snread(sc);
}
/* An on-card memory allocation came through.
*/
if (status & IM_ALLOC_INT) {
/* Disable this interrupt.
*/
mask &= ~IM_ALLOC_INT;
sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
snresume(&sc->arpcom.ac_if);
}
/* TX Completion. Handle a transmit error message.
* This will only be called when there is an error,
* because of the AUTO_RELEASE mode.
*/
if (status & IM_TX_INT) {
/* Acknowlege Interrupt
*/
SMC_SELECT_BANK(2);
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = (u_short)IM_TX_INT & 0x00FF;
outw( BASE + INTR_ACK_REG_W, tmp_reg );
#else
outb(BASE + INTR_ACK_REG_B, IM_TX_INT);
#endif
packet_no = inw( BASE + FIFO_PORTS_REG_W );
packet_no &= FIFO_TX_MASK;
/* select this as the packet to read from
*/
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = (u_short)packet_no & 0x00FF;
outw( BASE + PACKET_NUM_REG_W, tmp_reg );
#else
outb( BASE + PACKET_NUM_REG_B, packet_no );
#endif
/* Position the pointer to the first word from this packet
*/
outw( BASE + POINTER_REG_W, PTR_AUTOINC | PTR_READ | 0x0000 );
/* delay time to read the data reg. after setting the pointer reg. */
inw( BASE + POINTER_REG_W );
inw( BASE + POINTER_REG_W );
/* Fetch the TX status word. The value found here will be
* a copy of the EPH_STATUS_REG_W at the time the transmit
* failed.
*/
tx_status = inw( BASE + DATA_REG_W );
if ( tx_status & EPHSR_TX_SUC ) {
#ifdef PRINTON
printf("sn%d: Successful packet caused interrupt\n", ifp->if_unit);
#endif
} else {
++sc->arpcom.ac_if.if_oerrors;
}
if ( tx_status & EPHSR_LATCOL )
++sc->arpcom.ac_if.if_collisions;
/* Some of these errors will have disabled transmit.
* Re-enable transmit now.
*/
SMC_SELECT_BANK( 0 );
flags = TCR_ENABLE;
#if !defined(SW_PAD)
flags |= TCR_PAD_ENABLE;
#endif
#if !defined(OLD)
/* set Switched Full Duplex mode */
flags |= TCR_SWFDUP;
#endif
outw( BASE + TXMIT_CONTROL_REG_W, flags );
/* kill the failed packet.
* Wait for the MMU to be un-busy.
*/
SMC_SELECT_BANK( 2 );
outw( BASE + MMU_CMD_REG_W, MMUCR_FREEPKT );
while ( inw( BASE + MMU_CMD_REG_W ) & MMUCR_BUSY ) /*NOTHING*/ ;
/*
* If there is no memory allocation oustanding, then
* attempt to queue more transmits.
*/
if (sc->pages_wanted == -1) {
sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
snstart(&sc->arpcom.ac_if);
}
}
/* Transmit underrun. We use this opportunity to
* update transmit statistics from the card.
*/
if (status & IM_TX_EMPTY_INT) {
/* Acknowlege Interrupt
*/
SMC_SELECT_BANK( 2 );
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = (u_short)IM_TX_EMPTY_INT & 0x00FF;
outw( BASE + INTR_ACK_REG_W, tmp_reg );
#else
outb(BASE + INTR_ACK_REG_B, IM_TX_EMPTY_INT);
#endif
/* Disable this interrupt.
*/
mask &= ~IM_TX_EMPTY_INT;
SMC_SELECT_BANK( 0 );
card_stats = inw( BASE + COUNTER_REG_W );
/* Single collisions
*/
sc->arpcom.ac_if.if_collisions += card_stats & ECR_COLN_MASK;
/* Multiple collisions
*/
sc->arpcom.ac_if.if_collisions += (card_stats & ECR_MCOLN_MASK) >> 4;
SMC_SELECT_BANK( 2 );
/*
* If there is no memory allocation oustanding, then
* attempt to enqueue some more stuff.
*/
if (sc->pages_wanted == -1) {
sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
snstart(&sc->arpcom.ac_if);
}
}
/* Some other error. Try to fix it by resetting the adapter.
*/
if (status & IM_EPH_INT) {
snstop();
sninit(0);
}
#if defined(LAN91C111)
/* PHY MI state has changed */
if (status & IM_MDINT) {
/* Acknowlege Interrupt */
SMC_SELECT_BANK( 2 );
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = (u_short)IM_MDINT & 0x00FF;
outw( BASE + INTR_ACK_REG_W, tmp_reg );
#else
outb(BASE + INTR_ACK_REG_B, IM_MDINT);
#endif
phy_ints();
}
#endif
/* Handled all interrupt sources.
*/
SMC_SELECT_BANK( 2 );
/* Reestablish interrupts from mask which have not been deselected
* during this interrupt. Note that the hardware mask, which was set
* to 0x00 at the start of this service routine, may have been updated
* by one or more of the interrupt handers and we must let those
* new interrupts stay enabled here.
*/
#if defined(_STD_SH727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = inw( BASE + INTR_MASK_REG_W );
mask |= (u_char)(tmp_reg >> 8);
tmp_reg = (u_short)(mask << 8);
outw( BASE + INTR_MASK_REG_W, tmp_reg );
#else
mask |= inb( BASE + INTR_MASK_REG_B );
outb( BASE + INTR_MASK_REG_B, mask );
#endif
sc->intr_mask = mask;
splx(x);
}
void
snread(struct sn_softc *sc)
{
struct ether_header *eh;
struct mbuf *top, *mcur, *m;
int lenthisone;
short rx_fifo2, status;
register short delta;
register short rx_fifo;
int packet_number;
u_short packet_length;
u_char *data;
int i;
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
volatile unsigned short tmp_reg;
#endif
#if !defined(ORIGINAL)
for (i=0; i < SN_MAX_RECV_COUNT; i++) {
#endif
SMC_SELECT_BANK( 2 );
packet_number = inw( BASE + FIFO_PORTS_REG_W );
if ( packet_number & FIFO_REMPTY ) {
/* we got called , but nothing was on the FIFO
*/
#ifdef PRINTON
printf("sn: Receive interrupt with nothing on FIFO\n");
#endif
return;
}
read_another:
/* Start reading from the start of the packet.
* Since PTR_RCV is set, packet number is found
* in FIFO_PORTS_REG_W, FIFO_RX_MASK.
*/
outw( BASE + POINTER_REG_W, PTR_READ | PTR_RCV | PTR_AUTOINC | 0x0000 );
#if !defined(OLD)
/* delay time to read the data reg. after setting the pointer reg. */
inw( BASE + POINTER_REG_W );
inw( BASE + POINTER_REG_W );
#endif
/* First two words are status and packet_length
*/
status = inw( BASE + DATA_REG_W );
packet_length = inw( BASE + DATA_REG_W ) & RLEN_MASK;
/***********************************
Get Data:
b15 b0
+------------------------------+
0 |Status Word |
+------------------------------+
2 |(length+6)/256 |(length+6)%256|
+------------------------------+
4 |Data Area |
+------------------------------+
| |
+------------------------------+
2046 |Control Byte | Last Data Byte if odd.
max +------------------------------+
**********************************/
/*
* The packet length contains 3 extra words:
* status, length, and a extra word with the control byte.
*/
packet_length -= 6;
/* Account for receive errors and discard.
*/
if (status & RS_ERRORS) {
++sc->arpcom.ac_if.if_ierrors;
goto out;
}
/* A packet is received.
*/
/* Adjust for odd-length packet.
*/
if ( status & RS_ODDFRAME ) {
packet_length++;
}
/* Allocate a header mbuf from the kernel.
*/
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
goto out;
}
m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
m->m_pkthdr.len = m->m_len = packet_length;
/* Attach an mbuf cluster
*/
MCLGET(m, M_DONTWAIT);
/* Insist on getting a cluster
*/
if ((m->m_flags & M_EXT) == 0) {
m_freem(m);
++sc->arpcom.ac_if.if_ierrors;
#ifdef PRINTON
printf("sn: snread() kernel memory allocation problem\n");
#endif
goto out;
}
#if defined(_MIC_M32192_)||defined(_STD_SH7727_)||defined(_MIC_SH7145_)||(_MIC_M32104_)
/* We change offset to set IP header's alignment to 4byte */
m->m_data += 2;
#endif
eh = mtod(m, struct ether_header *);
/*
* Get packet, including link layer address, from interface.
*/
data = (u_char *) eh;
insw(BASE + DATA_REG_W, (unsigned short *)data, packet_length >> 1);
if ( packet_length & 1 ) {
data += packet_length & ~1;
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = inw(BASE + DATA_REG_W);
*data = (unsigned char)(tmp_reg & 0x00FF);
#else
*data = inb( BASE + DATA_REG_B );
#endif
#ifdef DEBUG
tm_putstring("snread.\n");
#endif
}
++sc->arpcom.ac_if.if_ipackets;
/*
* Remove link layer addresses and whatnot.
*/
m->m_pkthdr.len = m->m_len = packet_length - sizeof(struct ether_header);
m->m_data += sizeof(struct ether_header);
(void)ether_input(&sc->arpcom.ac_if, eh, m);
out:
/* Error or good, tell the card to get rid of this packet
* Wait for the MMU to be un-busy.
*/
SMC_SELECT_BANK( 2 );
outw( BASE + MMU_CMD_REG_W, MMUCR_RELEASE );
while ( inw( BASE + MMU_CMD_REG_W ) & MMUCR_BUSY ) /*NOTHING*/ ;
#if defined(ORIGINAL)
/* Check whether another packet is ready
*/
packet_number = inw( BASE + FIFO_PORTS_REG_W );
if ( packet_number & FIFO_REMPTY ) {
return;
}
goto read_another;
#else
} /* for */
#endif
}
/*
* Handle IOCTLS. This function is completely stolen from if_ep.c
* As with its progenitor, it does not handle hardware address
* changes.
*/
static int
snioctl(struct ifnet *ifp, unsigned int cmd, caddr_t data)
{
register struct ifaddr *ifa = (struct ifaddr *) data;
struct sn_softc *sc = &sn_softc0;
struct ifreq *ifr = (struct ifreq *) data;
int s, error = 0;
s = splimp();
switch (cmd) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
sninit(0); /* before arpwhohas */
arp_ifinit((struct arpcom *)ifp, ifa);
break;
#endif
default:
sninit(0);
break;
}
break;
case SIOCGIFADDR:
{
struct sockaddr *sa;
sa = (struct sockaddr *) & ifr->ifr_data;
bcopy((caddr_t) sc->arpcom.ac_enaddr,
(caddr_t) sa->sa_data, ETHER_ADDR_LEN);
}
break;
case SIOCSIFFLAGS:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -