if_fxp.c

来自「RTEMS (Real-Time Executive for Multiproc」· C语言 代码 · 共 2,315 行 · 第 1/5 页

C
2,315
字号
	DBGLVL_PRINTK(5,"fxp_init: initialize TxCB list\n");	txp = sc->cbl_base;	bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXCB);	for (i = 0; i < FXP_NTXCB; i++) {		txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;		txp[i].cb_command = FXP_CB_COMMAND_NOP;		txp[i].link_addr =		    vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status);		if (sc->flags & FXP_FLAG_EXT_TXCB)			txp[i].tbd_array_addr = vtophys(&txp[i].tbd[2]);		else			txp[i].tbd_array_addr = vtophys(&txp[i].tbd[0]);		txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK];	}	/*	 * Set the suspend flag on the first TxCB and start the control	 * unit. It will execute the NOP and then suspend.	 */	DBGLVL_PRINTK(5,"fxp_init: setup suspend flag\n");	txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;	sc->cbl_first = sc->cbl_last = txp;	sc->tx_queued = 1;	fxp_scb_wait(sc);	fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START);	/*	 * Initialize receiver buffer area - RFA.	 */	DBGLVL_PRINTK(5,"fxp_init: initialize RFA\n");	fxp_scb_wait(sc);	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,	    vtophys(sc->rfa_headm->m_ext.ext_buf) + RFA_ALIGNMENT_FUDGE);	fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_START);#ifdef NOTUSED	/*	 * Set current media.	 */	if (sc->miibus != NULL)		mii_mediachg(device_get_softc(sc->miibus));#endif	ifp->if_flags |= IFF_RUNNING;	ifp->if_flags &= ~IFF_OACTIVE;	if (sc->daemonTid == 0) {		/*		 * Start driver task		 */		sc->daemonTid = rtems_bsdnet_newproc ("FXPd", 4096, fxp_daemon, sc);	}	/*	 * Enable interrupts.	 */	CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0);	splx(s);	/*	 * Start stats updater.	 */	sc->stat_ch = fxp_timeout_running;	DBGLVL_PRINTK(2,"fxp_init: stats updater timeout called with hz=%d\n", hz);	timeout(fxp_tick, sc, hz);	DBGLVL_PRINTK(2,"fxp_init finished\n");}#ifdef NOTUSEDstatic intfxp_serial_ifmedia_upd(struct ifnet *ifp){	return (0);}static voidfxp_serial_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr){	ifmr->ifm_active = IFM_ETHER|IFM_MANUAL;}/* * Change media according to request. */static intfxp_ifmedia_upd(struct ifnet *ifp){	struct fxp_softc *sc = ifp->if_softc;	struct mii_data *mii;	mii = device_get_softc(sc->miibus);	mii_mediachg(mii);	return (0);}/* * Notify the world which media we're using. */static voidfxp_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr){	struct fxp_softc *sc = ifp->if_softc;	struct mii_data *mii;	mii = device_get_softc(sc->miibus);	mii_pollstat(mii);	ifmr->ifm_active = mii->mii_media_active;	ifmr->ifm_status = mii->mii_media_status;	if (ifmr->ifm_status & IFM_10_T && sc->flags & FXP_FLAG_CU_RESUME_BUG)		sc->cu_resume_bug = 1;	else		sc->cu_resume_bug = 0;}#endif/* * Add a buffer to the end of the RFA buffer list. * Return 0 if successful, 1 for failure. A failure results in * adding the 'oldm' (if non-NULL) on to the end of the list - * tossing out its old contents and recycling it. * The RFA struct is stuck at the beginning of mbuf cluster and the * data pointer is fixed up to point just past it. */static intfxp_add_rfabuf(struct fxp_softc *sc, struct mbuf *oldm){	u_int32_t v;	struct mbuf *m;	struct fxp_rfa *rfa, *p_rfa;	DBGLVL_PRINTK(4,"fxp_add_rfabuf called\n");	MGETHDR(m, M_DONTWAIT, MT_DATA);	if (m != NULL) {		MCLGET(m, M_DONTWAIT);		if ((m->m_flags & M_EXT) == 0) {			m_freem(m);			if (oldm == NULL)				return 1;			m = oldm;			m->m_data = m->m_ext.ext_buf;		}	} else {		if (oldm == NULL)			return 1;		m = oldm;		m->m_data = m->m_ext.ext_buf;	}	/*	 * Move the data pointer up so that the incoming data packet	 * will be 32-bit aligned.	 */	m->m_data += RFA_ALIGNMENT_FUDGE;	/*	 * Get a pointer to the base of the mbuf cluster and move	 * data start past it.	 */	rfa = mtod(m, struct fxp_rfa *);	m->m_data += sizeof(struct fxp_rfa);	rfa->size = (u_int16_t)(MCLBYTES - sizeof(struct fxp_rfa) - RFA_ALIGNMENT_FUDGE);	/*	 * Initialize the rest of the RFA.  Note that since the RFA	 * is misaligned, we cannot store values directly.  Instead,	 * we use an optimized, inline copy.	 */	rfa->rfa_status = 0;	rfa->rfa_control = FXP_RFA_CONTROL_EL;	rfa->actual_size = 0;	v = -1;	fxp_lwcopy(&v, (volatile u_int32_t *) rfa->link_addr);	fxp_lwcopy(&v, (volatile u_int32_t *) rfa->rbd_addr);	/*	 * If there are other buffers already on the list, attach this	 * one to the end by fixing up the tail to point to this one.	 */	if (sc->rfa_headm != NULL) {		p_rfa = (struct fxp_rfa *) (sc->rfa_tailm->m_ext.ext_buf +		    RFA_ALIGNMENT_FUDGE);		sc->rfa_tailm->m_next = m;		v = vtophys(rfa);		fxp_lwcopy(&v, (volatile u_int32_t *) p_rfa->link_addr);		p_rfa->rfa_control = 0;	} else {		sc->rfa_headm = m;	}	sc->rfa_tailm = m;	return (m == oldm);}#ifdef NOTUSEDstatic volatile intfxp_miibus_readreg(device_t dev, int phy, int reg){	struct fxp_softc *sc = device_get_softc(dev);	int count = 10000;	int value;	CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,	    (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21));	while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0	    && count--)		DELAY(10);	if (count <= 0)		device_printf(dev, "fxp_miibus_readreg: timed out\n");	return (value & 0xffff);}static voidfxp_miibus_writereg(device_t dev, int phy, int reg, int value){	struct fxp_softc *sc = device_get_softc(dev);	int count = 10000;	CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,	    (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) |	    (value & 0xffff));	while ((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 &&	    count--)		DELAY(10);	if (count <= 0)		device_printf(dev, "fxp_miibus_writereg: timed out\n");}#endifstatic intfxp_ioctl(struct ifnet *ifp, int command, caddr_t data){	struct fxp_softc *sc = ifp->if_softc;#ifdef NOTUSED	struct ifreq *ifr = (struct ifreq *)data;	struct mii_data *mii;#endif	int s, error = 0;	DBGLVL_PRINTK(2,"fxp_ioctl called\n");	s = splimp();	switch (command) {	case SIOCSIFADDR:	case SIOCGIFADDR:	case SIOCSIFMTU:		error = ether_ioctl(ifp, command, data);		break;	case SIOCSIFFLAGS:		if (ifp->if_flags & IFF_ALLMULTI)			sc->flags |= FXP_FLAG_ALL_MCAST;		else			sc->flags &= ~FXP_FLAG_ALL_MCAST;		/*		 * If interface is marked up and not running, then start it.		 * If it is marked down and running, stop it.		 * XXX If it's up then re-initialize it. This is so flags		 * such as IFF_PROMISC are handled.		 */		if (ifp->if_flags & IFF_UP) {			fxp_init(sc);		} else {			if (ifp->if_flags & IFF_RUNNING)				fxp_stop(sc);		}		break;	case SIOCADDMULTI:	case SIOCDELMULTI:		if (ifp->if_flags & IFF_ALLMULTI)			sc->flags |= FXP_FLAG_ALL_MCAST;		else			sc->flags &= ~FXP_FLAG_ALL_MCAST;		/*		 * Multicast list has changed; set the hardware filter		 * accordingly.		 */		if ((sc->flags & FXP_FLAG_ALL_MCAST) == 0)			fxp_mc_setup(sc);		/*		 * fxp_mc_setup() can set FXP_FLAG_ALL_MCAST, so check it		 * again rather than else {}.		 */		if (sc->flags & FXP_FLAG_ALL_MCAST)			fxp_init(sc);		error = 0;		break;#ifdef NOTUSED	case SIOCSIFMEDIA:	case SIOCGIFMEDIA:		if (sc->miibus != NULL) {			mii = device_get_softc(sc->miibus);                        error = ifmedia_ioctl(ifp, ifr,                            &mii->mii_media, command);		} else {                        error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);		}		break;#endif    case SIO_RTEMS_SHOW_STATS:        fxp_stats(sc);        break;	default:		error = EINVAL;	}	splx(s);	return (error);}/* * Program the multicast filter. * * We have an artificial restriction that the multicast setup command * must be the first command in the chain, so we take steps to ensure * this. By requiring this, it allows us to keep up the performance of * the pre-initialized command ring (esp. link pointers) by not actually * inserting the mcsetup command in the ring - i.e. its link pointer * points to the TxCB ring, but the mcsetup descriptor itself is not part * of it. We then can do 'CU_START' on the mcsetup descriptor and have it * lead into the regular TxCB ring when it completes. * * This function must be called at splimp. */static voidfxp_mc_setup(struct fxp_softc *sc){	struct fxp_cb_mcs *mcsp = sc->mcsp;	struct ifnet *ifp = &sc->sc_if;#ifdef NOTUSED	struct ifmultiaddr *ifma;#endif	int nmcasts;	int count;	DBGLVL_PRINTK(2,"fxp_mc_setup called\n");	/*	 * If there are queued commands, we must wait until they are all	 * completed. If we are already waiting, then add a NOP command	 * with interrupt option so that we're notified when all commands	 * have been completed - fxp_start() ensures that no additional	 * TX commands will be added when need_mcsetup is true.	 */	if (sc->tx_queued) {		struct fxp_cb_tx *txp;		/*		 * need_mcsetup will be true if we are already waiting for the		 * NOP command to be completed (see below). In this case, bail.		 */		if (sc->need_mcsetup)			return;		sc->need_mcsetup = 1;		/*		 * Add a NOP command with interrupt so that we are notified when all		 * TX commands have been processed.		 */		txp = sc->cbl_last->next;		txp->mb_head = NULL;		txp->cb_status = 0;		txp->cb_command = FXP_CB_COMMAND_NOP |		    FXP_CB_COMMAND_S | FXP_CB_COMMAND_I;		/*		 * Advance the end of list forward.		 */		sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;		sc->cbl_last = txp;		sc->tx_queued++;		/*		 * Issue a resume in case the CU has just suspended.		 */		fxp_scb_wait(sc);		fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_RESUME);		/*		 * Set a 5 second timer just in case we don't hear from the		 * card again.		 */		ifp->if_timer = 5;		return;	}	sc->need_mcsetup = 0;	/*	 * Initialize multicast setup descriptor.	 */	mcsp->next = sc->cbl_base;	mcsp->mb_head = NULL;	mcsp->cb_status = 0;	mcsp->cb_command = FXP_CB_COMMAND_MCAS |	    FXP_CB_COMMAND_S | FXP_CB_COMMAND_I;	mcsp->link_addr = vtophys(&sc->cbl_base->cb_status);	nmcasts = 0;#ifdef NOTUSED /* FIXME: Multicast not supported? */	if ((sc->flags & FXP_FLAG_ALL_MCAST) == 0) {#if __FreeBSD_version < 500000		LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {#else		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {#endif			if (ifma->ifma_addr->sa_family != AF_LINK)				continue;			if (nmcasts >= MAXMCADDR) {				sc->flags |= FXP_FLAG_ALL_MCAST;				nmcasts = 0;				break;			}			bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),			    (void *)(uintptr_t)(volatile void *)				&sc->mcsp->mc_addr[nmcasts][0], 6);			nmcasts++;		}	}#endif	mcsp->mc_cnt = nmcasts * 6;	sc->cbl_first = sc->cbl_last = (struct fxp_cb_tx *) mcsp;	sc->tx_queued = 1;	/*	 * Wait until command unit is not active. This should never	 * be the case when nothing is queued, but make sure anyway.	 */	count = 100;	while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==	    FXP_SCB_CUS_ACTIVE && --count)		DELAY(10);	if (count == 0) {		device_printf(sc->dev, "command queue timeout\n");		return;	}	/*	 * Start the multicast setup command.	 */	fxp_scb_wait(sc);	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&mcsp->cb_status));	fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START);	ifp->if_timer = 2;	return;	}#endif /* defined(__i386__) */

⌨️ 快捷键说明

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