📄 if_tx.c
字号:
#else ifp->if_flags |= IFF_LINK2;#endif } else { printf(", 10Mbps ");#if !defined(EPIC_NOIFMEDIA) tmp |= IFM_10_T;#endif } if( i & BMCR_FULL_DUPLEX ) { printf("FD");#if !defined(EPIC_NOIFMEDIA) tmp |= IFM_FDX;#else ifp->if_flags |= IFF_LINK1;#endif } } /* Init ifmedia interface */#if !defined(EPIC_NOIFMEDIA) ifmedia_init(&sc->ifmedia,0,epic_ifmedia_change,epic_ifmedia_status); for (i=0; i<EPIC_MTYPESNUM; i++) ifmedia_add(&sc->ifmedia,epic_mtypes[i],0,NULL); ifmedia_set(&sc->ifmedia, tmp);#endif s = splimp(); /* Map interrupt */ if( !pci_map_int(config_id, epic_intr, (void*)sc, &net_imask) ) { printf(": couldn't map interrupt\n"); free(sc, M_DEVBUF); return; } /* Set shut down routine to stop DMA processes on reboot */ at_shutdown(epic_shutdown, sc, SHUTDOWN_POST_SYNC); /* Attach to if manager */ if_attach(ifp); ether_ifattach(ifp);#if NBPFILTER > 0 bpfattach(ifp,DLT_EN10MB, sizeof(struct ether_header));#endif splx(s); printf("\n"); return;}static voidepic_shutdown( int howto, void *sc){ epic_stop(sc);}#endif /* __OpenBSD__ *//* ------------------------------------------------------------------------ OS-independing part ------------------------------------------------------------------------ *//* * This is if_ioctl handler. */static intepic_ifioctl __P(( register struct ifnet * ifp, EPIC_IFIOCTL_CMD_TYPE command, caddr_t data)){ epic_softc_t *sc = ifp->if_softc; int x, error = 0; x = splimp(); switch (command) {#if defined(__FreeBSD__) case SIOCSIFADDR: case SIOCGIFADDR: case SIOCSIFMTU: error = ether_ioctl(ifp, command, data); break;#else /* __OpenBSD__ */ case SIOCSIFADDR: { struct ifaddr *ifa = (struct ifaddr *)data; ifp->if_flags |= IFF_UP; switch(ifa->ifa_addr->sa_family) {#if INET case AF_INET: epic_stop(sc); epic_init(sc); arp_ifinit(&sc->arpcom,ifa); break;#endif /* __FreeBSD__ */#if NS case AF_NS: { register struct ns_addr * ina = &IA_SNS(ifa)->sns_addr; if( ns_nullhost(*ina) ) ina->x_host = *(union ns_host *) LLADDR(ifp->if_sadl); else bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl), ifp->if_addrlen); epic_stop(sc); epic_init(sc); break; }#endif default: epic_stop(sc); epic_init(sc); break; } }#endif case SIOCSIFFLAGS: /* * If the interface is marked up and stopped, then start it. * If it is marked down and running, then stop it. */ if (ifp->if_flags & IFF_UP) { if ((ifp->if_flags & IFF_RUNNING) == 0) { epic_init(sc); break; } } else { if (ifp->if_flags & IFF_RUNNING) { epic_stop(sc); break; } } epic_stop_activity(sc); /* Handle IFF_PROMISC flag */ epic_set_rx_mode(sc);#if defined(EPIC_NOIFMEDIA) /* Handle IFF_LINKx flags */ epic_set_media_speed(sc);#endif epic_start_activity(sc); break; case SIOCADDMULTI: case SIOCDELMULTI: /* Update out multicast list */#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 epic_set_mc_table(sc); error = 0;#else error = (command == SIOCADDMULTI) ? ether_addmulti((struct ifreq *)data, &sc->arpcom) : ether_delmulti((struct ifreq *)data, &sc->arpcom); if (error == ENETRESET) { epic_set_mc_table(sc); error = 0; }#endif break;#if !defined(EPIC_NOIFMEDIA) case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, (struct ifreq *)data, &sc->ifmedia, command); break;#endif default: error = EINVAL; } splx(x); return error;}/* * OS-independed part of attach process. allocate memory for descriptors * and frag lists, wake up chip, read MAC address and PHY identyfier. * Return -1 on failure. */static intepic_common_attach( epic_softc_t *sc){ int i; caddr_t pool; i = sizeof(struct epic_frag_list)*TX_RING_SIZE + sizeof(struct epic_rx_desc)*RX_RING_SIZE + sizeof(struct epic_tx_desc)*TX_RING_SIZE + PAGE_SIZE, sc->pool = (epic_softc_t *) malloc( i, M_DEVBUF, M_NOWAIT); if (sc->pool == NULL) { printf(": can't allocate memory for buffers\n"); return -1; } bzero(sc->pool, i); /* Align pool on PAGE_SIZE */ pool = (caddr_t)sc->pool; pool = (caddr_t)((u_int32_t)(pool + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)); /* Distribute memory */ sc->tx_flist = (void *)pool; pool += sizeof(struct epic_frag_list)*TX_RING_SIZE; sc->rx_desc = (void *)pool; pool += sizeof(struct epic_rx_desc)*RX_RING_SIZE; sc->tx_desc = (void *)pool; /* Bring the chip out of low-power mode. */ CSR_WRITE_4( sc, GENCTL, 0x0000 ); /* Workaround for Application Note 7-15 */ for (i=0; i<16; i++) CSR_WRITE_4(sc, TEST1, TEST1_CLOCK_TEST); /* Read mac address from EEPROM */ for (i = 0; i < ETHER_ADDR_LEN / sizeof(u_int16_t); i++) ((u_int16_t *)sc->sc_macaddr)[i] = epic_read_eeprom(sc,i); /* Identify PHY */ sc->phyid = PHY_READ_2(sc, DP83840_PHYIDR1 )<<6; sc->phyid|= (PHY_READ_2( sc, DP83840_PHYIDR2 )>>10)&0x3F; if( QS6612_OUI != sc->phyid ) printf(": WARNING! PHY unknown (0x%x)",sc->phyid); sc->tx_threshold = TRANSMIT_THRESHOLD; sc->txcon = TXCON_DEFAULT; return 0;}/* * This is if_start handler. It takes mbufs from if_snd queue * and quque them for transmit, one by one, until TX ring become full * or quque become empty. */static voidepic_ifstart(struct ifnet * const ifp){ epic_softc_t *sc = ifp->if_softc; struct epic_tx_buffer *buf; struct epic_tx_desc *desc; struct epic_frag_list *flist; struct mbuf *m0; register struct mbuf *m; register int i;#if 0 /* If no link is established, simply free all mbufs in queue */ PHY_READ_2( sc, DP83840_BMSR ); if( !(BMSR_LINK_STATUS & PHY_READ_2( sc, DP83840_BMSR )) ){ IF_DEQUEUE( &ifp->if_snd, m0 ); while( m0 ) { m_freem(m0); IF_DEQUEUE( &ifp->if_snd, m0 ); } return; }#endif /* Link is OK, queue packets to NIC */ while( sc->pending_txs < TX_RING_SIZE ){ buf = sc->tx_buffer + sc->cur_tx; desc = sc->tx_desc + sc->cur_tx; flist = sc->tx_flist + sc->cur_tx; /* Get next packet to send */ IF_DEQUEUE( &ifp->if_snd, m0 ); /* If nothing to send, return */ if( NULL == m0 ) return; /* If descriptor is busy, set IFF_OACTIVE and exit */ if( desc->status & 0x8000 ) { dprintf((EPIC_FORMAT ": desc is busy in ifstart, up and down interface please\n",EPIC_ARGS(sc))); break; } if( buf->mbuf ) { dprintf((EPIC_FORMAT ": mbuf not freed in ifstart, up and down interface please\n",EPIC_ARGS(sc))); break; } /* Fill fragments list */ for( m=m0, i=0; (NULL != m) && (i < EPIC_MAX_FRAGS); m = m->m_next, i++ ) { flist->frag[i].fraglen = m->m_len; flist->frag[i].fragaddr = vtophys( mtod(m, caddr_t) ); } flist->numfrags = i; /* If packet was more than EPIC_MAX_FRAGS parts, */ /* recopy packet to new allocated mbuf cluster */ if( NULL != m ){ EPIC_MGETCLUSTER(m); if( NULL == m ){ printf(EPIC_FORMAT ": cannot allocate mbuf cluster\n",EPIC_ARGS(sc)); m_freem(m0); ifp->if_oerrors++; continue; } m_copydata( m0, 0, m0->m_pkthdr.len, mtod(m,caddr_t) ); flist->frag[0].fraglen = m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; m->m_pkthdr.rcvif = ifp; flist->numfrags = 1; flist->frag[0].fragaddr = vtophys( mtod(m, caddr_t) ); m_freem(m0); m0 = m; } buf->mbuf = m0; sc->pending_txs++; sc->cur_tx = ( sc->cur_tx + 1 ) & TX_RING_MASK; desc->control = 0x01; desc->txlength = max(m0->m_pkthdr.len,ETHER_MIN_LEN-ETHER_CRC_LEN); desc->status = 0x8000; CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED ); /* Set watchdog timer */ ifp->if_timer = 8;#if NBPFILTER > 0 if( ifp->if_bpf ) #if defined(__FreeBSD__) bpf_mtap( ifp, m0 );#else /* __OpenBSD__ */ bpf_mtap( ifp->if_bpf, m0 );#endif /* __FreeBSD__ */#endif } ifp->if_flags |= IFF_OACTIVE; return; }/* * * splimp() invoked before epic_intr_normal() */static __inline voidepic_rx_done __P(( epic_softc_t *sc )){ u_int16_t len; struct epic_rx_buffer *buf; struct epic_rx_desc *desc; struct mbuf *m; struct ether_header *eh; while( !(sc->rx_desc[sc->cur_rx].status & 0x8000) ) { buf = sc->rx_buffer + sc->cur_rx; desc = sc->rx_desc + sc->cur_rx; /* Switch to next descriptor */ sc->cur_rx = (sc->cur_rx+1) & RX_RING_MASK; /* Check for errors, this should happend */ /* only if SAVE_ERRORED_PACKETS is set, */ /* normaly rx errors generate RXE interrupt */ if( !(desc->status & 1) ) { dprintf((EPIC_FORMAT ": Rx error status: 0x%x\n",EPIC_ARGS(sc),desc->status)); sc->sc_if.if_ierrors++; desc->status = 0x8000; continue; } /* Save packet length and mbuf contained packet */ len = desc->rxlength - ETHER_CRC_LEN; m = buf->mbuf; /* Try to get mbuf cluster */ EPIC_MGETCLUSTER( buf->mbuf ); if( NULL == buf->mbuf ) { printf(EPIC_FORMAT ": cannot allocate mbuf cluster\n",EPIC_ARGS(sc)); buf->mbuf = m; desc->status = 0x8000; sc->sc_if.if_ierrors++; continue; } /* Point to new mbuf, and give descriptor to chip */ desc->bufaddr = vtophys( mtod( buf->mbuf, caddr_t ) ); desc->status = 0x8000; /* First mbuf in packet holds the ethernet and packet headers */ eh = mtod( m, struct ether_header * ); m->m_pkthdr.rcvif = &(sc->sc_if); m->m_pkthdr.len = m->m_len = len;#if NBPFILTER > 0 /* Give mbuf to BPFILTER */ if( sc->sc_if.if_bpf ) #if defined(__FreeBSD__) bpf_mtap( &sc->sc_if, m );#else /* __OpenBSD__ */ bpf_mtap( sc->sc_if.if_bpf, m );#endif /* __FreeBSD__ */#endif /* NBPFILTER */#ifdef BRIDGE if (do_bridge) { struct ifnet *bdg_ifp ; bdg_ifp = bridge_in(m); if (bdg_ifp == BDG_DROP) { if (m) m_free(m); continue; /* and drop */ } if (bdg_ifp != BDG_LOCAL) bdg_forward(&m, bdg_ifp); if (bdg_ifp != BDG_LOCAL && bdg_ifp != BDG_BCAST && bdg_ifp != BDG_MCAST) { if (m) m_free(m); continue; /* and drop */ } /* all others accepted locally */ }#endif#if NBPFILTER > 0#ifdef BRIDGE /* * This deserves explanation * If the bridge is _on_, then the following check * must not be done because occasionally the bridge * gets packets that are local but have the ethernet * address of one of the other interfaces. * * But if the bridge is off, then we have to drop * stuff that came in just via bpfilter. */ if (!do_bridge)#endif /* Accept only our packets, broadcasts and multicasts */ if( (eh->ether_dhost[0] & 1) == 0 && bcmp(eh->ether_dhost,sc->sc_macaddr,ETHER_ADDR_LEN)){ m_freem(m); continue; }#endif /* Second mbuf holds packet ifself */ m->m_pkthdr.len = m->m_len = len - sizeof(struct ether_header); m->m_data += sizeof( struct ether_header ); /* Give mbuf to OS */ ether_input(&sc->sc_if, eh, m); /* Successfuly received frame */ sc->sc_if.if_ipackets++; } return;}/* * Synopsis: Do last phase of transmission. I.e. if desc is * transmitted, decrease pending_txs counter, free mbuf contained * packet, switch to next descriptor and repeat until no packets * are pending or descriptor is not transmitted yet. */static __inline voidepic_tx_done __P(( register epic_softc_t *sc )){ struct epic_tx_buffer *buf; struct epic_tx_desc *desc; u_int16_t status; while( sc->pending_txs > 0 ){ buf = sc->tx_buffer + sc->dirty_tx; desc = sc->tx_desc + sc->dirty_tx; status = desc->status; /* If packet is not transmitted, thou followed */ /* packets are not transmitted too */ if( status & 0x8000 ) break; /* Packet is transmitted. Switch to next and */ /* free mbuf */ sc->pending_txs--; sc->dirty_tx = (sc->dirty_tx + 1) & TX_RING_MASK; m_freem( buf->mbuf ); buf->mbuf = NULL; /* Check for errors and collisions */ if( status & 0x0001 ) sc->sc_if.if_opackets++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -