📄 dp8390.c
字号:
return; } assert(dep->de_mode == DEM_ENABLED); assert(dep->de_flags & DEF_ENABLED); if(dep->de_flags & DEF_READING) panic("", "dp8390: read already in progress", NO_NUM); if (vectored) { get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR, (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t), dep->de_read_iovec.iod_iovec); dep->de_read_iovec.iod_iovec_s = count; dep->de_read_iovec.iod_proc_nr = mp->DL_PROC; dep->de_read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR; dep->de_tmp_iovec = dep->de_read_iovec; size= calc_iovec_size(&dep->de_tmp_iovec); } else { dep->de_read_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR; dep->de_read_iovec.iod_iovec[0].iov_size = mp->DL_COUNT; dep->de_read_iovec.iod_iovec_s = 1; dep->de_read_iovec.iod_proc_nr = mp->DL_PROC; dep->de_read_iovec.iod_iovec_addr = 0; size= count; } if (size < ETH_MAX_PACK_SIZE_TAGGED) panic("", "dp8390: wrong packet size", size); dep->de_flags |= DEF_READING; dp_recv(dep); if ((dep->de_flags & (DEF_READING|DEF_STOPPED)) == (DEF_READING|DEF_STOPPED)) { /* The chip is stopped, and all arrived packets are * delivered. */ dp_reset(dep); } reply(dep, OK, FALSE);}/*===========================================================================* * do_init * *===========================================================================*/static void do_init(mp)message *mp;{ int port; dpeth_t *dep; message reply_mess;#if ENABLE_PCI pci_conf(); /* Configure PCI devices. */#endif port = mp->DL_PORT; if (port < 0 || port >= DE_PORT_NR) { reply_mess.m_type= DL_INIT_REPLY; reply_mess.m3_i1= ENXIO; mess_reply(mp, &reply_mess); return; } dep= &de_table[port]; if (dep->de_mode == DEM_DISABLED) { /* This is the default, try to (re)locate the device. */ conf_hw(dep); if (dep->de_mode == DEM_DISABLED) { /* Probe failed, or the device is configured off. */ reply_mess.m_type= DL_INIT_REPLY; reply_mess.m3_i1= ENXIO; mess_reply(mp, &reply_mess); return; } if (dep->de_mode == DEM_ENABLED) dp_init(dep); } if (dep->de_mode == DEM_SINK) { strncpy((char *) dep->de_address.ea_addr, "ZDP", 6); dep->de_address.ea_addr[5] = port; dp_confaddr(dep); reply_mess.m_type = DL_INIT_REPLY; reply_mess.m3_i1 = mp->DL_PORT; reply_mess.m3_i2 = DE_PORT_NR; *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address; mess_reply(mp, &reply_mess); return; } assert(dep->de_mode == DEM_ENABLED); assert(dep->de_flags & DEF_ENABLED); dep->de_flags &= ~(DEF_PROMISC | DEF_MULTI | DEF_BROAD); if (mp->DL_MODE & DL_PROMISC_REQ) dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD; if (mp->DL_MODE & DL_MULTI_REQ) dep->de_flags |= DEF_MULTI; if (mp->DL_MODE & DL_BROAD_REQ) dep->de_flags |= DEF_BROAD; dep->de_client = mp->m_source; dp_reinit(dep); reply_mess.m_type = DL_INIT_REPLY; reply_mess.m3_i1 = mp->DL_PORT; reply_mess.m3_i2 = DE_PORT_NR; *(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address; mess_reply(mp, &reply_mess);}/*===========================================================================* * do_int * *===========================================================================*/static void do_int(dep)dpeth_t *dep;{ if (dep->de_flags & (DEF_PACK_SEND | DEF_PACK_RECV)) reply(dep, OK, TRUE);}/*===========================================================================* * do_getstat * *===========================================================================*/static void do_getstat(mp)message *mp;{ int port; dpeth_t *dep; port = mp->DL_PORT; if (port < 0 || port >= DE_PORT_NR) panic("", "dp8390: illegal port", port); dep= &de_table[port]; dep->de_client= mp->DL_PROC; if (dep->de_mode == DEM_SINK) { put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR, (vir_bytes) sizeof(dep->de_stat), &dep->de_stat); reply(dep, OK, FALSE); return; } assert(dep->de_mode == DEM_ENABLED); assert(dep->de_flags & DEF_ENABLED); dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0); dep->de_stat.ets_frameAll += inb_reg0(dep, DP_CNTR1); dep->de_stat.ets_missedP += inb_reg0(dep, DP_CNTR2); put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR, (vir_bytes) sizeof(dep->de_stat), &dep->de_stat); reply(dep, OK, FALSE);}/*===========================================================================* * do_getname * *===========================================================================*/static void do_getname(mp)message *mp;{ int r; strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME)); mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0'; mp->m_type= DL_NAME_REPLY; r= send(mp->m_source, mp); if (r != OK) panic("dp8390", "do_getname: send failed: %d\n", r);}/*===========================================================================* * do_stop * *===========================================================================*/static void do_stop(mp)message *mp;{ int port; dpeth_t *dep; port = mp->DL_PORT; if (port < 0 || port >= DE_PORT_NR) panic("", "dp8390: illegal port", port); dep= &de_table[port]; if (dep->de_mode == DEM_SINK) return; assert(dep->de_mode == DEM_ENABLED); if (!(dep->de_flags & DEF_ENABLED)) return; outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT); (dep->de_stopf)(dep); dep->de_flags= DEF_EMPTY;}/*===========================================================================* * dp_init * *===========================================================================*/static void dp_init(dep)dpeth_t *dep;{ int dp_rcr_reg; int i, r; /* General initialization */ dep->de_flags = DEF_EMPTY; (*dep->de_initf)(dep); dp_confaddr(dep); if (debug) { printf("%s: Ethernet address ", dep->de_name); for (i= 0; i < 6; i++) printf("%x%c", dep->de_address.ea_addr[i], i < 5 ? ':' : '\n'); } /* Initialization of the dp8390 following the mandatory procedure * in reference manual ("DP8390D/NS32490D NIC Network Interface * Controller", National Semiconductor, July 1995, Page 29). */ /* Step 1: */ outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT); /* Step 2: */ 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); /* Step 3: */ outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR1, 0); /* Step 4: */ dp_rcr_reg = 0; if (dep->de_flags & DEF_PROMISC) dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM; if (dep->de_flags & DEF_BROAD) dp_rcr_reg |= RCR_AB; if (dep->de_flags & DEF_MULTI) dp_rcr_reg |= RCR_AM; outb_reg0(dep, DP_RCR, dp_rcr_reg); /* Step 5: */ outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Step 6: */ outb_reg0(dep, DP_BNRY, dep->de_startpage); outb_reg0(dep, DP_PSTART, dep->de_startpage); outb_reg0(dep, DP_PSTOP, dep->de_stoppage); /* Step 7: */ outb_reg0(dep, DP_ISR, 0xFF); /* Step 8: */ outb_reg0(dep, DP_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE); /* Step 9: */ outb_reg0(dep, DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP); outb_reg1(dep, DP_PAR0, dep->de_address.ea_addr[0]); outb_reg1(dep, DP_PAR1, dep->de_address.ea_addr[1]); outb_reg1(dep, DP_PAR2, dep->de_address.ea_addr[2]); outb_reg1(dep, DP_PAR3, dep->de_address.ea_addr[3]); outb_reg1(dep, DP_PAR4, dep->de_address.ea_addr[4]); outb_reg1(dep, DP_PAR5, dep->de_address.ea_addr[5]); outb_reg1(dep, DP_MAR0, 0xff); outb_reg1(dep, DP_MAR1, 0xff); outb_reg1(dep, DP_MAR2, 0xff); outb_reg1(dep, DP_MAR3, 0xff); outb_reg1(dep, DP_MAR4, 0xff); outb_reg1(dep, DP_MAR5, 0xff); outb_reg1(dep, DP_MAR6, 0xff); outb_reg1(dep, DP_MAR7, 0xff); outb_reg1(dep, DP_CURR, dep->de_startpage + 1); /* Step 10: */ outb_reg0(dep, DP_CR, CR_DM_ABORT | CR_STA); /* Step 11: */ outb_reg0(dep, DP_TCR, TCR_NORMAL); inb_reg0(dep, DP_CNTR0); /* reset counters by reading */ inb_reg0(dep, DP_CNTR1); inb_reg0(dep, DP_CNTR2); /* Finish the initialization. */ dep->de_flags |= DEF_ENABLED; for (i= 0; i<dep->de_sendq_nr; i++) dep->de_sendq[i].sq_filled= 0; dep->de_sendq_head= 0; dep->de_sendq_tail= 0; if (!dep->de_prog_IO) { dep->de_user2nicf= dp_user2nic; dep->de_nic2userf= dp_nic2user; dep->de_getblockf= dp_getblock; } else if (dep->de_16bit) { dep->de_user2nicf= dp_pio16_user2nic; dep->de_nic2userf= dp_pio16_nic2user; dep->de_getblockf= dp_pio16_getblock; } else { dep->de_user2nicf= dp_pio8_user2nic; dep->de_nic2userf= dp_pio8_nic2user; dep->de_getblockf= dp_pio8_getblock; } /* Set the interrupt handler and policy. Do not automatically * reenable interrupts. Return the IRQ line number on interrupts. */ dep->de_hook = dep->de_irq; r= sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook); if (r != OK) panic("DP8390", "sys_irqsetpolicy failed", r); r= sys_irqenable(&dep->de_hook); if (r != OK) { panic("DP8390", "unable enable interrupts", r); }}/*===========================================================================* * dp_confaddr * *===========================================================================*/static void dp_confaddr(dep)dpeth_t *dep;{ int i; char eakey[16]; static char eafmt[]= "x:x:x:x:x:x"; long v; /* User defined ethernet address? */ strcpy(eakey, dp_conf[dep-de_table].dpc_envvar); strcat(eakey, "_EA"); for (i= 0; i < 6; i++) { v= dep->de_address.ea_addr[i]; if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) { break; } dep->de_address.ea_addr[i]= v; } if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */}/*===========================================================================* * dp_reinit * *===========================================================================*/static void dp_reinit(dep)dpeth_t *dep;{ int dp_rcr_reg; outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA); dp_rcr_reg = 0; if (dep->de_flags & DEF_PROMISC) dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM; if (dep->de_flags & DEF_BROAD) dp_rcr_reg |= RCR_AB; if (dep->de_flags & DEF_MULTI) dp_rcr_reg |= RCR_AM; outb_reg0(dep, DP_RCR, dp_rcr_reg);}/*===========================================================================* * dp_reset * *===========================================================================*/static void dp_reset(dep)dpeth_t *dep;{ int i; /* Stop chip */ outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT); outb_reg0(dep, DP_RBCR0, 0); outb_reg0(dep, DP_RBCR1, 0); for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++) ; /* Do nothing */ outb_reg0(dep, DP_TCR, TCR_1EXTERNAL|TCR_OFST); outb_reg0(dep, DP_CR, CR_STA|CR_DM_ABORT); outb_reg0(dep, DP_TCR, TCR_NORMAL); /* Acknowledge the ISR_RDC (remote dma) interrupt. */ for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); i++) ; /* Do nothing */ outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & ~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 (i= 0; i<dep->de_sendq_nr; i++) dep->de_sendq[i].sq_filled= 0; dp_send(dep); dep->de_flags &= ~DEF_STOPPED;}/*===========================================================================* * dp_check_ints * *===========================================================================*/static void dp_check_ints(dep)dpeth_t *dep;{ int isr, tsr; int size, sendq_tail; if (!(dep->de_flags & DEF_ENABLED)) panic("", "dp8390: got premature interrupt", NO_NUM); for(;;) { isr = inb_reg0(dep, DP_ISR); if (!isr) break; outb_reg0(dep, DP_ISR, isr); if (isr & (ISR_PTX|ISR_TXE)) { if (isr & ISR_TXE) {#if DEBUG { printf("%s: got send Error\n", dep->de_name); }#endif dep->de_stat.ets_sendErr++; } else { tsr = inb_reg0(dep, DP_TSR); if (tsr & TSR_PTX) dep->de_stat.ets_packetT++;#if 0 /* Reserved in later manuals, should be ignored */ if (!(tsr & TSR_DFR)) { /* In most (all?) implementations of * the dp8390, this bit is set * when the packet is not deferred */ dep->de_stat.ets_transDef++; }#endif if (tsr & TSR_COL) dep->de_stat.ets_collision++; if (tsr & TSR_ABT) dep->de_stat.ets_transAb++; if (tsr & TSR_CRS) dep->de_stat.ets_carrSense++; if (tsr & TSR_FU && ++dep->de_stat.ets_fifoUnder <= 10) { printf("%s: fifo underrun\n", dep->de_name); } if (tsr & TSR_CDH && ++dep->de_stat.ets_CDheartbeat <= 10) { printf("%s: CD heart beat failure\n", dep->de_name); } if (tsr & TSR_OWC) dep->de_stat.ets_OWC++; } sendq_tail= dep->de_sendq_tail; if (!(dep->de_sendq[sendq_tail].sq_filled)) { /* Software bug? */ assert(!debug); /* Or hardware bug? */ printf( "%s: transmit interrupt, but not sending\n", dep->de_name); continue; } dep->de_sendq[sendq_tail].sq_filled= 0; if (++sendq_tail == dep->de_sendq_nr) sendq_tail= 0; dep->de_sendq_tail= sendq_tail; if (dep->de_sendq[sendq_tail].sq_filled) { size= dep->de_sendq[sendq_tail].sq_size; outb_reg0(dep, DP_TPSR,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -