📄 lnc.c
字号:
}static buf_tlnc_get_packet(int start_of_packet, int pkt_len){ struct host_ring_entry *start; buf_t b; char *data, *buf_data; int blen; disable; b = _bget(ETHER_PKT_LEN); enable; if (b == NULL) {#if _DEBUG kprintf("lnc_get_packet: no buffers\n");#endif return NULL; } blen(b) = 0; start = sc.recv_ring + start_of_packet; blen = RECVBUFSIZE; data = start->buff.data; buf_data = bstart(b); while (start_of_packet != sc.recv_next) { if (pkt_len < blen) blen = pkt_len; bcopy(data, buf_data, blen); pkt_len -= blen; blen(b) += blen; data += blen; buf_data += blen; start->md->md1 &= HADR; start->md->md1 |= OWN; start->md->md2 = -RECVBUFSIZE; INC_MD_PTR(start_of_packet, sc.nrdre); start = sc.recv_ring + start_of_packet; data = start->buff.data; blen = RECVBUFSIZE; } return b;}static voidlnc_rint(){ struct host_ring_entry *start, *next; int flags, lookahead, pkt_len, start_of_packet; /* * The LANCE will issue a RINT interrupt when the ownership of the * last buffer of a receive packet has been relinquished by the LANCE. * Therefore, it can be assumed that a complete packet can be found * before hitting buffers that are still owned by the LANCE, if not * then there is a bug in the driver that is causing the descriptors * to get out of sync. */ lookahead = 0; next = sc.recv_ring + sc.recv_next; for (;;) { flags = next->md->md1; if (!(flags & STP)) break; /* Note start of packet */ start_of_packet = sc.recv_next; /* * Find the end of the packet. Even if not data chaining, jabber * packets can overrun into a second descriptor. If there is no * error, then the ENP flag is set in the last descriptor of the * packet. If there is an error then the ERR flag will be set in * the descriptor where the error occured. Therefore, to find * the last buffer of a packet we search for either ERR or ENP. */ if (!(flags & (ENP | MDERR))) { do { INC_MD_PTR(sc.recv_next, sc.nrdre); next = sc.recv_ring + sc.recv_next; flags = next->md->md1; } while (!(flags & (STP | OWN | ENP | MDERR))); if (flags & STP) {#if _DEBUG kprintf("lnc_rint: start of packet before end of prev\n");#endif lnc_reset(sc); return; } if (flags & OWN) { if (lookahead) { /* Looked ahead into a packet still being received */ sc.recv_next = start_of_packet; break; } else {#if _DEBUG kprintf("lnc_rint: end of packet not found\n");#endif lnc_reset(sc); return; } } } pkt_len = (next->md->md3 & MCNT) - FCS_LEN; /* Move pointer onto start of next packet */ INC_MD_PTR(sc.recv_next, sc.nrdre); next = sc.recv_ring + sc.recv_next; if (flags & MDERR) { /* Drop packet */ while (start_of_packet != sc.recv_next) { start = sc.recv_ring + start_of_packet; start->md->md2 = -RECVBUFSIZE; start->md->md1 &= HADR; start->md->md1 |= OWN; INC_MD_PTR(start_of_packet, sc.nrdre); } } else { buf_t b = lnc_get_packet(start_of_packet, pkt_len); if (b != NULL) netif_input(b); } lookahead++; } write_csr(CSR0, RINT | INEA);}static voidlnc_tint(){ struct host_ring_entry *next, *start; int start_of_packet; int lookahead; /* * The LANCE will write the status information for the packet it just * tried to transmit in one of two places. If the packet was * transmitted successfully then the status will be written into the * last descriptor of the packet. If the transmit failed then the * status will be written into the descriptor that was being accessed * when the error occured and all subsequent descriptors in that * packet will have been relinquished by the LANCE. * * At this point we know that sc.trans_next points to the start * of a packet that the LANCE has just finished trying to transmit. * We now search for a buffer with either ENP or ERR set. */ lookahead = 0; do { start_of_packet = sc.trans_next; next = sc.trans_ring + sc.trans_next; /* Find end of packet */ if (!(next->md->md1 & (ENP | MDERR))) { do { INC_MD_PTR(sc.trans_next, sc.ntdre); next = sc.trans_ring + sc.trans_next; } while (!(next->md->md1 & (STP | OWN | ENP | MDERR))); if (next->md->md1 & STP) {#if _DEBUG kprintf("lnc_tint: start of packet found before end "); kprintf("of prevous in transmit ring\n");#endif lnc_reset(); return; } if (next->md->md1 & OWN) { if (lookahead) { /* Looked ahead into a packet still being transmitted */ sc.trans_next = start_of_packet; break; } else {#if _DEBUG kprintf("lnc_tint: end of packet not found\n");#endif lnc_reset(); return; } } } /* * Check for ERR first since other flags are irrelevant if an * error occurred. */ if (next->md->md1 & MDERR) { if (next->md->md3 & LCOL) {#if _DEBUG kprintf("lnc_tint: transmit late collision\n");#endif /* Clear TBUFF since it's not valid when LCOL set */ next->md->md3 &= ~TBUFF; } if (next->md->md3 & LCAR) {#if _DEBUG kprintf("lnc_tint: loss of carrier during transmit\n");#endif } if (next->md->md3 & RTRY) {#if _DEBUG kprintf("lnc_tint: retransmits failed\n");#endif /* Clear TBUFF since it's not valid when RTRY set */ next->md->md3 &= ~TBUFF; } /* * TBUFF is only valid if neither LCOL nor RTRY are set. * We need to check UFLO after LCOL and RTRY so that we * know whether or not TBUFF is valid. If either are * set then TBUFF will have been cleared above. A * UFLO error will turn off the transmitter so we * have to reset. * */ if (next->md->md3 & UFLO) { /* If UFLO occured it's possibly due to TBUFF error */#if _DEBUG if (next->md->md3 & TBUFF) kprintf("lnc_tint: transmit buffer error\n"); else kprintf("lnc_tint: transmit underflow error\n");#endif lnc_reset(); return; } do { INC_MD_PTR(sc.trans_next, sc.ntdre); next = sc.trans_ring + sc.trans_next; } while (!(next->md->md1 & STP) && (sc.trans_next != sc.next_to_send)); } else { INC_MD_PTR(sc.trans_next, sc.ntdre); next = sc.trans_ring + sc.trans_next; } /* Clear descriptors */ do { start = sc.trans_ring + start_of_packet; start->md->md1 &= HADR; sc.pending_transmits--; INC_MD_PTR(start_of_packet, sc.ntdre); } while (start_of_packet != sc.trans_next); lookahead++; } while (sc.pending_transmits && !(next->md->md1 & OWN)); /* Clear TINT since we've dealt with all the completed transmissions */ write_csr(CSR0, TINT | INEA); lnc_start();}static voidlnc_isr(void *params){ u_short csr0; for (;;) { csr0 = read_csr(CSR0); if (!(csr0 & INTR)) break; /* * Clear interrupt flags early to avoid race conditions. The * controller can still set these flags even while we're in this * interrupt routine. If the flag is still set from the event * that caused this interrupt any new events will be missed. */ write_csr(CSR0, csr0); if (csr0 & ERR) { if (csr0 & CERR) {#if _DEBUG kprintf("lnc_isr: heartbeat error\n");#endif } if (csr0 & BABL) {#if _DEBUG kprintf("lnc_isr: babbling\n");#endif } if (csr0 & MISS) {#if _DEBUG kprintf("lnc_isr: missed packet\n");#endif } if (csr0 & MERR) {#if _DEBUG kprintf("lnc_isr: memory error\n");#endif } } if (csr0 & RINT) lnc_rint(); if (csr0 & TINT) { lnc_tint(); } } /* XXX Hard coded for the moment */ outb(I8259_SLV_CTRL, 0x61); outb(I8259_MSTR_CTRL, I8259_EOI_CAS);}intlnc_init(){ pci_func_t func; ipaddr ip; char s[20]; int ndesc; bzero(&sc, sizeof(struct lnc_softc)); /* XXX Looking for PCI NICs only for the moment */ func = pci_lookup(PCI_VENDOR_AMD, PCI_DEVICE); if (func == NULL) {#if _DEBUG kprintf("lnc_init: no pci adapter found\n");#endif return EFAIL; } sc.isa_dev.id_iobase = func->iobase; sc.isa_dev.id_irq = func->irq; if (ne2100_probe() == 0) {#if _DEBUG kprintf("lnc_init: no NE2100 adapter found\n");#endif return EFAIL; } ether2str(sc.hwaddr, s); kprintf("lnc_init: %s iobase 0x%x irq %d hwaddr %s\n", ic_ident[sc.nic.ic], sc.isa_dev.id_iobase, sc.isa_dev.id_irq, s); bcopy(sc.hwaddr, netif_primary.hwaddr, ETHER_ADDR_LEN); netif_primary.state = NETIF_STATE_UP; str2ip(IPADDR, &ip); arp_insert(ARP_ENTRY_RESOLVED, ARP_TTL_INFINITE, ip, sc.hwaddr); binitq(&(sc.sndq)); /* Stop the LANCE for initialization */ lnc_stop(); /* Enable bus mastering */ if (sc.nic.ic > PCnet_32) pci_busmaster_enable(func->bus, func->dev, 0); ndesc = NDESC(sc.nrdre) + NDESC(sc.ntdre); sc.lnc_mem_size = ndesc * sizeof(struct host_ring_entry); sc.lnc_mem_size += sizeof(struct init_block); sc.lnc_mem_size += ndesc * sizeof(struct mds); sc.lnc_mem_size += 8; sc.lnc_mem_size += NDESC(sc.nrdre) * RECVBUFSIZE; sc.lnc_mem_size += NDESC(sc.ntdre) * TRANSBUFSIZE; sc.recv_ring = (struct host_ring_entry *) kmalloc(sc.lnc_mem_size); if (sc.recv_ring == NULL) {#if _DEBUG kprintf("lnc_init: could not allocate memory\n");#endif return ENOMEM; } if ((u_long) sc.recv_ring + sc.lnc_mem_size >= 0x1000000) {#if _DEBUG kprintf("lnc_init: memory allocated above 16 Mbyte limit\n");#endif return ENOMEM; } bzero(sc.recv_ring, sc.lnc_mem_size); isr_inst(IRQ2INTR(sc.isa_dev.id_irq), lnc_isr, NULL); intr_unmask(IRQ2INTR(sc.isa_dev.id_irq)); /* Initialize LANCE controller */ lnc_reset(); return 0;}intlnc_shut(){ return ENOSYS;}intlnc_ioctl(int cmd, void *args){ return ENOSYS;}intlnc_read(buf_t * b){ return ENOSYS;}intlnc_write(buf_t * b){ disable; benq(*b, &(sc.sndq)); enable; lnc_start(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -