if_fxp.c

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

C
1,926
字号
		break;	default:		return (EINVAL);	}	return (0);}#else /* __FreeBSD__ */static u_long fxp_count;static const char *fxp_probe		__P((pcici_t, pcidi_t));static void fxp_attach		__P((pcici_t, int));static void fxp_shutdown	__P((int, void *));static struct pci_device fxp_device = {	"fxp",	fxp_probe,	fxp_attach,	&fxp_count,	NULL};DATA_SET(pcidevice_set, fxp_device);/* * Return identification string if this is device is ours. */static const char *fxp_probe(config_id, device_id)	pcici_t config_id;	pcidi_t device_id;{	if (((device_id & 0xffff) == FXP_VENDORID_INTEL) &&	    ((device_id >> 16) & 0xffff) == FXP_DEVICEID_i82557)		return ("Intel EtherExpress Pro 10/100B Ethernet");	return NULL;}static voidfxp_attach(config_id, unit)	pcici_t config_id;	int unit;{	struct fxp_softc *sc;	vm_offset_t pbase;	struct ifnet *ifp;	int s;	u_long val;	sc = malloc(sizeof(struct fxp_softc), M_DEVBUF, M_NOWAIT);	if (sc == NULL)		return;	bzero(sc, sizeof(struct fxp_softc));	callout_handle_init(&sc->stat_ch);	s = splimp();	/*	 * Enable bus mastering.	 */	val = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);	val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);	pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, val);	/*	 * Map control/status registers.	 */	if (!pci_map_mem(config_id, FXP_PCI_MMBA,	    (vm_offset_t *)&sc->csr, &pbase)) {		printf("fxp%d: couldn't map memory\n", unit);		goto fail;	}	/*	 * Allocate our interrupt.	 */	if (!pci_map_int(config_id, fxp_intr, sc, &net_imask)) {		printf("fxp%d: couldn't map interrupt\n", unit);		goto fail;	}	/* Do generic parts of attach. */	if (fxp_attach_common(sc, sc->arpcom.ac_enaddr)) {		/* Failed! */		(void) pci_unmap_int(config_id);		goto fail;	}	printf("fxp%d: Ethernet address %6D%s\n", unit,	    sc->arpcom.ac_enaddr, ":", sc->phy_10Mbps_only ? ", 10Mbps" : "");	ifp = &sc->arpcom.ac_if;	ifp->if_unit = unit;	ifp->if_name = "fxp";	ifp->if_output = ether_output;	ifp->if_baudrate = 100000000;	ifp->if_init = fxp_init;	ifp->if_softc = sc;	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;	ifp->if_ioctl = fxp_ioctl;	ifp->if_start = fxp_start;	ifp->if_watchdog = fxp_watchdog;	/*	 * Attach the interface.	 */	if_attach(ifp);	/*	 * Let the system queue as many packets as we have available	 * TX descriptors.	 */	ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1;	ether_ifattach(ifp);#if NBPFILTER > 0	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));#endif	/*	 * Add shutdown hook so that DMA is disabled prior to reboot. Not	 * doing do could allow DMA to corrupt kernel memory during the	 * reboot before the driver initializes.	 */	at_shutdown(fxp_shutdown, sc, SHUTDOWN_POST_SYNC);	splx(s);	return; fail:	free(sc, M_DEVBUF);	splx(s);}/* * Device shutdown routine. Called at system shutdown after sync. The * main purpose of this routine is to shut off receiver DMA so that * kernel memory doesn't get clobbered during warmboot. */static voidfxp_shutdown(howto, sc)	int howto;	void *sc;{	fxp_stop((struct fxp_softc *) sc);}#endif /* __NetBSD__ *//************************************************************* * End of operating system-specific autoconfiguration glue *************************************************************//* * Do generic parts of attach. */static intfxp_attach_common(sc, enaddr)	struct fxp_softc *sc;	u_int8_t *enaddr;{	u_int16_t data;	int i, nmedia, defmedia;	const int *media;	/*	 * Reset to a stable state.	 */	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);	DELAY(10);	sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB,	    M_DEVBUF, M_NOWAIT);	if (sc->cbl_base == NULL)		goto fail;	bzero(sc->cbl_base, sizeof(struct fxp_cb_tx) * FXP_NTXCB);	sc->fxp_stats = malloc(sizeof(struct fxp_stats), M_DEVBUF, M_NOWAIT);	if (sc->fxp_stats == NULL)		goto fail;	bzero(sc->fxp_stats, sizeof(struct fxp_stats));	sc->mcsp = malloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_NOWAIT);	if (sc->mcsp == NULL)		goto fail;	/*	 * Pre-allocate our receive buffers.	 */	for (i = 0; i < FXP_NRFABUFS; i++) {		if (fxp_add_rfabuf(sc, NULL) != 0) {			goto fail;		}	}	/*	 * Get info about the primary PHY	 */	fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1);	sc->phy_primary_addr = data & 0xff;	sc->phy_primary_device = (data >> 8) & 0x3f;	sc->phy_10Mbps_only = data >> 15;	/*	 * Read MAC address.	 */	fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3);	/*	 * Initialize the media structures.	 */	media = fxp_media_default;	nmedia = sizeof(fxp_media_default) / sizeof(fxp_media_default[0]);	defmedia = FXP_MEDIA_DEFAULT_DEFMEDIA;	for (i = 0; i < NFXPMEDIA; i++) {		if (sc->phy_primary_device == fxp_media[i].fsm_phy) {			media = fxp_media[i].fsm_media;			nmedia = fxp_media[i].fsm_nmedia;			defmedia = fxp_media[i].fsm_defmedia;		}	}	ifmedia_init(&sc->sc_media, 0, fxp_mediachange, fxp_mediastatus);	for (i = 0; i < nmedia; i++) {		if (IFM_SUBTYPE(media[i]) == IFM_100_TX && sc->phy_10Mbps_only)			continue;		ifmedia_add(&sc->sc_media, media[i], 0, NULL);	}	ifmedia_set(&sc->sc_media, defmedia);	return (0); fail:	printf(FXP_FORMAT ": Failed to malloc memory\n", FXP_ARGS(sc));	if (sc->cbl_base)		free(sc->cbl_base, M_DEVBUF);	if (sc->fxp_stats)		free(sc->fxp_stats, M_DEVBUF);	if (sc->mcsp)		free(sc->mcsp, M_DEVBUF);	/* frees entire chain */	if (sc->rfa_headm)		m_freem(sc->rfa_headm);	return (ENOMEM);}/* * Read from the serial EEPROM. Basically, you manually shift in * the read opcode (one bit at a time) and then shift in the address, * and then you shift out the data (all of this one bit at a time). * The word size is 16 bits, so you have to provide the address for * every 16 bits of data. */static voidfxp_read_eeprom(sc, data, offset, words)	struct fxp_softc *sc;	u_short *data;	int offset;	int words;{	u_int16_t reg;	int i, x;	for (i = 0; i < words; i++) {		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);		/*		 * Shift in read opcode.		 */		for (x = 3; x > 0; x--) {			if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {				reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;			} else {				reg = FXP_EEPROM_EECS;			}			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,			    reg | FXP_EEPROM_EESK);			DELAY(1);			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);			DELAY(1);		}		/*		 * Shift in address.		 */		for (x = 6; x > 0; x--) {			if ((i + offset) & (1 << (x - 1))) {				reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;			} else {				reg = FXP_EEPROM_EECS;			}			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,			    reg | FXP_EEPROM_EESK);			DELAY(1);			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);			DELAY(1);		}		reg = FXP_EEPROM_EECS;		data[i] = 0;		/*		 * Shift out data.		 */		for (x = 16; x > 0; x--) {			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,			    reg | FXP_EEPROM_EESK);			DELAY(1);			if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &			    FXP_EEPROM_EEDO)				data[i] |= (1 << (x - 1));			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);			DELAY(1);		}		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);		DELAY(1);	}}/* * Start packet transmission on the interface. */static voidfxp_start(ifp)	struct ifnet *ifp;{	struct fxp_softc *sc = ifp->if_softc;	struct fxp_cb_tx *txp;	/*	 * See if we need to suspend xmit until the multicast filter	 * has been reprogrammed (which can only be done at the head	 * of the command chain).	 */	if (sc->need_mcsetup)		return;	txp = NULL;	/*	 * We're finished if there is nothing more to add to the list or if	 * we're all filled up with buffers to transmit.	 * NOTE: One TxCB is reserved to guarantee that fxp_mc_setup() can add	 *       a NOP command when needed.	 */	while (ifp->if_snd.ifq_head != NULL && sc->tx_queued < FXP_NTXCB - 1) {		struct mbuf *m, *mb_head;		int segment;		/*		 * Grab a packet to transmit.		 */		IF_DEQUEUE(&ifp->if_snd, mb_head);		/*		 * Get pointer to next available tx desc.		 */		txp = sc->cbl_last->next;		/*		 * Go through each of the mbufs in the chain and initialize		 * the transmit buffer descriptors with the physical address		 * and size of the mbuf.		 */tbdinit:		for (m = mb_head, segment = 0; m != NULL; m = m->m_next) {			if (m->m_len != 0) {				if (segment == FXP_NTXSEG)					break;				txp->tbd[segment].tb_addr =				    vtophys(mtod(m, vm_offset_t));				txp->tbd[segment].tb_size = m->m_len;				segment++;			}		}		if (m != NULL) {			struct mbuf *mn;			/*			 * We ran out of segments. We have to recopy this mbuf			 * chain first. Bail out if we can't get the new buffers.			 */			MGETHDR(mn, M_DONTWAIT, MT_DATA);			if (mn == NULL) {				m_freem(mb_head);				break;			}			if (mb_head->m_pkthdr.len > MHLEN) {				MCLGET(mn, M_DONTWAIT);				if ((mn->m_flags & M_EXT) == 0) {					m_freem(mn);					m_freem(mb_head);					break;				}			}			m_copydata(mb_head, 0, mb_head->m_pkthdr.len,			    mtod(mn, caddr_t));			mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len;			m_freem(mb_head);			mb_head = mn;			goto tbdinit;		}		txp->tbd_number = segment;		txp->mb_head = mb_head;		txp->cb_status = 0;		if (sc->tx_queued != FXP_CXINT_THRESH - 1) {			txp->cb_command =			    FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S;		} else {			txp->cb_command =			    FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S | FXP_CB_COMMAND_I;			/*			 * Set a 5 second timer just in case we don't hear from the			 * card again.			 */			ifp->if_timer = 5;		}		txp->tx_threshold = tx_threshold;			/*		 * Advance the end of list forward.		 */		sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;		sc->cbl_last = txp;		/*		 * Advance the beginning of the list forward if there are		 * no other packets queued (when nothing is queued, cbl_first		 * sits on the last TxCB that was sent out).		 */		if (sc->tx_queued == 0)			sc->cbl_first = txp;		sc->tx_queued++;#if NBPFILTER > 0		/*		 * Pass packet to bpf if there is a listener.		 */		if (ifp->if_bpf)			bpf_mtap(FXP_BPFTAP_ARG(ifp), mb_head);#endif	}	/*	 * We're finished. If we added to the list, issue a RESUME to get DMA	 * going again if suspended.	 */	if (txp != NULL) {		fxp_scb_wait(sc);		CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);	}}/* * Process interface interrupts. */static FXP_INTR_TYPEfxp_intr(arg)	void *arg;{	struct fxp_softc *sc = arg;	struct ifnet *ifp = &sc->sc_if;	u_int8_t statack;#if defined(__NetBSD__)	int claimed = 0;#endif	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {#if defined(__NetBSD__)		claimed = 1;#endif		/*		 * First ACK all the interrupts in this pass.		 */		CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);		/*		 * Free any finished transmit mbuf chains.

⌨️ 快捷键说明

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