📄 fxp.c
字号:
return; /* PCI device is present */ fp->fxp_mode= FM_ENABLED; fp->fxp_flags= FF_EMPTY; fp->fxp_got_int= 0; fp->fxp_send_int= 0; fp->fxp_ee_addrlen= 0; /* Unknown */ fp->fxp_need_reset= 0; fp->fxp_report_link= 0; fp->fxp_link_up= -1; /* Unknown */ fp->fxp_mii_busy= 0; fp->fxp_read_s= 0; fp->fxp_rx_need_restart= 0; fp->fxp_need_conf= 0; fp->fxp_tx_head= 0; fp->fxp_tx_tail= 0; fp->fxp_tx_alive= 0; fp->fxp_tx_threshold= TXTT_MIN; /* Try to come up with a sensible configuration for the current * device. Unfortunately every device is different, defaults are * not always zero, and some fields are re-used with a completely * different interpretation. We start out with a sensible default * for all devices and then add device specific changes. */ fp->fxp_conf_bytes[0]= CC_BYTES_NR; fp->fxp_conf_bytes[1]= CTL_DEFAULT | CRL_DEFAULT; fp->fxp_conf_bytes[2]= CAI_DEFAULT; fp->fxp_conf_bytes[3]= 0; fp->fxp_conf_bytes[4]= 0; fp->fxp_conf_bytes[5]= 0; fp->fxp_conf_bytes[6]= CCB6_ESC | CCB6_ETCB | CCB6_RES; fp->fxp_conf_bytes[7]= CUR_1; fp->fxp_conf_bytes[8]= CCB8_503_MII; fp->fxp_conf_bytes[9]= 0; fp->fxp_conf_bytes[10]= CLB_NORMAL | CPAL_DEFAULT | CCB10_NSAI | CCB10_RES1; fp->fxp_conf_bytes[11]= 0; fp->fxp_conf_bytes[12]= CIS_DEFAULT; fp->fxp_conf_bytes[13]= CCB13_DEFAULT; fp->fxp_conf_bytes[14]= CCB14_DEFAULT; fp->fxp_conf_bytes[15]= CCB15_RES1 | CCB15_RES2; fp->fxp_conf_bytes[16]= CCB16_DEFAULT; fp->fxp_conf_bytes[17]= CCB17_DEFAULT; fp->fxp_conf_bytes[18]= CCB18_RES1 | CCB18_PFCT | CCB18_PE; fp->fxp_conf_bytes[19]= CCB19_FDPE; fp->fxp_conf_bytes[20]= CCB20_PFCL | CCB20_RES1; fp->fxp_conf_bytes[21]= CCB21_RES21;#if VERBOSE for (i= 0; i<CC_BYTES_NR; i++) printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]); printf("\n");#endif mwi= 0; /* Do we want "Memory Write and Invalidate"? */ ext_stat1= 0; /* Do we want extended statistical counters? */ ext_stat2= 0; /* Do we want even more statistical counters? */ lim_fifo= 0; /* Limit number of frame in TX FIFO */ i82503= 0; /* Older 10 Mbps interface on the 82557 */ fc= 0; /* Flow control */ switch(fp->fxp_type) { case FT_82557: if (i82503) { fp->fxp_conf_bytes[8] &= ~CCB8_503_MII; fp->fxp_conf_bytes[15] |= CCB15_CRSCDT; } break; case FT_82558A: case FT_82559: if (mwi) fp->fxp_conf_bytes[3] |= CCB3_MWIE; if (ext_stat1) fp->fxp_conf_bytes[6] &= ~CCB6_ESC; if (ext_stat2) fp->fxp_conf_bytes[6] &= ~CCB6_TCOSC; if (lim_fifo) fp->fxp_conf_bytes[7] |= CCB7_2FFIFO; if (fc) { /* From FreeBSD driver */ fp->fxp_conf_bytes[16]= 0x1f; fp->fxp_conf_bytes[17]= 0x01; fp->fxp_conf_bytes[19] |= CCB19_FDRSTAFC | CCB19_FDRSTOFC; } fp->fxp_conf_bytes[18] |= CCB18_LROK; break; default: panic("FXP","fxp_conf_hw: bad device type", fp->fxp_type); }#if VERBOSE for (i= 0; i<CC_BYTES_NR; i++) printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]); printf("\n");#endif}/*===========================================================================* * fxp_init_hw * *===========================================================================*/static void fxp_init_hw(fp)fxp_t *fp;{ int i, r, isr; port_t port; u32_t bus_addr; port= fp->fxp_base_port; fxp_init_buf(fp); fp->fxp_flags = FF_EMPTY; fp->fxp_flags |= FF_ENABLED; /* Set the interrupt handler and policy. Do not automatically * reenable interrupts. Return the IRQ line number on interrupts. */ fp->fxp_hook = fp->fxp_irq; r= sys_irqsetpolicy(fp->fxp_irq, 0, &fp->fxp_hook); if (r != OK) panic("FXP","sys_irqsetpolicy failed", r); fxp_reset_hw(fp); r= sys_irqenable(&fp->fxp_hook); if (r != OK) panic("FXP","sys_irqenable failed", r); /* Reset PHY? */ fxp_do_conf(fp); /* Set pointer to statistical counters */ r= sys_umap(SELF, D, (vir_bytes)&fp->fxp_stat, sizeof(fp->fxp_stat), &bus_addr); if (r != OK) panic("FXP","sys_umap failed", r); fxp_cu_ptr_cmd(fp, SC_CU_LOAD_DCA, bus_addr, TRUE /* check idle */); /* Ack previous interrupts */ isr= fxp_inb(port, SCB_INT_STAT); fxp_outb(port, SCB_INT_STAT, isr); /* Enable interrupts */ fxp_outb(port, SCB_INT_MASK, 0); fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr, TRUE /* check idle */); fxp_confaddr(fp); if (debug) { printf("%s: Ethernet address ", fp->fxp_name); for (i= 0; i < 6; i++) { printf("%x%c", fp->fxp_address.ea_addr[i], i < 5 ? ':' : '\n'); } }}/*===========================================================================* * fxp_init_buf * *===========================================================================*/static void fxp_init_buf(fp)fxp_t *fp;{ size_t rx_totbufsize, tx_totbufsize, tot_bufsize; phys_bytes buf; int i, r; struct rfd *rfdp; struct tx *txp; fp->fxp_rx_nbuf= N_RX_BUF; rx_totbufsize= fp->fxp_rx_nbuf * sizeof(struct rfd); fp->fxp_rx_bufsize= rx_totbufsize; fp->fxp_tx_nbuf= N_TX_BUF; tx_totbufsize= fp->fxp_tx_nbuf * sizeof(struct tx); fp->fxp_tx_bufsize= tx_totbufsize; tot_bufsize= tx_totbufsize + rx_totbufsize; /* What about memory allocation? */ { static int first_time= 1; assert(first_time); first_time= 0;#define BUFALIGN 4096 assert(tot_bufsize <= sizeof(buffer)-BUFALIGN); buf= (phys_bytes)buffer; buf += BUFALIGN - (buf % BUFALIGN); } fp->fxp_rx_buf= (struct rfd *)buf; r= sys_umap(SELF, D, (vir_bytes)buf, rx_totbufsize, &fp->fxp_rx_busaddr); if (r != OK) panic("FXP","sys_umap failed", r); for (i= 0, rfdp= fp->fxp_rx_buf; i<fp->fxp_rx_nbuf; i++, rfdp++) { rfdp->rfd_status= 0; rfdp->rfd_command= 0; if (i != fp->fxp_rx_nbuf-1) { r= sys_umap(SELF, D, (vir_bytes)&rfdp[1], sizeof(rfdp[1]), &rfdp->rfd_linkaddr); if (r != OK) panic("FXP","sys_umap failed", r); } else { rfdp->rfd_linkaddr= fp->fxp_rx_busaddr; rfdp->rfd_command |= RFDC_EL; } rfdp->rfd_reserved= 0; rfdp->rfd_res= 0; rfdp->rfd_size= sizeof(rfdp->rfd_buf); } fp->fxp_rx_head= 0; fp->fxp_tx_buf= (struct tx *)(buf+rx_totbufsize); r= sys_umap(SELF, D, (vir_bytes)fp->fxp_tx_buf, (phys_bytes)tx_totbufsize, &fp->fxp_tx_busaddr); if (r != OK) panic("FXP","sys_umap failed", r); for (i= 0, txp= fp->fxp_tx_buf; i<fp->fxp_tx_nbuf; i++, txp++) { txp->tx_status= 0; txp->tx_command= TXC_EL | CBL_NOP; /* Just in case */ if (i != fp->fxp_tx_nbuf-1) { r= sys_umap(SELF, D, (vir_bytes)&txp[1], (phys_bytes)sizeof(txp[1]), &txp->tx_linkaddr); if (r != OK) panic("FXP","sys_umap failed", r); } else { txp->tx_linkaddr= fp->fxp_tx_busaddr; } txp->tx_tbda= TX_TBDA_NIL; txp->tx_size= 0; txp->tx_tthresh= fp->fxp_tx_threshold; txp->tx_ntbd= 0; } fp->fxp_tx_idle= 1;}/*===========================================================================* * fxp_reset_hw * *===========================================================================*/static void fxp_reset_hw(fp)fxp_t *fp;{/* Inline the function in init? */ port_t port; port= fp->fxp_base_port; /* Reset device */ fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET); tickdelay(MICROS_TO_TICKS(CSR_PORT_RESET_DELAY)); /* Disable interrupts */ fxp_outb(port, SCB_INT_MASK, SIM_M); /* Set CU base to zero */ fxp_cu_ptr_cmd(fp, SC_CU_LOAD_BASE, 0, TRUE /* check idle */); /* Set RU base to zero */ fxp_ru_ptr_cmd(fp, SC_RU_LOAD_BASE, 0, TRUE /* check idle */);}/*===========================================================================* * fxp_confaddr * *===========================================================================*/static void fxp_confaddr(fp)fxp_t *fp;{ static char eakey[]= FXP_ENVVAR "#_EA"; static char eafmt[]= "x:x:x:x:x:x"; clock_t t0,t1; int i, r; port_t port; u32_t bus_addr; long v; struct ias ias; port= fp->fxp_base_port; /* User defined ethernet address? */ eakey[sizeof(FXP_ENVVAR)-1]= '0' + (fp-fxp_table);#if 0 for (i= 0; i < 6; i++) { if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; fp->fxp_address.ea_addr[i]= v; }#else i= 0;#endif#if 0 if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */#endif if (i == 0) { /* Get ethernet address from EEPROM */ for (i= 0; i<3; i++) { v= eeprom_read(fp, i); fp->fxp_address.ea_addr[i*2]= (v & 0xff); fp->fxp_address.ea_addr[i*2+1]= ((v >> 8) & 0xff); } } /* Tell NIC about ethernet address */ ias.ias_status= 0; ias.ias_command= CBL_C_EL | CBL_AIS; ias.ias_linkaddr= 0; memcpy(ias.ias_ethaddr, fp->fxp_address.ea_addr, sizeof(ias.ias_ethaddr)); r= sys_umap(SELF, D, (vir_bytes)&ias, (phys_bytes)sizeof(ias), &bus_addr); if (r != OK) panic("FXP","sys_umap failed", r); fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */); getuptime(&t0); do { /* Wait for CU command to complete */ if (ias.ias_status & CBL_F_C) break; } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000)); if (!(ias.ias_status & CBL_F_C)) panic("FXP","fxp_confaddr: CU command failed to complete", NO_NUM); if (!(ias.ias_status & CBL_F_OK)) panic("FXP","fxp_confaddr: CU command failed", NO_NUM);#if VERBOSE printf("%s: hardware ethernet address: ", fp->fxp_name); for (i= 0; i<6; i++) { printf("%02x%s", fp->fxp_address.ea_addr[i], i < 5 ? ":" : ""); } printf("\n");#endif}/*===========================================================================* * fxp_rec_mode * *===========================================================================*/static void fxp_rec_mode(fp)fxp_t *fp;{ fp->fxp_conf_bytes[0]= CC_BYTES_NR; /* Just to be sure */ fp->fxp_conf_bytes[15] &= ~(CCB15_BD|CCB15_PM); fp->fxp_conf_bytes[21] &= ~CCB21_MA; if (fp->fxp_flags & FF_PROMISC) fp->fxp_conf_bytes[15] |= CCB15_PM; if (fp->fxp_flags & FF_MULTI) fp->fxp_conf_bytes[21] |= CCB21_MA; if (!(fp->fxp_flags & (FF_BROAD|FF_MULTI|FF_PROMISC))) fp->fxp_conf_bytes[15] |= CCB15_BD; /* Queue request if not idle */ if (fp->fxp_tx_idle) { fxp_do_conf(fp); } else { printf("fxp_rec_mode: setting fxp_need_conf\n"); fp->fxp_need_conf= TRUE; }}/*===========================================================================* * fxp_writev * *===========================================================================*/static void fxp_writev(mp, from_int, vectored)message *mp;int from_int;int vectored;{ vir_bytes iov_src; int i, j, n, o, r, s, dl_port, count, size, prev_head; int fxp_client, fxp_tx_nbuf, fxp_tx_head; u16_t tx_command; fxp_t *fp; iovec_t *iovp; struct tx *txp, *prev_txp; dl_port = mp->DL_PORT; count = mp->DL_COUNT; if (dl_port < 0 || dl_port >= FXP_PORT_NR) panic("FXP","fxp_writev: illegal port", dl_port); fp= &fxp_table[dl_port]; fxp_client= mp->DL_PROC; fp->fxp_client= fxp_client; assert(fp->fxp_mode == FM_ENABLED); assert(fp->fxp_flags & FF_ENABLED); if (from_int) { assert(fp->fxp_flags & FF_SEND_AVAIL); fp->fxp_flags &= ~FF_SEND_AVAIL; fp->fxp_tx_alive= TRUE; } if (fp->fxp_tx_idle) { txp= fp->fxp_tx_buf; fxp_tx_head= 0; /* lint */ prev_txp= NULL; /* lint */ } else { fxp_tx_nbuf= fp->fxp_tx_nbuf; prev_head= fp->fxp_tx_head; fxp_tx_head= prev_head+1; if (fxp_tx_head == fxp_tx_nbuf) fxp_tx_head= 0; assert(fxp_tx_head < fxp_tx_nbuf); if (fxp_tx_head == fp->fxp_tx_tail) { /* Send queue is full */ assert(!(fp->fxp_flags & FF_SEND_AVAIL)); fp->fxp_flags |= FF_SEND_AVAIL; goto suspend; } prev_txp= &fp->fxp_tx_buf[prev_head]; txp= &fp->fxp_tx_buf[fxp_tx_head]; } assert(!(fp->fxp_flags & FF_SEND_AVAIL)); assert(!(fp->fxp_flags & FF_PACK_SENT)); if (vectored) { iov_src = (vir_bytes)mp->DL_ADDR; size= 0; o= 0; for (i= 0; i<count; i += IOVEC_NR, iov_src += IOVEC_NR * sizeof(fp->fxp_iovec[0])) { n= IOVEC_NR; if (i+n > count) n= count-i; r= sys_vircopy(fxp_client, D, iov_src, SELF, D, (vir_bytes)fp->fxp_iovec, n * sizeof(fp->fxp_iovec[0])); if (r != OK) panic("FXP","fxp_writev: sys_vircopy failed", r); for (j= 0, iovp= fp->fxp_iovec; j<n; j++, iovp++) { s= iovp->iov_size; if (size + s > ETH_MAX_PACK_SIZE_TAGGED) { panic("FXP","fxp_writev: invalid packet size", NO_NUM); } r= sys_vircopy(fxp_client, D, iovp->iov_addr, SELF, D, (vir_bytes)(txp->tx_buf+o), s); if (r != OK) { panic("FXP","fxp_writev: sys_vircopy failed", r); } size += s; o += s; } } if (size < ETH_MIN_PACK_SIZE) panic("FXP","fxp_writev: invalid packet size", size); } else { size= mp->DL_COUNT; if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED) panic("FXP","fxp_writev: invalid packet size", size); r= sys_vircopy(fxp_client, D, (vir_bytes)mp->DL_ADDR, SELF, D, (vir_bytes)txp->tx_buf, size); if (r != OK) panic("FXP","fxp_writev: sys_vircopy failed", r); } txp->tx_status= 0; txp->tx_command= TXC_EL | CBL_XMIT; txp->tx_tbda= TX_TBDA_NIL; txp->tx_size= TXSZ_EOF | size; txp->tx_tthresh= fp->fxp_tx_threshold; txp->tx_ntbd= 0; if (fp->fxp_tx_idle) { fp->fxp_tx_idle= 0; fp->fxp_tx_head= fp->fxp_tx_tail= 0; fxp_cu_ptr_cmd(fp, SC_CU_START, fp->fxp_tx_busaddr, TRUE /* check idle */); } else { /* Link new request in transmit list */ tx_command= prev_txp->tx_command; assert(tx_command == (TXC_EL | CBL_XMIT)); prev_txp->tx_command= CBL_XMIT; fp->fxp_tx_head= fxp_tx_head; } fp->fxp_flags |= FF_PACK_SENT; /* If the interrupt handler called, don't send a reply. The reply * will be sent after all interrupts are handled. */ if (from_int) return; reply(fp, OK, FALSE); return;suspend: if (from_int) panic("FXP","fxp: should not be sending\n", NO_NUM); fp->fxp_tx_mess= *mp; reply(fp, OK, FALSE);}/*===========================================================================* * fxp_readv * *===========================================================================*/static void fxp_readv(mp, from_int, vectored)message *mp;int from_int;int vectored;{ int i, j, n, o, r, s, dl_port, fxp_client, count, size, fxp_rx_head, fxp_rx_nbuf; port_t port; unsigned packlen; vir_bytes iov_src; u16_t rfd_status; u16_t rfd_res; u8_t scb_status; fxp_t *fp; iovec_t *iovp; struct rfd *rfdp, *prev_rfdp; dl_port = mp->DL_PORT; count = mp->DL_COUNT; if (dl_port < 0 || dl_port >= FXP_PORT_NR) panic("FXP","fxp_readv: illegal port", dl_port); fp= &fxp_table[dl_port]; fxp_client= mp->DL_PROC; fp->fxp_client= fxp_client; assert(fp->fxp_mode == FM_ENABLED); assert(fp->fxp_flags & FF_ENABLED); port= fp->fxp_base_port; fxp_rx_head= fp->fxp_rx_head; rfdp= &fp->fxp_rx_buf[fxp_rx_head]; rfd_status= rfdp->rfd_status; if (!(rfd_status & RFDS_C)) { /* Receive buffer is empty, suspend */ goto suspend; } if (!rfd_status & RFDS_OK) { /* Not OK? What happened? */ assert(0); } else { assert(!(rfd_status & (RFDS_CRCERR | RFDS_ALIGNERR | RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT | RFDS_RXERR))); } rfd_res= rfdp->rfd_res; assert(rfd_res & RFDR_EOF); assert(rfd_res & RFDR_F); packlen= rfd_res & RFDSZ_SIZE; if (vectored) { iov_src = (vir_bytes)mp->DL_ADDR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -