if_vr.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,963 行 · 第 1/4 页

C
1,963
字号
	}	sc->vr_bhandle = vbase;	sc->vr_btag = I386_BUS_SPACE_MEM;#endif	/* Allocate interrupt */	if (!pci_map_int(config_id, vr_intr, sc, &net_imask)) {		printf("vr%d: couldn't map interrupt\n", unit);		goto fail;	}	/* Reset the adapter. */	vr_reset(sc);	/*	 * Get station address. The way the Rhine chips work,	 * you're not allowed to directly access the EEPROM once	 * they've been programmed a special way. Consequently,	 * we need to read the node address from the PAR0 and PAR1	 * registers.	 */	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);	DELAY(200);	for (i = 0; i < ETHER_ADDR_LEN; i++)		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);	/*	 * A Rhine chip was detected. Inform the world.	 */	printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":");	sc->vr_unit = unit;	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);	sc->vr_ldata_ptr = malloc(sizeof(struct vr_list_data) + 8,				M_DEVBUF, M_NOWAIT);	if (sc->vr_ldata_ptr == NULL) {		free(sc, M_DEVBUF);		printf("vr%d: no memory for list buffers!\n", unit);		return;	}	sc->vr_ldata = (struct vr_list_data *)sc->vr_ldata_ptr;	round = (unsigned int)sc->vr_ldata_ptr & 0xF;	roundptr = sc->vr_ldata_ptr;	for (i = 0; i < 8; i++) {		if (round % 8) {			round++;			roundptr++;		} else			break;	}	sc->vr_ldata = (struct vr_list_data *)roundptr;	bzero(sc->vr_ldata, sizeof(struct vr_list_data));	ifp = &sc->arpcom.ac_if;	ifp->if_softc = sc;	ifp->if_unit = unit;	ifp->if_name = "vr";	ifp->if_mtu = ETHERMTU;	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;	ifp->if_ioctl = vr_ioctl;	ifp->if_output = ether_output;	ifp->if_start = vr_start;	ifp->if_watchdog = vr_watchdog;	ifp->if_init = vr_init;	ifp->if_baudrate = 10000000;	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;	if (bootverbose)		printf("vr%d: probing for a PHY\n", sc->vr_unit);	for (i = VR_PHYADDR_MIN; i < VR_PHYADDR_MAX + 1; i++) {		if (bootverbose)			printf("vr%d: checking address: %d\n",						sc->vr_unit, i);		sc->vr_phy_addr = i;		vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);		DELAY(500);		while(vr_phy_readreg(sc, PHY_BMCR)				& PHY_BMCR_RESET);		if ((phy_sts = vr_phy_readreg(sc, PHY_BMSR)))			break;	}	if (phy_sts) {		phy_vid = vr_phy_readreg(sc, PHY_VENID);		phy_did = vr_phy_readreg(sc, PHY_DEVID);		if (bootverbose)			printf("vr%d: found PHY at address %d, ",					sc->vr_unit, sc->vr_phy_addr);		if (bootverbose)			printf("vendor id: %x device id: %x\n",				phy_vid, phy_did);		p = vr_phys;		while(p->vr_vid) {			if (phy_vid == p->vr_vid &&				(phy_did | 0x000F) == p->vr_did) {				sc->vr_pinfo = p;				break;			}			p++;		}		if (sc->vr_pinfo == NULL)			sc->vr_pinfo = &vr_phys[PHY_UNKNOWN];		if (bootverbose)			printf("vr%d: PHY type: %s\n",				sc->vr_unit, sc->vr_pinfo->vr_name);	} else {		printf("vr%d: MII without any phy!\n", sc->vr_unit);		goto fail;	}	/*	 * Do ifmedia setup.	 */	ifmedia_init(&sc->ifmedia, 0, vr_ifmedia_upd, vr_ifmedia_sts);	vr_getmode_mii(sc);	vr_autoneg_mii(sc, VR_FLAG_FORCEDELAY, 1);	media = sc->ifmedia.ifm_media;	vr_stop(sc);	ifmedia_set(&sc->ifmedia, media);	/*	 * Call MI attach routines.	 */	if_attach(ifp);	ether_ifattach(ifp);#if NBPFILTER > 0	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));#endif	at_shutdown(vr_shutdown, sc, SHUTDOWN_POST_SYNC);fail:	splx(s);	return;}/* * Initialize the transmit descriptors. */static int vr_list_tx_init(sc)	struct vr_softc		*sc;{	struct vr_chain_data	*cd;	struct vr_list_data	*ld;	int			i;	cd = &sc->vr_cdata;	ld = sc->vr_ldata;	for (i = 0; i < VR_TX_LIST_CNT; i++) {		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];		if (i == (VR_TX_LIST_CNT - 1))			cd->vr_tx_chain[i].vr_nextdesc = 				&cd->vr_tx_chain[0];		else			cd->vr_tx_chain[i].vr_nextdesc =				&cd->vr_tx_chain[i + 1];	}	cd->vr_tx_free = &cd->vr_tx_chain[0];	cd->vr_tx_tail = cd->vr_tx_head = NULL;	return(0);}/* * Initialize the RX descriptors and allocate mbufs for them. Note that * we arrange the descriptors in a closed ring, so that the last descriptor * points back to the first. */static int vr_list_rx_init(sc)	struct vr_softc		*sc;{	struct vr_chain_data	*cd;	struct vr_list_data	*ld;	int			i;	cd = &sc->vr_cdata;	ld = sc->vr_ldata;	for (i = 0; i < VR_RX_LIST_CNT; i++) {		cd->vr_rx_chain[i].vr_ptr =			(struct vr_desc *)&ld->vr_rx_list[i];		if (vr_newbuf(sc, &cd->vr_rx_chain[i]) == ENOBUFS)			return(ENOBUFS);		if (i == (VR_RX_LIST_CNT - 1)) {			cd->vr_rx_chain[i].vr_nextdesc =					&cd->vr_rx_chain[0];			ld->vr_rx_list[i].vr_next =					vtophys(&ld->vr_rx_list[0]);		} else {			cd->vr_rx_chain[i].vr_nextdesc =					&cd->vr_rx_chain[i + 1];			ld->vr_rx_list[i].vr_next =					vtophys(&ld->vr_rx_list[i + 1]);		}	}	cd->vr_rx_head = &cd->vr_rx_chain[0];	return(0);}/* * Initialize an RX descriptor and attach an MBUF cluster. * Note: the length fields are only 11 bits wide, which means the * largest size we can specify is 2047. This is important because * MCLBYTES is 2048, so we have to subtract one otherwise we'll * overflow the field and make a mess. */static int vr_newbuf(sc, c)	struct vr_softc		*sc;	struct vr_chain_onefrag	*c;{	struct mbuf		*m_new = NULL;	MGETHDR(m_new, M_DONTWAIT, MT_DATA);	if (m_new == NULL) {		printf("vr%d: no memory for rx list -- packet dropped!\n",								sc->vr_unit);		return(ENOBUFS);	}	MCLGET(m_new, M_DONTWAIT);	if (!(m_new->m_flags & M_EXT)) {		printf("vr%d: no memory for rx list -- packet dropped!\n",								sc->vr_unit);		m_freem(m_new);		return(ENOBUFS);	}	c->vr_mbuf = m_new;	c->vr_ptr->vr_status = VR_RXSTAT;	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;	return(0);}/* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */static void vr_rxeof(sc)	struct vr_softc		*sc;{        struct ether_header	*eh;        struct mbuf		*m;        struct ifnet		*ifp;	struct vr_chain_onefrag	*cur_rx;	int			total_len = 0;	u_int32_t		rxstat;	ifp = &sc->arpcom.ac_if;	while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &							VR_RXSTAT_OWN)) {		cur_rx = sc->vr_cdata.vr_rx_head;		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;		/*		 * If an error occurs, update stats, clear the		 * status word and leave the mbuf cluster in place:		 * it should simply get re-used next time this descriptor	 	 * comes up in the ring.		 */		if (rxstat & VR_RXSTAT_RXERR) {			ifp->if_ierrors++;			printf("vr%d: rx error: ", sc->vr_unit);			switch(rxstat & 0x000000FF) {			case VR_RXSTAT_CRCERR:				printf("crc error\n");				break;			case VR_RXSTAT_FRAMEALIGNERR:				printf("frame alignment error\n");				break;			case VR_RXSTAT_FIFOOFLOW:				printf("FIFO overflow\n");				break;			case VR_RXSTAT_GIANT:				printf("received giant packet\n");				break;			case VR_RXSTAT_RUNT:				printf("received runt packet\n");				break;			case VR_RXSTAT_BUSERR:				printf("system bus error\n");				break;			case VR_RXSTAT_BUFFERR:				printf("rx buffer error\n");				break;			default:				printf("unknown rx error\n");				break;			}			cur_rx->vr_ptr->vr_status = VR_RXSTAT;			cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN;			continue;		}		/* No errors; receive the packet. */			m = cur_rx->vr_mbuf;		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);		/*		 * XXX The VIA Rhine chip includes the CRC with every		 * received frame, and there's no way to turn this		 * behavior off (at least, I can't find anything in	 	 * the manual that explains how to do it) so we have		 * to trim off the CRC manually.		 */		total_len -= ETHER_CRC_LEN;		/*		 * Try to conjure up a new mbuf cluster. If that		 * fails, it means we have an out of memory condition and		 * should leave the buffer in place and continue. This will		 * result in a lost packet, but there's little else we		 * can do in this situation.		 */		if (vr_newbuf(sc, cur_rx) == ENOBUFS) {			ifp->if_ierrors++;			cur_rx->vr_ptr->vr_status = VR_RXSTAT;			cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN;			continue;		}		ifp->if_ipackets++;		eh = mtod(m, struct ether_header *);		m->m_pkthdr.rcvif = ifp;		m->m_pkthdr.len = m->m_len = total_len;#if NBPFILTER > 0		/*		 * Handle BPF listeners. Let the BPF user see the packet, but		 * don't pass it up to the ether_input() layer unless it's		 * a broadcast packet, multicast packet, matches our ethernet		 * address or the interface is in promiscuous mode.		 */		if (ifp->if_bpf) {			bpf_mtap(ifp, m);			if (ifp->if_flags & IFF_PROMISC &&				(bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,						ETHER_ADDR_LEN) &&					(eh->ether_dhost[0] & 1) == 0)) {				m_freem(m);				continue;			}		}#endif		/* Remove header from mbuf and pass it on. */		m_adj(m, sizeof(struct ether_header));		ether_input(ifp, eh, m);	}	return;}void vr_rxeoc(sc)	struct vr_softc		*sc;{	vr_rxeof(sc);	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);	return;}/* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */static void vr_txeof(sc)	struct vr_softc		*sc;{	struct vr_chain		*cur_tx;	struct ifnet		*ifp;	register struct mbuf	*n;	ifp = &sc->arpcom.ac_if;	/* Clear the timeout timer. */	ifp->if_timer = 0;	/* Sanity check. */	if (sc->vr_cdata.vr_tx_head == NULL)		return;	/*	 * Go through our tx list and free mbufs for those	 * frames that have been transmitted.	 */	while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) {		u_int32_t		txstat;		cur_tx = sc->vr_cdata.vr_tx_head;		txstat = cur_tx->vr_ptr->vr_status;		if (txstat & VR_TXSTAT_OWN)			break;		if (txstat & VR_TXSTAT_ERRSUM) {			ifp->if_oerrors++;			if (txstat & VR_TXSTAT_DEFER)				ifp->if_collisions++;			if (txstat & VR_TXSTAT_LATECOLL)				ifp->if_collisions++;		}		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;		ifp->if_opackets++;        	MFREE(cur_tx->vr_mbuf, n);		cur_tx->vr_mbuf = NULL;		if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) {			sc->vr_cdata.vr_tx_head = NULL;			sc->vr_cdata.vr_tx_tail = NULL;			break;		}		sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc;	}	return;}/* * TX 'end of channel' interrupt handler. */static void vr_txeoc(sc)	struct vr_softc		*sc;{	struct ifnet		*ifp;	ifp = &sc->arpcom.ac_if;	ifp->if_timer = 0;	if (sc->vr_cdata.vr_tx_head == NULL) {		ifp->if_flags &= ~IFF_OACTIVE;		sc->vr_cdata.vr_tx_tail = NULL;		if (sc->vr_want_auto)			vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1);	}	return;}static void vr_intr(arg)	void			*arg;{	struct vr_softc		*sc;	struct ifnet		*ifp;	u_int16_t		status;	sc = arg;	ifp = &sc->arpcom.ac_if;	/* Supress unwanted interrupts. */	if (!(ifp->if_flags & IFF_UP)) {		vr_stop(sc);		return;	}	/* Disable interrupts. */	CSR_WRITE_2(sc, VR_IMR, 0x0000);	for (;;) {		status = CSR_READ_2(sc, VR_ISR);		if (status)			CSR_WRITE_2(sc, VR_ISR, status);		if ((status & VR_INTRS) == 0)			break;		if (status & VR_ISR_RX_OK)			vr_rxeof(sc);		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) ||		    (status & VR_ISR_RX_DROPPED)) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?