/* ** Name: void ns_reset(dpeth_t *dep) ** Function: Resets device. */ static void ns_reset(dpeth_t * dep) { int ix; /* Stop chip */ outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA); outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR1, 0); for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1) /* Do nothing */ ; outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST); outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST); /* Acknowledge the ISR_RDC (remote dma) interrupt. */ for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1) /* Do nothing */ ; outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC)); /* Reset the transmit ring. If we were transmitting a packet, we * pretend that the packet is processed. Higher layers will * retransmit if the packet wasn't actually sent. */ dep->de_sendq_head = dep->de_sendq_tail = 0; for (ix = 0; ix < dep->de_sendq_nr; ix++) dep->de_sendq[ix].sq_filled = FALSE; ns_send(dep, TRUE, dep->de_send_s); return; }
/* ** Name: void ns_stats(dpeth_t * dep) ** Function: Updates counters reading from device */ static void ns_stats(dpeth_t * dep) { dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1); dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2); return; }
/*===========================================================================* * dp8390_dump * *===========================================================================*/ void dp8390_dump() { dpeth_t *dep; int i, isr; printf("\n"); for (i= 0, dep = &de_table[0]; i<DE_PORT_NR; i++, dep++) { #if XXX if (dep->de_mode == DEM_DISABLED) printf("dp8390 port %d is disabled\n", i); else if (dep->de_mode == DEM_SINK) printf("dp8390 port %d is in sink mode\n", i); #endif if (dep->de_mode != DEM_ENABLED) continue; printf("dp8390 statistics of port %d:\n", i); printf("recvErr :%8ld\t", dep->de_stat.ets_recvErr); printf("sendErr :%8ld\t", dep->de_stat.ets_sendErr); printf("OVW :%8ld\n", dep->de_stat.ets_OVW); printf("CRCerr :%8ld\t", dep->de_stat.ets_CRCerr); printf("frameAll :%8ld\t", dep->de_stat.ets_frameAll); printf("missedP :%8ld\n", dep->de_stat.ets_missedP); printf("packetR :%8ld\t", dep->de_stat.ets_packetR); printf("packetT :%8ld\t", dep->de_stat.ets_packetT); printf("transDef :%8ld\n", dep->de_stat.ets_transDef); printf("collision :%8ld\t", dep->de_stat.ets_collision); printf("transAb :%8ld\t", dep->de_stat.ets_transAb); printf("carrSense :%8ld\n", dep->de_stat.ets_carrSense); printf("fifoUnder :%8ld\t", dep->de_stat.ets_fifoUnder); printf("fifoOver :%8ld\t", dep->de_stat.ets_fifoOver); printf("CDheartbeat:%8ld\n", dep->de_stat.ets_CDheartbeat); printf("OWC :%8ld\t", dep->de_stat.ets_OWC); isr= inb_reg0(dep, DP_ISR); printf("dp_isr = 0x%x + 0x%x, de_flags = 0x%x\n", isr, inb_reg0(dep, DP_ISR), dep->de_flags); if (debug) { dep->de_int_pending= 1; interrupt(dpeth_tasknr); } } }
/* ** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize) ** Function: Copies a packet from user area to board (Prog. I/O). */ static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize) { iovec_dat_s_t *iovp = &dep->de_write_iovec; int r, bytes, ix = 0; /* Sets up board for writing */ ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE); do { /* Reads chuncks of packet from user area */ bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */ if (bytes > pktsize) bytes = pktsize; r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant, 0, bytes); if (r != OK) panic("pio_user2nic: sys_safe_outsb failed: %d", r); if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */ dp_next_iovec(iovp); ix = 0; } /* Till packet done */ } while ((pktsize -= bytes) > 0); for (ix = 0; ix < 100; ix += 1) { if (inb_reg0(dep, DP_ISR) & ISR_RDC) break; } if (ix == 100) { panic(RdmaErrMsg); } return; }
/*===========================================================================* * dp8390_dump * *===========================================================================*/ void dp8390_dump() { dpeth_t *dep; int isr; dep = &de_state; printf("\n"); #if XXX if (dep->de_mode == DEM_DISABLED) printf("dp8390 instance %d is disabled\n", de_instance); else if (dep->de_mode == DEM_SINK) printf("dp8390 instance %d is in sink mode\n", de_instance); #endif if (dep->de_mode != DEM_ENABLED) return; printf("dp8390 statistics of instance %d:\n", de_instance); printf("recvErr :%8ld\t", dep->de_stat.ets_recvErr); printf("sendErr :%8ld\t", dep->de_stat.ets_sendErr); printf("OVW :%8ld\n", dep->de_stat.ets_OVW); printf("CRCerr :%8ld\t", dep->de_stat.ets_CRCerr); printf("frameAll :%8ld\t", dep->de_stat.ets_frameAll); printf("missedP :%8ld\n", dep->de_stat.ets_missedP); printf("packetR :%8ld\t", dep->de_stat.ets_packetR); printf("packetT :%8ld\t", dep->de_stat.ets_packetT); printf("transDef :%8ld\n", dep->de_stat.ets_transDef); printf("collision :%8ld\t", dep->de_stat.ets_collision); printf("transAb :%8ld\t", dep->de_stat.ets_transAb); printf("carrSense :%8ld\n", dep->de_stat.ets_carrSense); printf("fifoUnder :%8ld\t", dep->de_stat.ets_fifoUnder); printf("fifoOver :%8ld\t", dep->de_stat.ets_fifoOver); printf("CDheartbeat:%8ld\n", dep->de_stat.ets_CDheartbeat); printf("OWC :%8ld\t", dep->de_stat.ets_OWC); isr= inb_reg0(dep, DP_ISR); printf("dp_isr = 0x%x + 0x%x, de_flags = 0x%x\n", isr, inb_reg0(dep, DP_ISR), dep->de_flags); }
/* ** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize) ** Function: Copies a packet from user area to board (Prog. I/O, 16bits). */ static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize) { u8_t two_bytes[2]; phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes); vir_bytes ecount = (pktsize + 1) & NOT(0x0001); int bytes, ix = 0, odd_byte = 0; iovec_dat_t *iovp = &dep->de_write_iovec; outb_reg0(dep, DP_ISR, ISR_RDC); dp_read_setup(dep, ecount, pageno * DP_PAGESIZE); do { bytes = iovp->iod_iovec[ix].iov_size; if (bytes > pktsize) bytes = pktsize; phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes); if (!phys_user) panic(UmapErrMsg); if (odd_byte) { phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1); out_word(dep->de_data_port, *(u16_t *)two_bytes); pktsize--; bytes--; phys_user++; odd_byte = 0; if (!bytes) continue; } ecount = bytes & NOT(0x0001); if (ecount != 0) { phys_outsw(dep->de_data_port, phys_user, ecount); pktsize -= ecount; bytes -= ecount; phys_user += ecount; } if (bytes) { phys_copy(phys_user, phys_2bytes, (phys_bytes) 1); pktsize--; bytes--; phys_user++; odd_byte = 1; } if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */ dp_next_iovec(iovp); ix = 0; } } while (bytes > 0); if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes); for (ix = 0; ix < 100; ix++) { if (inb_reg0(dep, DP_ISR) & ISR_RDC) break; } if (ix == 100) { panic(RdmaErrMsg); } return; }
/*===========================================================================* * ne_probe * *===========================================================================*/ int ne_probe(dpeth_t *dep) { int byte; int i; int loc1, loc2; testf_t f; dep->de_dp8390_port= dep->de_base_port + NE_DP8390; /* We probe for an ne1000 or an ne2000 by testing whether the * on board is reachable through the dp8390. Note that the * ne1000 is an 8bit card and has a memory region distict from * the 16bit ne2000 */ for (dep->de_16bit= 0; dep->de_16bit < 2; dep->de_16bit++) { /* Reset the ethernet card */ byte= inb_ne(dep, NE_RESET); milli_delay(2); outb_ne(dep, NE_RESET, byte); milli_delay(2); /* Reset the dp8390 */ outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT); for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++) ; /* Do nothing */ /* Check if the dp8390 is really there */ if ((inb_reg0(dep, DP_CR) & (CR_STP|CR_DM_ABORT)) != (CR_STP|CR_DM_ABORT)) { return 0; } /* Disable the receiver and init TCR and DCR. */ outb_reg0(dep, DP_RCR, RCR_MON); outb_reg0(dep, DP_TCR, TCR_NORMAL); if (dep->de_16bit) { outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS); } else { outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES | DCR_BMS); } if (dep->de_16bit) { loc1= NE2000_START; loc2= NE2000_START + NE2000_SIZE - 4; f= test_16; } else { loc1= NE1000_START; loc2= NE1000_START + NE1000_SIZE - 4; f= test_8; } if (f(dep, loc1, pat0) && f(dep, loc1, pat1) && f(dep, loc1, pat2) && f(dep, loc1, pat3) && f(dep, loc2, pat0) && f(dep, loc2, pat1) && f(dep, loc2, pat2) && f(dep, loc2, pat3)) { /* We don't need a memory segment */ dep->de_linmem= 0; if (!dep->de_pci) dep->de_initf= ne_init; dep->de_stopf= ne_stop; dep->de_prog_IO= 1; return 1; } } return 0; }
/* ** Name: void ns_init(dpeth_t *dep) ** Function: Initializes the NS 8390 */ void ns_init(dpeth_t * dep) { int dp_reg; int ix; /* NS8390 initialization (as recommended in National Semiconductor specs) */ outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */ #if PIO16 == 0 outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS)); #else outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS)); #endif outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR1, 0); outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */ outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Sets Loopback mode 1 */ outb_reg0(dep, DP_PSTART, dep->de_startpage); outb_reg0(dep, DP_PSTOP, dep->de_stoppage); outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1); outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */ outb_reg0(dep, DP_IMR, 0); /* Clears Interrupt Mask Register */ /* Copies station address in page 1 registers */ outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA); /* Selects Page 1 */ for (ix = 0; ix < SA_ADDR_LEN; ix += 1) /* Initializes address */ outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]); for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1) /* Initializes address */ outb_reg1(dep, ix, 0xFF); outb_reg1(dep, DP_CURR, dep->de_startpage); outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA); /* Selects Page 0 */ inb_reg0(dep, DP_CNTR0); /* Resets counters by reading them */ inb_reg0(dep, DP_CNTR1); inb_reg0(dep, DP_CNTR2); dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE; outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */ outb_reg0(dep, DP_IMR, dp_reg); /* Sets Interrupt Mask register */ dp_reg = 0; if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM; if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB; if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM; outb_reg0(dep, DP_RCR, dp_reg); /* Sets receive as requested */ outb_reg0(dep, DP_TCR, TCR_NORMAL); /* Sets transmitter */ outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); /* Starts board */ /* Initializes the send queue. */ for (ix = 0; ix < dep->de_sendq_nr; ix += 1) dep->de_sendq[ix].sq_filled = 0; dep->de_sendq_head = dep->de_sendq_tail = 0; /* Device specific functions */ if (!dep->de_prog_IO) { dep->de_user2nicf = mem_user2nic; dep->de_nic2userf = mem_nic2user; dep->de_getblockf = mem_getblock; } else { #if PIO16 == 0 dep->de_user2nicf = pio_user2nic; dep->de_nic2userf = pio_nic2user; dep->de_getblockf = pio_getblock; #else #error Missing I/O functions for pio 16 bits #endif } dep->de_recvf = ns_recv; dep->de_sendf = ns_send; dep->de_flagsf = ns_reinit; dep->de_resetf = ns_reset; dep->de_getstatsf = ns_stats; dep->de_dumpstatsf = ns_dodump; dep->de_interruptf = ns_interrupt; return; /* Done */ }
/* ** Name: void ns_interrupt(dpeth_t * dep) ** Function: Handles interrupt. */ static void ns_interrupt(dpeth_t * dep) { int isr, tsr; int queue; while ((isr = inb_reg0(dep, DP_ISR)) != 0) { outb_reg0(dep, DP_ISR, isr); if (isr & (ISR_PTX | ISR_TXE)) { tsr = inb_reg0(dep, DP_TSR); if (tsr & TSR_PTX) { dep->de_stat.ets_packetT++; } if (tsr & TSR_COL) dep->de_stat.ets_collision++; if (tsr & (TSR_ABT | TSR_FU)) { dep->de_stat.ets_fifoUnder++; } if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) { printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr); dep->de_stat.ets_sendErr++; } queue = dep->de_sendq_tail; if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */ printf("%s: transmit interrupt, but not sending\n", dep->de_name); continue; } dep->de_sendq[queue].sq_filled = FALSE; if (++queue == dep->de_sendq_nr) queue = 0; dep->de_sendq_tail = queue; if (dep->de_sendq[queue].sq_filled) { ns_start_xmit(dep, dep->de_sendq[queue].sq_size, dep->de_sendq[queue].sq_sendpage); } if (dep->de_flags & DEF_SENDING) { ns_send(dep, TRUE, dep->de_send_s); } } if (isr & ISR_PRX) { ns_recv(dep, TRUE, 0); } if (isr & ISR_RXE) { printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR)); dep->de_stat.ets_recvErr++; } if (isr & ISR_CNT) { dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1); dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2); } if (isr & ISR_OVW) { printf("%s: got overwrite warning\n", dep->de_name); } if (isr & ISR_RDC) { /* Nothing to do */ } if (isr & ISR_RST) { /* This means we got an interrupt but the ethernet * chip is shutdown. We set the flag DEF_STOPPED, and * continue processing arrived packets. When the * receive buffer is empty, we reset the dp8390. */ printf("%s: network interface stopped\n", dep->de_name); dep->de_flags |= DEF_STOPPED; break; } } if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) { /* The chip is stopped, and all arrived packets delivered */ ns_reset(dep); dep->de_flags &= NOT(DEF_STOPPED); } return; }
/* ** Name: void ns_recv(dpeth_t *dep, int fromint, int size) ** Function: Gets a packet from device */ static void ns_recv(dpeth_t *dep, int fromint, int size) { dp_rcvhdr_t header; unsigned pageno, curr, next; vir_bytes length; int packet_processed = FALSE; #ifdef ETH_IGN_PROTO u16_t eth_type; #endif pageno = inb_reg0(dep, DP_BNRY) + 1; if (pageno == dep->de_stoppage) pageno = dep->de_startpage; do { /* */ outb_reg0(dep, DP_CR, CR_PS_P1); curr = inb_reg1(dep, DP_CURR); outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA); if (curr == pageno) break; (dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header); #ifdef ETH_IGN_PROTO (dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type); #endif length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t); next = header.dr_next; if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) { printf("%s: packet with strange length arrived: %d\n", dep->de_name, length); dep->de_stat.ets_recvErr += 1; next = curr; } else if (next < dep->de_startpage || next >= dep->de_stoppage) { printf("%s: strange next page\n", dep->de_name); dep->de_stat.ets_recvErr += 1; next = curr; #ifdef ETH_IGN_PROTO } else if (eth_type == eth_ign_proto) { /* Hack: ignore packets of a given protocol */ static int first = TRUE; if (first) { first = FALSE; printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto)); } next = curr; #endif } else if (header.dr_status & RSR_FO) { /* This is very serious, issue a warning and reset buffers */ printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name); dep->de_stat.ets_fifoOver += 1; next = curr; } else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) { if (!(dep->de_flags & DEF_READING)) break; (dep->de_nic2userf) (dep, pageno, length); dep->de_read_s = length; dep->de_flags |= DEF_ACK_RECV; dep->de_flags &= NOT(DEF_READING); packet_processed = TRUE; } dep->bytes_Rx += (long) length; dep->de_stat.ets_packetR += 1; outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1); pageno = next; } while (!packet_processed); #if 0 if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) /* The chip is stopped, and all arrived packets delivered */ (*dep->de_resetf) (dep); dep->de_flags &= NOT(DEF_STOPPED); #endif return; }