if_ax.c

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

C
2,242
字号
			command &= 0xFFFFFFFC;			pci_conf_write(config_id, AX_PCI_PWRMGMTCTRL, command);			/* Restore PCI config data. */			pci_conf_write(config_id, AX_PCI_LOIO, iobase);			pci_conf_write(config_id, AX_PCI_LOMEM, membase);			pci_conf_write(config_id, AX_PCI_INTLINE, irq);		}	}	/*	 * Map control/status registers.	 */	command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);	command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);	pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command);	command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);#ifdef AX_USEIOSPACE	if (!(command & PCIM_CMD_PORTEN)) {		printf("ax%d: failed to enable I/O ports!\n", unit);		free(sc, M_DEVBUF);		goto fail;	}	if (!pci_map_port(config_id, AX_PCI_LOIO,					(u_short *)&(sc->ax_bhandle))) {		printf ("ax%d: couldn't map ports\n", unit);		goto fail;        }#ifdef __i386__	sc->ax_btag = I386_BUS_SPACE_IO;#endif#ifdef __alpha__	sc->ax_btag = ALPHA_BUS_SPACE_IO;#endif#else	if (!(command & PCIM_CMD_MEMEN)) {		printf("ax%d: failed to enable memory mapping!\n", unit);		goto fail;	}	if (!pci_map_mem(config_id, AX_PCI_LOMEM, &vbase, &pbase)) {		printf ("ax%d: couldn't map memory\n", unit);		goto fail;	}#ifdef __i386__	sc->ax_btag = I386_BUS_SPACE_MEM;#endif#ifdef __alpha__	sc->ax_btag = ALPHA_BUS_SPACE_MEM;#endif	sc->ax_bhandle = vbase;#endif	/* Allocate interrupt */	if (!pci_map_int(config_id, ax_intr, sc, &net_imask)) {		printf("ax%d: couldn't map interrupt\n", unit);		goto fail;	}	/* Reset the adapter. */	ax_reset(sc);	/*	 * Get station address from the EEPROM.	 */	ax_read_eeprom(sc, (caddr_t)&eaddr, AX_EE_NODEADDR, 3, 0);	/*	 * An ASIX chip was detected. Inform the world.	 */	printf("ax%d: Ethernet address: %6D\n", unit, eaddr, ":");	sc->ax_unit = unit;	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);	sc->ax_ldata_ptr = malloc(sizeof(struct ax_list_data) + 8,				M_DEVBUF, M_NOWAIT);	if (sc->ax_ldata_ptr == NULL) {		free(sc, M_DEVBUF);		printf("ax%d: no memory for list buffers!\n", unit);		goto fail;	}	sc->ax_ldata = (struct ax_list_data *)sc->ax_ldata_ptr;	round = (unsigned int)sc->ax_ldata_ptr & 0xF;	roundptr = sc->ax_ldata_ptr;	for (i = 0; i < 8; i++) {		if (round % 8) {			round++;			roundptr++;		} else			break;	}	sc->ax_ldata = (struct ax_list_data *)roundptr;	bzero(sc->ax_ldata, sizeof(struct ax_list_data));	ifp = &sc->arpcom.ac_if;	ifp->if_softc = sc;	ifp->if_unit = unit;	ifp->if_name = "ax";	ifp->if_mtu = ETHERMTU;	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;	ifp->if_ioctl = ax_ioctl;	ifp->if_output = ether_output;	ifp->if_start = ax_start;	ifp->if_watchdog = ax_watchdog;	ifp->if_init = ax_init;	ifp->if_baudrate = 10000000;	ifp->if_snd.ifq_maxlen = AX_TX_LIST_CNT - 1;	if (bootverbose)		printf("ax%d: probing for a PHY\n", sc->ax_unit);	for (i = AX_PHYADDR_MIN; i < AX_PHYADDR_MAX + 1; i++) {		if (bootverbose)			printf("ax%d: checking address: %d\n",						sc->ax_unit, i);		sc->ax_phy_addr = i;		ax_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);		DELAY(500);		while(ax_phy_readreg(sc, PHY_BMCR)				& PHY_BMCR_RESET);		if ((phy_sts = ax_phy_readreg(sc, PHY_BMSR)))			break;	}	if (phy_sts) {		phy_vid = ax_phy_readreg(sc, PHY_VENID);		phy_did = ax_phy_readreg(sc, PHY_DEVID);		if (bootverbose)			printf("ax%d: found PHY at address %d, ",				sc->ax_unit, sc->ax_phy_addr);		if (bootverbose)			printf("vendor id: %x device id: %x\n",			phy_vid, phy_did);		p = ax_phys;		while(p->ax_vid) {			if (phy_vid == p->ax_vid &&				(phy_did | 0x000F) == p->ax_did) {				sc->ax_pinfo = p;				break;			}			p++;		}		if (sc->ax_pinfo == NULL)			sc->ax_pinfo = &ax_phys[PHY_UNKNOWN];		if (bootverbose)			printf("ax%d: PHY type: %s\n",				sc->ax_unit, sc->ax_pinfo->ax_name);	} else {#ifdef DIAGNOSTIC		printf("ax%d: MII without any phy!\n", sc->ax_unit);#endif	}	/*	 * Do ifmedia setup.	 */	ifmedia_init(&sc->ifmedia, 0, ax_ifmedia_upd, ax_ifmedia_sts);	if (sc->ax_pinfo != NULL) {		ax_getmode_mii(sc);		ax_autoneg_mii(sc, AX_FLAG_FORCEDELAY, 1);	} else {		ifmedia_add(&sc->ifmedia,			IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);		ifmedia_add(&sc->ifmedia,			IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);		ifmedia_add(&sc->ifmedia,			IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);		ifmedia_add(&sc->ifmedia,			IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);	}	media = sc->ifmedia.ifm_media;	ax_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(ax_shutdown, sc, SHUTDOWN_POST_SYNC);fail:	splx(s);	return;}/* * Initialize the transmit descriptors. */static int ax_list_tx_init(sc)	struct ax_softc		*sc;{	struct ax_chain_data	*cd;	struct ax_list_data	*ld;	int			i;	cd = &sc->ax_cdata;	ld = sc->ax_ldata;	for (i = 0; i < AX_TX_LIST_CNT; i++) {		cd->ax_tx_chain[i].ax_ptr = &ld->ax_tx_list[i];		if (i == (AX_TX_LIST_CNT - 1))			cd->ax_tx_chain[i].ax_nextdesc =				&cd->ax_tx_chain[0];		else			cd->ax_tx_chain[i].ax_nextdesc =				&cd->ax_tx_chain[i + 1];	}	cd->ax_tx_free = &cd->ax_tx_chain[0];	cd->ax_tx_tail = cd->ax_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 ax_list_rx_init(sc)	struct ax_softc		*sc;{	struct ax_chain_data	*cd;	struct ax_list_data	*ld;	int			i;	cd = &sc->ax_cdata;	ld = sc->ax_ldata;	for (i = 0; i < AX_RX_LIST_CNT; i++) {		cd->ax_rx_chain[i].ax_ptr =			(volatile struct ax_desc *)&ld->ax_rx_list[i];		if (ax_newbuf(sc, &cd->ax_rx_chain[i]) == ENOBUFS)			return(ENOBUFS);		if (i == (AX_RX_LIST_CNT - 1)) {			cd->ax_rx_chain[i].ax_nextdesc =						&cd->ax_rx_chain[0];			ld->ax_rx_list[i].ax_next =					vtophys(&ld->ax_rx_list[0]);		} else {			cd->ax_rx_chain[i].ax_nextdesc =						&cd->ax_rx_chain[i + 1];			ld->ax_rx_list[i].ax_next =					vtophys(&ld->ax_rx_list[i + 1]);		}	}	cd->ax_rx_head = &cd->ax_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 ax_newbuf(sc, c)	struct ax_softc		*sc;	struct ax_chain_onefrag	*c;{	struct mbuf		*m_new = NULL;	MGETHDR(m_new, M_DONTWAIT, MT_DATA);	if (m_new == NULL) {		printf("ax%d: no memory for rx list -- packet dropped!\n",								sc->ax_unit);		return(ENOBUFS);	}	MCLGET(m_new, M_DONTWAIT);	if (!(m_new->m_flags & M_EXT)) {		printf("ax%d: no memory for rx list -- packet dropped!\n",								sc->ax_unit);		m_freem(m_new);		return(ENOBUFS);	}	c->ax_mbuf = m_new;	c->ax_ptr->ax_status = AX_RXSTAT;	c->ax_ptr->ax_data = vtophys(mtod(m_new, caddr_t));	c->ax_ptr->ax_ctl = MCLBYTES - 1;	return(0);}/* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */static void ax_rxeof(sc)	struct ax_softc		*sc;{        struct ether_header	*eh;        struct mbuf		*m;        struct ifnet		*ifp;	struct ax_chain_onefrag	*cur_rx;	int			total_len = 0;	u_int32_t		rxstat;	ifp = &sc->arpcom.ac_if;	while(!((rxstat = sc->ax_cdata.ax_rx_head->ax_ptr->ax_status) &							AX_RXSTAT_OWN)) {#ifdef __alpha__		struct mbuf		*m0 = NULL;#endif		cur_rx = sc->ax_cdata.ax_rx_head;		sc->ax_cdata.ax_rx_head = cur_rx->ax_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 & AX_RXSTAT_RXERR) {			ifp->if_ierrors++;			if (rxstat & AX_RXSTAT_COLLSEEN)				ifp->if_collisions++;			cur_rx->ax_ptr->ax_status = AX_RXSTAT;			cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1);			continue;		}		/* No errors; receive the packet. */			m = cur_rx->ax_mbuf;		total_len = AX_RXBYTES(cur_rx->ax_ptr->ax_status);		total_len -= ETHER_CRC_LEN;#ifdef __alpha__		/*		 * 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 (ax_newbuf(sc, cur_rx) == ENOBUFS) {			ifp->if_ierrors++;			cur_rx->ax_ptr->ax_status = AX_RXSTAT;			cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1);			continue;		}		/*		 * Sadly, the ASIX chip doesn't decode the last few		 * bits of the RX DMA buffer address, so we have to		 * cheat in order to obtain proper payload alignment		 * on the alpha.		 */		MGETHDR(m0, M_DONTWAIT, MT_DATA);		if (m0 == NULL) {			ifp->if_ierrors++;			cur_rx->ax_ptr->ax_status = AX_RXSTAT;			cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1);			continue;		}		m0->m_data += 2;		if (total_len <= (MHLEN - 2)) {			bcopy(mtod(m, caddr_t), mtod(m0, caddr_t), total_len);				m_freem(m);			m = m0;			m->m_pkthdr.len = m->m_len = total_len;		} else {			bcopy(mtod(m, caddr_t), mtod(m0, caddr_t), (MHLEN - 2));			m->m_len = total_len - (MHLEN - 2);			m->m_data += (MHLEN - 2);			m0->m_next = m;			m0->m_len = (MHLEN - 2);			m = m0;			m->m_pkthdr.len = total_len;		}		m->m_pkthdr.rcvif = ifp;#else		if (total_len < MINCLSIZE) {			m = m_devget(mtod(cur_rx->ax_mbuf, char *),				total_len, 0, ifp, NULL);			cur_rx->ax_ptr->ax_status = AX_RXSTAT;			cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1);			if (m == NULL) {				ifp->if_ierrors++;				continue;			}		} else {			m = cur_rx->ax_mbuf;		/*		 * 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 (ax_newbuf(sc, cur_rx) == ENOBUFS) {				ifp->if_ierrors++;				cur_rx->ax_ptr->ax_status = AX_RXSTAT;				cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1);				continue;			}			m->m_pkthdr.rcvif = ifp;			m->m_pkthdr.len = m->m_len = total_len;		}#endif		ifp->if_ipackets++;		eh = mtod(m, struct ether_header *);#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 ax_rxeoc(sc)	struct ax_softc		*sc;{	ax_rxeof(sc);	AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_RX_ON);	CSR_WRITE_4(sc, AX_RXADDR, vtophys(sc->ax_cdata.ax_rx_head->ax_ptr));	AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_RX_ON);	CSR_WRITE_4(sc, AX_RXSTART, 0xFFFFFFFF);	return;}/* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */static void ax_txeof(sc)	struct ax_softc		*sc;{	struct ax_chain		*cur_tx;	struct ifnet		*ifp;	ifp = &sc->arpcom.ac_if;	/* Clear the timeout timer. */	ifp->if_timer = 0;	if (sc->ax_cdata.ax_tx_head == NULL)		return;	/*	 * Go through our tx list and free mbufs for those	 * frames that have been transmitted.	 */	while(sc->ax_cdata.ax_tx_head->ax_mbuf != NULL) {		u_int32_t		txstat;		cur_tx = sc->ax_cdata.ax_tx_head;		txstat = AX_TXSTATUS(cur_tx);		if (txstat & AX_TXSTAT_OWN)			break;		if (txstat & AX_TXSTAT_ERRSUM) {			ifp->if_oerrors++;			if (txstat & AX_TXSTAT_EXCESSCOLL)				ifp->if_collisions++;			if (txstat & AX_TXSTAT_LATECOLL)				ifp->if_collisions++;		}		ifp->if_collisions += (txstat & AX_TXSTAT_COLLCNT) >> 3;		ifp->if_opackets++;		m_freem(cur_tx->ax_mbuf);		cur_tx->ax_mbuf = NULL;		if (sc->ax_cdata.ax_tx_head == sc->ax_cdata.ax_tx_tail) {			sc->ax_cdata.ax_tx_head = NULL;			sc->ax_cdata.ax_tx_tail = NULL;			break;		}		sc->ax_cdata.ax_tx_head = cur_tx->ax_nextdesc;	}	return;}/* * TX 'end of channel' interrupt handler. */static void ax_txeoc(sc)	struct ax_softc		*sc;{	struct ifnet		*ifp;	ifp = &sc->arpcom.ac_if;	ifp->if_timer = 0;	if (sc->ax_cdata.ax_tx_head == NULL) {		ifp->if_flags &= ~IFF_OACTIVE;		sc->ax_cdata.ax_tx_tail = NULL;		if (sc->ax_want_auto)			ax_autoneg_mii(sc, AX_FLAG_DELAYTIMEO, 1);	}	return;}static void ax_intr(arg)	void			*arg;{	struct ax_softc		*sc;	struct ifnet		*ifp;	u_int32_t		status;	sc = arg;	ifp = &sc->arpcom.ac_if;	/* Supress unwanted interrupts */	if (!(ifp->if_flags & IFF_UP)) {		ax_stop(sc);		return;	}	/* Disable interrupts. */	CSR_WRITE_4(sc, AX_IMR, 0x00000000);	for (;;) {

⌨️ 快捷键说明

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