if_fxp.c

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

C
2,315
字号
		 */		if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) {			struct mbuf *m;			struct fxp_rfa *rfa;rcvloop:			m = sc->rfa_headm;			rfa = (struct fxp_rfa *)(m->m_ext.ext_buf +			    RFA_ALIGNMENT_FUDGE);			if (rfa->rfa_status & FXP_RFA_STATUS_C) {				/*				 * Remove first packet from the chain.				 */				sc->rfa_headm = m->m_next;				m->m_next = NULL;				/*				 * Add a new buffer to the receive chain.				 * If this fails, the old buffer is recycled				 * instead.				 */				if (fxp_add_rfabuf(sc, m) == 0) {					struct ether_header *eh;					int total_len;					total_len = rfa->actual_size &					    (MCLBYTES - 1);					if (total_len <					    sizeof(struct ether_header)) {						m_freem(m);						goto rcvloop;					}					/*					 * Drop the packet if it has CRC					 * errors.  This test is only needed					 * when doing 802.1q VLAN on the 82557					 * chip.					 */					if (rfa->rfa_status &					    FXP_RFA_STATUS_CRC) {						m_freem(m);						goto rcvloop;					}					m->m_pkthdr.rcvif = ifp;					m->m_pkthdr.len = m->m_len = total_len;					eh = mtod(m, struct ether_header *);					m->m_data +=					    sizeof(struct ether_header);					m->m_len -=					    sizeof(struct ether_header);					m->m_pkthdr.len = m->m_len;					ether_input(ifp, eh, m);				}				goto rcvloop;			}			if (statack & FXP_SCB_STATACK_RNR) {				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);			}		}	  }	  /*	   * reenable interrupts	   */	  rtems_interrupt_disable (level);	  CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL,0);	  rtems_interrupt_enable (level);	}}/* * Update packet in/out/collision statistics. The i82557 doesn't * allow you to access these counters without doing a fairly * expensive DMA to get _all_ of the statistics it maintains, so * we do this operation here only once per second. The statistics * counters in the kernel are updated from the previous dump-stats * DMA and then a new dump-stats DMA is started. The on-chip * counters are zeroed when the DMA completes. If we can't start * the DMA immediately, we don't wait - we just prepare to read * them again next time. */static voidfxp_tick(void *xsc){	struct fxp_softc *sc = xsc;	struct ifnet *ifp = &sc->sc_if;	struct fxp_stats *sp = sc->fxp_stats;	struct fxp_cb_tx *txp;	int s;	DBGLVL_PRINTK(4,"fxp_tick called\n");	ifp->if_opackets += sp->tx_good;	ifp->if_collisions += sp->tx_total_collisions;	if (sp->rx_good) {		ifp->if_ipackets += sp->rx_good;		sc->rx_idle_secs = 0;	} else {		/*		 * Receiver's been idle for another second.		 */		sc->rx_idle_secs++;	}	ifp->if_ierrors +=	    sp->rx_crc_errors +	    sp->rx_alignment_errors +	    sp->rx_rnr_errors +	    sp->rx_overrun_errors;	/*	 * If any transmit underruns occured, bump up the transmit	 * threshold by another 512 bytes (64 * 8).	 */	if (sp->tx_underruns) {		ifp->if_oerrors += sp->tx_underruns;		if (tx_threshold < 192)			tx_threshold += 64;	}	s = splimp();	/*	 * Release any xmit buffers that have completed DMA. This isn't	 * strictly necessary to do here, but it's advantagous for mbufs	 * with external storage to be released in a timely manner rather	 * than being defered for a potentially long time. This limits	 * the delay to a maximum of one second.	 */ 	for (txp = sc->cbl_first; sc->tx_queued &&	    (txp->cb_status & FXP_CB_STATUS_C) != 0;	    txp = txp->next) {		if (txp->mb_head != NULL) {			m_freem(txp->mb_head);			txp->mb_head = NULL;		}		sc->tx_queued--;	}	sc->cbl_first = txp;	/*	 * If we haven't received any packets in FXP_MAC_RX_IDLE seconds,	 * then assume the receiver has locked up and attempt to clear	 * the condition by reprogramming the multicast filter. This is	 * a work-around for a bug in the 82557 where the receiver locks	 * up if it gets certain types of garbage in the syncronization	 * bits prior to the packet header. This bug is supposed to only	 * occur in 10Mbps mode, but has been seen to occur in 100Mbps	 * mode as well (perhaps due to a 10/100 speed transition).	 */	if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) {		sc->rx_idle_secs = 0;		fxp_mc_setup(sc);	}	/*	 * If there is no pending command, start another stats	 * dump. Otherwise punt for now.	 */	if (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) == 0) {		/*		 * Start another stats dump.		 */		fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_DUMPRESET);	} else {		/*		 * A previous command is still waiting to be accepted.		 * Just zero our copy of the stats and wait for the		 * next timer event to update them.		 */		sp->tx_good = 0;		sp->tx_underruns = 0;		sp->tx_total_collisions = 0;		sp->rx_good = 0;		sp->rx_crc_errors = 0;		sp->rx_alignment_errors = 0;		sp->rx_rnr_errors = 0;		sp->rx_overrun_errors = 0;	}#ifdef NOTUSED	if (sc->miibus != NULL)		mii_tick(device_get_softc(sc->miibus));#endif	splx(s);	/*	 * Schedule another timeout one second from now.	 */	if (sc->stat_ch == fxp_timeout_running) {	  timeout(fxp_tick, sc, hz);	}	else if (sc->stat_ch == fxp_timeout_stop_rq) {	  sc->stat_ch = fxp_timeout_stopped;	}	  }/* * Stop the interface. Cancels the statistics updater and resets * the interface. */static voidfxp_stop(struct fxp_softc *sc){	struct ifnet *ifp = &sc->sc_if;	struct fxp_cb_tx *txp;	int i;	DBGLVL_PRINTK(2,"fxp_stop called\n");	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);	ifp->if_timer = 0;	/*	 * stop stats updater.	 */	if (sc->stat_ch == fxp_timeout_running) {	  DBGLVL_PRINTK(3,"fxp_stop: trying to stop stat update tick\n");	  sc->stat_ch = fxp_timeout_stop_rq;	  while(sc->stat_ch != fxp_timeout_stopped) {	    rtems_bsdnet_semaphore_release();	    rtems_task_wake_after(fxp_ticksPerSecond);	    rtems_bsdnet_semaphore_obtain();	  }	  DBGLVL_PRINTK(3,"fxp_stop: stat update tick stopped\n");	}	/*	 * Issue software reset	 */	DBGLVL_PRINTK(3,"fxp_stop: issue software reset\n");	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);	DELAY(10);	/*	 * Release any xmit buffers.	 */	DBGLVL_PRINTK(3,"fxp_stop: releasing xmit buffers\n");	txp = sc->cbl_base;	if (txp != NULL) {		for (i = 0; i < FXP_NTXCB; i++) {			if (txp[i].mb_head != NULL) {				m_freem(txp[i].mb_head);				txp[i].mb_head = NULL;			}		}	}	sc->tx_queued = 0;	/*	 * Free all the receive buffers then reallocate/reinitialize	 */	DBGLVL_PRINTK(3,"fxp_stop: free and reinit all receive buffers\n");	if (sc->rfa_headm != NULL)		m_freem(sc->rfa_headm);	sc->rfa_headm = NULL;	sc->rfa_tailm = NULL;	for (i = 0; i < FXP_NRFABUFS; i++) {		if (fxp_add_rfabuf(sc, NULL) != 0) {			/*			 * This "can't happen" - we're at splimp()			 * and we just freed all the buffers we need			 * above.			 */			panic("fxp_stop: no buffers!");		}	}	DBGLVL_PRINTK(2,"fxp_stop: finished\n");}/* * Watchdog/transmission transmit timeout handler. Called when a * transmission is started on the interface, but no interrupt is * received before the timeout. This usually indicates that the * card has wedged for some reason. */static voidfxp_watchdog(struct ifnet *ifp){	struct fxp_softc *sc = ifp->if_softc;	device_printf(sc->dev, "device timeout\n");	ifp->if_oerrors++;	fxp_init(sc);}static voidfxp_init(void *xsc){	struct fxp_softc *sc = xsc;	struct ifnet *ifp = &sc->sc_if;	struct fxp_cb_config *cbp;	struct fxp_cb_ias *cb_ias;	struct fxp_cb_tx *txp;	int i, prm, s;	DBGLVL_PRINTK(2,"fxp_init called\n");	s = splimp();	/*	 * Cancel any pending I/O	 */    /*     * Add line suggested by "Eugene Denisov" <dea@sendmail.ru>     * on Tue, 16 Mar 2004 13:10:15 +0300     */    sc->stat_ch = fxp_timeout_stopped;	fxp_stop(sc);	prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;	DBGLVL_PRINTK(5,"fxp_init: Initializing base of CBL and RFA memory\n");	/*	 * Initialize base of CBL and RFA memory. Loading with zero	 * sets it up for regular linear addressing.	 */	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);	fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_BASE);	fxp_scb_wait(sc);	fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_BASE);	/*	 * Initialize base of dump-stats buffer.	 */	DBGLVL_PRINTK(5,"fxp_init: Initializing base of dump-stats buffer\n");	fxp_scb_wait(sc);	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats));	fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_DUMP_ADR);	/*	 * We temporarily use memory that contains the TxCB list to	 * construct the config CB. The TxCB list memory is rebuilt	 * later.	 */	cbp = (struct fxp_cb_config *) sc->cbl_base;	DBGLVL_PRINTK(5,"fxp_init: cbp = 0x%x\n",cbp);	/*	 * This bcopy is kind of disgusting, but there are a bunch of must be	 * zero and must be one bits in this structure and this is the easiest	 * way to initialize them all to proper values.	 */	bcopy(fxp_cb_config_template,		(void *)(u_int32_t *)(volatile void *)&cbp->cb_status,		sizeof(fxp_cb_config_template));	cbp->cb_status =	0;	cbp->cb_command =	FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;	cbp->link_addr =	-1;	/* (no) next command */	cbp->byte_count =	22;	/* (22) bytes to config */	cbp->rx_fifo_limit =	8;	/* rx fifo threshold (32 bytes) */	cbp->tx_fifo_limit =	0;	/* tx fifo threshold (0 bytes) */	cbp->adaptive_ifs =	0;	/* (no) adaptive interframe spacing */	cbp->mwi_enable =	sc->flags & FXP_FLAG_MWI_ENABLE ? 1 : 0;	cbp->type_enable =	0;	/* actually reserved */	cbp->read_align_en =	sc->flags & FXP_FLAG_READ_ALIGN ? 1 : 0;	cbp->end_wr_on_cl =	sc->flags & FXP_FLAG_WRITE_ALIGN ? 1 : 0;	cbp->rx_dma_bytecount =	0;	/* (no) rx DMA max */	cbp->tx_dma_bytecount =	0;	/* (no) tx DMA max */	cbp->dma_mbce =		0;	/* (disable) dma max counters */	cbp->late_scb =		0;	/* (don't) defer SCB update */	cbp->direct_dma_dis =	1;	/* disable direct rcv dma mode */	cbp->tno_int_or_tco_en =0;	/* (disable) tx not okay interrupt */	cbp->ci_int =		1;	/* interrupt on CU idle */	cbp->ext_txcb_dis = 	sc->flags & FXP_FLAG_EXT_TXCB ? 0 : 1;	cbp->ext_stats_dis = 	1;	/* disable extended counters */	cbp->keep_overrun_rx = 	0;	/* don't pass overrun frames to host */	cbp->save_bf =		sc->chip == FXP_CHIP_82557 ? 1 : prm;	cbp->disc_short_rx =	!prm;	/* discard short packets */	cbp->underrun_retry =	1;	/* retry mode (once) on DMA underrun */	cbp->two_frames =	0;	/* do not limit FIFO to 2 frames */	cbp->dyn_tbd =		0;	/* (no) dynamic TBD mode */	cbp->mediatype =	sc->flags & FXP_FLAG_SERIAL_MEDIA ? 0 : 1;	cbp->csma_dis =		0;	/* (don't) disable link */	cbp->tcp_udp_cksum =	0;	/* (don't) enable checksum */	cbp->vlan_tco =		0;	/* (don't) enable vlan wakeup */	cbp->link_wake_en =	0;	/* (don't) assert PME# on link change */	cbp->arp_wake_en =	0;	/* (don't) assert PME# on arp */	cbp->mc_wake_en =	0;	/* (don't) enable PME# on mcmatch */	cbp->nsai =		1;	/* (don't) disable source addr insert */	cbp->preamble_length =	2;	/* (7 byte) preamble */	cbp->loopback =		0;	/* (don't) loopback */	cbp->linear_priority =	0;	/* (normal CSMA/CD operation) */	cbp->linear_pri_mode =	0;	/* (wait after xmit only) */	cbp->interfrm_spacing =	6;	/* (96 bits of) interframe spacing */	cbp->promiscuous =	prm;	/* promiscuous mode */	cbp->bcast_disable =	0;	/* (don't) disable broadcasts */	cbp->wait_after_win =	0;	/* (don't) enable modified backoff alg*/	cbp->ignore_ul =	0;	/* consider U/L bit in IA matching */	cbp->crc16_en =		0;	/* (don't) enable crc-16 algorithm */	cbp->crscdt =		sc->flags & FXP_FLAG_SERIAL_MEDIA ? 1 : 0;	cbp->stripping =	!prm;	/* truncate rx packet to byte count */	cbp->padding =		1;	/* (do) pad short tx packets */	cbp->rcv_crc_xfer =	0;	/* (don't) xfer CRC to host */	cbp->long_rx_en =	sc->flags & FXP_FLAG_LONG_PKT_EN ? 1 : 0;	cbp->ia_wake_en =	0;	/* (don't) wake up on address match */	cbp->magic_pkt_dis =	0;	/* (don't) disable magic packet */					/* must set wake_en in PMCSR also */	cbp->force_fdx =	0;	/* (don't) force full duplex */	cbp->fdx_pin_en =	1;	/* (enable) FDX# pin */	cbp->multi_ia =		0;	/* (don't) accept multiple IAs */	cbp->mc_all =		sc->flags & FXP_FLAG_ALL_MCAST ? 1 : 0;	DBGLVL_PRINTK(5,"fxp_init: cbp initialized\n");	if (sc->chip == FXP_CHIP_82557) {		/*		 * The 82557 has no hardware flow control, the values		 * below are the defaults for the chip.		 */		cbp->fc_delay_lsb =	0;		cbp->fc_delay_msb =	0x40;		cbp->pri_fc_thresh =	3;		cbp->tx_fc_dis =	0;		cbp->rx_fc_restop =	0;		cbp->rx_fc_restart =	0;		cbp->fc_filter =	0;		cbp->pri_fc_loc =	1;	} else {		cbp->fc_delay_lsb =	0x1f;		cbp->fc_delay_msb =	0x01;		cbp->pri_fc_thresh =	3;		cbp->tx_fc_dis =	0;	/* enable transmit FC */		cbp->rx_fc_restop =	1;	/* enable FC restop frames */		cbp->rx_fc_restart =	1;	/* enable FC restart frames */		cbp->fc_filter =	!prm;	/* drop FC frames to host */		cbp->pri_fc_loc =	1;	/* FC pri location (byte31) */	}	/*	 * Start the config command/DMA.	 */	DBGLVL_PRINTK(5,"fxp_init: starting config command/DMA\n");	fxp_scb_wait(sc);	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));	fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START);	/* ...and wait for it to complete. */	fxp_dma_wait(&cbp->cb_status, sc);	/*	 * Now initialize the station address. Temporarily use the TxCB	 * memory area like we did above for the config CB.	 */	DBGLVL_PRINTK(5,"fxp_init: initialize station address\n");	cb_ias = (struct fxp_cb_ias *) sc->cbl_base;	cb_ias->cb_status = 0;	cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;	cb_ias->link_addr = -1;	bcopy(sc->arpcom.ac_enaddr,	    (void *)(u_int32_t *)(volatile void *)cb_ias->macaddr,	    sizeof(sc->arpcom.ac_enaddr));	/*	 * Start the IAS (Individual Address Setup) command/DMA.	 */	DBGLVL_PRINTK(5,"fxp_init: start IAS command/DMA\n");	fxp_scb_wait(sc);	fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_START);	/* ...and wait for it to complete. */	fxp_dma_wait(&cb_ias->cb_status, sc);	/*	 * Initialize transmit control block (TxCB) list.	 */

⌨️ 快捷键说明

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