📄 if_ns.c
字号:
if (interrupts & ENISR_TX) { nsxint(sc); } else if (interrupts & ENISR_COUNTERS) { /* * XXX - We really should be storing statistics * about the interface. For now we just drop them. */ /* reading resets the counters! */ (void) inb_p(port + EN0_COUNTER0); /* frame */ (void) inb_p(port + EN0_COUNTER1); /* crc */ (void) inb_p(port + EN0_COUNTER2); /* miss */ DEBUGF(printf("%s%d: acked counter interrupt.\n", sc->sc_name, sc->sc_unit)); outb_p(port + EN0_ISR, ENISR_COUNTERS); /* ack intr */ } if (interrupts & ENISR_TX_ERR) { DEBUGF(printf("acking transmit error\n")); outb_p(port + EN0_ISR, ENISR_TX_ERR); /* ack intr */ } outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_START); } DEBUGF({ if (interrupts) { printf("%s%d: unknown interrupt 0x%x", sc->sc_name, sc->sc_unit, interrupts); outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_START); outb_p(port + EN0_ISR, 0xff); /* ack all intrs */ } })}/* * Process a transmit interrupt. */voidnsxint(sc) struct nssoftc *sc;{ int port = sc->sc_port, status; struct ifnet *ifp = &sc->sc_if; status = inb(port + EN0_TSR); outb_p(port + EN0_ISR, ENISR_TX); /* ack intr */ sc->sc_txing = 0; sc->sc_timer = 0; sc->sc_oactive = 0; if (sc->sc_pingpong) { if (sc->sc_tx1 < 0) { if (sc->sc_lasttx != 1 && sc->sc_lasttx != -1) printf("%s%d: bogus last_tx_buffer %d," "tx1 = %d\n", sc->sc_name, sc->sc_unit, sc->sc_lasttx, sc->sc_tx1); sc->sc_tx1 = 0; if (sc->sc_tx2 > 0) { nsxmit(sc, sc->sc_tx2, sc->sc_txstrtpg + 6); sc->sc_tx2 = -1; sc->sc_lasttx = 2; } else sc->sc_lasttx = 20; } else if (sc->sc_tx2 < 0) { if (sc->sc_lasttx != 2 && sc->sc_lasttx != -2) printf("%s%d: bogus last_tx_buffer %d," "tx2 = %d\n", sc->sc_name, sc->sc_unit, sc->sc_lasttx, sc->sc_tx2); sc->sc_tx2 = 0; if (sc->sc_tx1 > 0) { nsxmit(sc, sc->sc_tx1, sc->sc_txstrtpg); sc->sc_tx1 = -1; sc->sc_lasttx = 1; } else sc->sc_lasttx = 10; } else printf("%s%d: unexpected TX-done interrupt, " "lasttx = %d\n", sc->sc_name, sc->sc_unit, sc->sc_lasttx); } /* * Update stats. */ if (status & ENTSR_COL) { if (status & ENTSR_ABT) ifp->if_collisions += 16; else ifp->if_collisions += inb(port + EN0_NCR); } if (status & ENTSR_PTX) { DEBUGF(printf("sent: %s%d\n", sc->sc_name, sc->sc_unit)); ifp->if_opackets++; } else ifp->if_oerrors++; /* * Start output on interface. */ nsstart(sc);}/* * Process a receive interrupt. */voidnsrint(sc) struct nssoftc *sc;{ int port = sc->sc_port; int rxing_page, this_frame, next_frame, current_offset; int rx_pkt_count = 0; int num_rx_pages = sc->sc_stoppg - sc->sc_rxstrtpg; struct nspkthdr rx_frame; struct ifnet *ifp = &sc->sc_if; while (++rx_pkt_count < 10) { int pkt_len; /* * Get the rx page (incoming packet pointer). */ outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE1); rxing_page = inb_p(port + EN1_CURPAG); outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0); /* * Remove one frame from the ring. * Boundary is always a page behind. */ this_frame = inb_p(port + EN0_BOUNDARY) + 1; if (this_frame >= sc->sc_stoppg) this_frame = sc->sc_rxstrtpg; DEBUGF({ if (this_frame != sc->sc_curpg) printf("%s%d: mismatched read page pointers " "%x vs %x\n", sc->sc_name, sc->sc_unit, this_frame, sc->sc_curpg); }); if (this_frame == rxing_page) { DEBUGF(printf("this_frame = rxing_page!\n")); break; } current_offset = this_frame << 8; (*sc->sc_input)(sc, sizeof(rx_frame), (char *)&rx_frame, current_offset); pkt_len = rx_frame.count - sizeof(rx_frame); next_frame = this_frame + 1 + ((pkt_len + 4) >> 8); if (rx_frame.next != next_frame && rx_frame.next != next_frame + 1 && rx_frame.next != next_frame - num_rx_pages && rx_frame.next != next_frame + 1 - num_rx_pages) { sc->sc_curpg = rxing_page; outb(port + EN0_BOUNDARY, sc->sc_curpg - 1); ifp->if_ierrors++; DEBUGF(printf("INPUT ERROR?\n")); continue; } if (pkt_len < 60 || pkt_len > 1518) { ifp->if_ierrors++; DEBUGF(printf("%s%d: bad packet length %d\n", sc->sc_name, sc->sc_unit, pkt_len)); } else if ((rx_frame.status & 0x0f) == ENRSR_RXOK) { ipc_kmsg_t kmsg; kmsg = net_kmsg_get(); if (kmsg == 0) { DEBUGF(printf("%s%d: dropped packet\n", sc->sc_name, sc->sc_unit)); ifp->if_rcvdrops++; } else { int len, off; struct ether_header *eh; struct packet_header *pkt; ifp->if_ipackets++; off = current_offset + sizeof(rx_frame); eh = ((struct ether_header *) (&net_kmsg(kmsg)->header[0])); (*sc->sc_input)(sc, sizeof(struct ether_header), (char *)eh, off); off += sizeof(struct ether_header); len = pkt_len - sizeof(struct ether_header); DEBUGF(printf("rcv: %s%d: %x:%x:%x:%x:%x:%x, " "len %d, type 0x%x\n", sc->sc_name, sc->sc_unit, eh->ether_shost[0], eh->ether_shost[1], eh->ether_shost[2], eh->ether_shost[3], eh->ether_shost[4], eh->ether_shost[5], len, eh->ether_type)); pkt = ((struct packet_header *) (&net_kmsg(kmsg)->packet[0])); (*sc->sc_input)(sc, len, (char *)(pkt+1), off); pkt->type = eh->ether_type; pkt->length = len+sizeof(struct packet_header); net_packet(ifp, kmsg, pkt->length, ethernet_priority(kmsg)); } } else { DEBUGF(printf("%s%d: bogus packet: " "status=0x%x nxpg=0x%x size=%d\n", sc->sc_name, sc->sc_unit, rx_frame.status, rx_frame.next, rx_frame.count)); ifp->if_ierrors++; } next_frame = rx_frame.next; if (next_frame >= sc->sc_stoppg) { DEBUGF(printf("%s%d: next frame inconsistency, 0x%x\n", sc->sc_name, sc->sc_unit, next_frame)); next_frame = sc->sc_rxstrtpg; } sc->sc_curpg = next_frame; outb(port + EN0_BOUNDARY, next_frame - 1); } /* * Bug alert! Reset ENISR_OVER to avoid spurious overruns! */ outb_p(port + EN0_ISR, ENISR_RX+ENISR_RX_ERR+ENISR_OVER);}/* * Handle a receive overrun condition. * * XXX - this needs to be gone over in light of the NS documentation. */voidnsrxoverrun(sc) struct nssoftc *sc;{ int port = sc->sc_port, i; extern unsigned delaycount; printf("%s%d: receive overrun\n", sc->sc_name, sc->sc_unit); /* * We should already be stopped and in page0, but just to be sure... */ outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_STOP); /* * Clear remote byte counter registers. */ outb_p(port + EN0_RCNTLO, 0); outb_p(port + EN0_RCNTHI, 0); /* * Wait for reset to complete. */ for (i = delaycount*2; i && !(inb_p(port+EN0_ISR) & ENISR_RESET); i--) ; if (i == 0) { printf("%s%d: reset did not complete at overrun\n", sc->sc_name, sc->sc_unit); nsinit(sc); return; } /* * Disable transmitter. */ outb_p(port + EN0_TXCR, E8390_TXOFF); /* * Remove packets. */ nsrint(sc); outb_p(port + EN0_ISR, 0xff); outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_START); outb_p(port + EN0_TXCR, E8390_TXCONFIG);}/* * Trigger a transmit start. */voidnsxmit(sc, length, start_page) struct nssoftc *sc; unsigned length; int start_page;{ int port = sc->sc_port; sc->sc_txing = 1; outb_p(port, E8390_NODMA+E8390_PAGE0); if (inb_p(port) & E8390_TRANS) { printf("%s%d: nsxmit() called with the transmitter busy\n", sc->sc_name, sc->sc_unit); return; } outb_p(port + EN0_TCNTLO, length & 0xff); outb_p(port + EN0_TCNTHI, (length >> 8) & 0xff); outb_p(port + EN0_TPSR, start_page); outb_p(port, E8390_NODMA+E8390_TRANS+E8390_START); sc->sc_timer = 4;}#endif /* NUL > 0 || NWD > 0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -