if_fxp.c

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

C
2,315
字号
fxp_shutdown(device_t dev){	/*	 * Make sure that DMA is disabled prior to reboot. Not doing	 * do could allow DMA to corrupt kernel memory during the	 * reboot before the driver initializes.	 */	fxp_stop((struct fxp_softc *) device_get_softc(dev));	return (0);}#endif/* * Show interface statistics */static voidfxp_stats(struct fxp_softc *sc){	struct ifnet *ifp = &sc->sc_if;	printf ("   Output packets:%-8lu", ifp->if_opackets);	printf ("    Collisions:%-8lu", ifp->if_collisions);	printf (" Output errors:%-8lu\n", ifp->if_oerrors);	printf ("    Input packets:%-8lu", ifp->if_ipackets);	printf ("  Input errors:%-8lu\n", ifp->if_ierrors);}static void fxp_eeprom_shiftin(struct fxp_softc *sc, int data, int length){	u_int16_t reg;	int x;	/*	 * Shift in data.	 */	for (x = 1 << (length - 1); x; x >>= 1) {		if (data & x)			reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;		else			reg = FXP_EEPROM_EECS;		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);		DELAY(1);		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK);		DELAY(1);		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);		DELAY(1);	}}/* * 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 u_int16_tfxp_eeprom_getword(struct fxp_softc *sc, int offset, int autosize){	u_int16_t reg, data;	int x;	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);	/*	 * Shift in read opcode.	 */	fxp_eeprom_shiftin(sc, FXP_EEPROM_OPC_READ, 3);	/*	 * Shift in address.	 */	data = 0;	for (x = 1 << (sc->eeprom_size - 1); x; x >>= 1) {		if (offset & x)			reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;		else			reg = FXP_EEPROM_EECS;		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);		DELAY(1);		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg | FXP_EEPROM_EESK);		DELAY(1);		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);		DELAY(1);		reg = CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO;		data++;		if (autosize && reg == 0) {			sc->eeprom_size = data;			break;		}	}	/*	 * Shift out data.	 */	data = 0;	reg = FXP_EEPROM_EECS;	for (x = 1 << 15; x; x >>= 1) {		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 |= x;		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);		DELAY(1);	}	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);	return (data);}static voidfxp_eeprom_putword(struct fxp_softc *sc, int offset, u_int16_t data){	int i;	/*	 * Erase/write enable.	 */	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);	fxp_eeprom_shiftin(sc, 0x4, 3);	fxp_eeprom_shiftin(sc, 0x03 << (sc->eeprom_size - 2), sc->eeprom_size);	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);	/*	 * Shift in write opcode, address, data.	 */	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);	fxp_eeprom_shiftin(sc, FXP_EEPROM_OPC_WRITE, 3);	fxp_eeprom_shiftin(sc, offset, sc->eeprom_size);	fxp_eeprom_shiftin(sc, data, 16);	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);	/*	 * Wait for EEPROM to finish up.	 */	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);	DELAY(1);	for (i = 0; i < 1000; i++) {		if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO)			break;		DELAY(50);	}	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);	/*	 * Erase/write disable.	 */	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);	fxp_eeprom_shiftin(sc, 0x4, 3);	fxp_eeprom_shiftin(sc, 0, sc->eeprom_size);	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);}/* * From NetBSD: * * Figure out EEPROM size. * * 559's can have either 64-word or 256-word EEPROMs, the 558 * datasheet only talks about 64-word EEPROMs, and the 557 datasheet * talks about the existance of 16 to 256 word EEPROMs. * * The only known sizes are 64 and 256, where the 256 version is used * by CardBus cards to store CIS information. * * The address is shifted in msb-to-lsb, and after the last * address-bit the EEPROM is supposed to output a `dummy zero' bit, * after which follows the actual data. We try to detect this zero, by * probing the data-out bit in the EEPROM control register just after * having shifted in a bit. If the bit is zero, we assume we've * shifted enough address bits. The data-out should be tri-state, * before this, which should translate to a logical one. */static voidfxp_autosize_eeprom(struct fxp_softc *sc){	/* guess maximum size of 256 words */	sc->eeprom_size = 8;	/* autosize */	(void) fxp_eeprom_getword(sc, 0, 1);}static voidfxp_read_eeprom(struct fxp_softc *sc, u_short *data, int offset, int words){	int i;	for (i = 0; i < words; i++) {		data[i] = fxp_eeprom_getword(sc, offset + i, 0);		DBGLVL_PRINTK(4,"fxp_eeprom_read(off=0x%x)=0x%x\n",			      offset+i,data[i]);	}}static voidfxp_write_eeprom(struct fxp_softc *sc, u_short *data, int offset, int words){	int i;	for (i = 0; i < words; i++)		fxp_eeprom_putword(sc, offset + i, data[i]);		DBGLVL_PRINTK(4,"fxp_eeprom_write(off=0x%x,0x%x)\n",			      offset+i,data[i]);}/* * Start packet transmission on the interface. */static voidfxp_start(struct ifnet *ifp){	struct fxp_softc *sc = ifp->if_softc;	struct fxp_cb_tx *txp;	DBGLVL_PRINTK(3,"fxp_start called\n");	/*	 * 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.		 */#ifdef __alpha__		/*		 * On platforms which can't access memory in 16-bit		 * granularities, we must prevent the card from DMA'ing		 * up the status while we update the command field.		 * This could cause us to overwrite the completion status.		 */		atomic_clear_short(&sc->cbl_last->cb_command,		    FXP_CB_COMMAND_S);#else		sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;#endif /*__alpha__*/		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++;#ifdef NOTUSED		/*		 * Pass packet to bpf if there is a listener.		 */		if (ifp->if_bpf)			bpf_mtap(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);		fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_RESUME);	}}/* * Process interface interrupts. */static rtems_isr fxp_intr(rtems_vector_number v){  /*   * FIXME: currently only works with one interface...    */  struct fxp_softc *sc = &(fxp_softc[0]);  /*   * disable interrupts   */  CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE);  /*   * send event to deamon   */  rtems_event_send (sc->daemonTid, INTERRUPT_EVENT);}static void fxp_daemon(void *xsc){	struct fxp_softc *sc = xsc;	struct ifnet *ifp = &sc->sc_if;	u_int8_t statack;	rtems_event_set events;	rtems_interrupt_level level;#ifdef NOTUSED	if (sc->suspended) {		return;	}#endif	for (;;) {	DBGLVL_PRINTK(4,"fxp_daemon waiting for event\n");	  /*	   * wait for event to receive from interrupt function	   */	  rtems_bsdnet_event_receive (INTERRUPT_EVENT,				      RTEMS_WAIT|RTEMS_EVENT_ANY,				      RTEMS_NO_TIMEOUT,				      &events);	  while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {	    DBGLVL_PRINTK(4,"fxp_daemon: processing event, statack = 0x%x\n",			  statack);#ifdef NOTUSED		/*		 * It should not be possible to have all bits set; the		 * FXP_SCB_INTR_SWI bit always returns 0 on a read.  If 		 * all bits are set, this may indicate that the card has		 * been physically ejected, so ignore it.		 */  		if (statack == 0xff) 			return;#endif		/*		 * First ACK all the interrupts in this pass.		 */		CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);		/*		 * Free any finished transmit mbuf chains.		 *		 * Handle the CNA event likt a CXTNO event. It used to		 * be that this event (control unit not ready) was not		 * encountered, but it is now with the SMPng modifications.		 * The exact sequence of events that occur when the interface		 * is brought up are different now, and if this event		 * goes unhandled, the configuration/rxfilter setup sequence		 * can stall for several seconds. The result is that no		 * packets go out onto the wire for about 5 to 10 seconds		 * after the interface is ifconfig'ed for the first time.		 */		if (statack & (FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA)) {			struct fxp_cb_tx *txp;			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;			ifp->if_timer = 0;			if (sc->tx_queued == 0) {				if (sc->need_mcsetup)					fxp_mc_setup(sc);			}			/*			 * Try to start more packets transmitting.			 */			if (ifp->if_snd.ifq_head != NULL)				fxp_start(ifp);		}		/*		 * Process receiver interrupts. If a no-resource (RNR)		 * condition exists, get whatever packets we can and		 * re-start the receiver.

⌨️ 快捷键说明

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