⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_fxp.c

📁 国产CPU-龙芯(loongson)BIOS源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB,	    sizeof(struct ether_header));#endif#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.	 */	shutdownhook_establish(fxp_shutdown, sc);#ifndef PMON	/*	 * Add suspend hook, for similiar reasons..	 */	powerhook_establish(fxp_power, sc);#endif}/* * 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(sc)	void *sc;{	fxp_stop((struct fxp_softc *) sc, 0);}#ifndef PMON/* * Power handler routine. Called when the system is transitioning * into/out of power save modes.  As with fxp_shutdown, the main * purpose of this routine is to shut off receiver DMA so it doesn't * clobber kernel memory at the wrong time. */voidfxp_power(why, arg)	int why;	void *arg;{	struct fxp_softc *sc = arg;	struct ifnet *ifp;	int s;	s = splnet();	if (why != PWR_RESUME)		fxp_stop(sc, 0);	else {		ifp = &sc->arpcom.ac_if;		if (ifp->if_flags & IFF_UP)			fxp_init(sc);	}	splx(s);}#endifstatic intfxp_ether_ioctl(ifp, cmd, data)	struct ifnet *ifp;	FXP_IOCTLCMD_TYPE cmd;	caddr_t data;{	struct ifaddr *ifa = (struct ifaddr *) data;	struct fxp_softc *sc = ifp->if_softc;	int error = 0;	switch (cmd) {#ifdef PMON	case SIOCPOLL:		break;#endif	case SIOCSIFADDR:		ifp->if_flags |= IFF_UP;		switch (ifa->ifa_addr->sa_family) {#ifdef INET		case AF_INET:			error = fxp_init(sc);			if(error == -1)				return(error);#ifdef __OpenBSD__			arp_ifinit(&sc->arpcom, ifa);#else			arp_ifinit(ifp, ifa);#endif			break;#endif#ifdef NS		case AF_NS:		    {			 register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;			 if (ns_nullhost(*ina))				ina->x_host = *(union ns_host *)				    LLADDR(ifp->if_sadl);			 else				bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),				    ifp->if_addrlen);			 /* Set new address. */			 fxp_init(sc);			 break;		    }#endif		default:			fxp_init(sc);			break;		}		break;	default:		return (EINVAL);	}	return (error);}/************************************************************* * 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;	/*	 * Reset to a stable state.	 */	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);	DELAY(100);	sc->cbl_base = malloc(sizeof(struct fxp_cb_tx) * FXP_NTXCB,	    M_DEVBUF, M_NOWAIT);	if (sc->cbl_base == NULL)		goto fail;#if defined(__mips__)	/*	 *  Due to MIPS processor cache behaviour we change to uncached	 *  addresses to access control structure areas.	 */	pci_sync_cache(sc->sc_pc, (vm_offset_t)sc->cbl_base,				sizeof(struct fxp_cb_tx) * FXP_NTXCB, SYNC_W);	sc->cbl_base = (void *)PHYS_TO_UNCACHED(vtophys(sc->cbl_base));#endif /*__mips__*/	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));#if defined(__mips__)	pci_sync_cache(sc->sc_pc, (vm_offset_t)sc->fxp_stats,				sizeof(struct fxp_stats), SYNC_W);	sc->fxp_stats = (void *)PHYS_TO_UNCACHED(vtophys(sc->fxp_stats));#endif /*__mips__*/		sc->mcsp = malloc(sizeof(struct fxp_cb_mcs), M_DEVBUF, M_NOWAIT);	if (sc->mcsp == NULL)		goto fail;#if defined(__mips__)	pci_sync_cache(sc->sc_pc, (vm_offset_t)sc->mcsp,				sizeof(struct fxp_cb_mcs), SYNC_W);	sc->mcsp = (void *)PHYS_TO_UNCACHED(vtophys(sc->mcsp));#endif /*__mips__*/	/*	 * Pre-allocate our receive buffers.	 */	for (i = 0; i < FXP_NRFABUFS; i++) {		if (fxp_add_rfabuf(sc, NULL) != 0) {			goto fail;		}	}	/*	 * Find out how large of an SEEPROM we have.	 */	fxp_autosize_eeprom(sc);	/*	 * Get info about the primary PHY	 */#if   defined(GODSONEV1)	data=0x4701;#else		fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1);#endif	sc->phy_primary_addr = data & 0xff;	sc->phy_primary_device = (data >> 8) & 0x3f;	sc->phy_10Mbps_only = data >> 15;	/*	 * Read MAC address.	 */#if defined(GODSONEV1)	enaddr[0]=0x12;	enaddr[1]=0x34;	enaddr[2]=0x56;	enaddr[3]=0x78;	enaddr[4]=0x9a;	enaddr[5]=0xbc;#else	fxp_read_eeprom(sc, (u_int16_t *)enaddr, 0, 3);#endif	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);}/* * 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. * * Other ways to do this would be to try to read a register with known * contents with a varying number of address bits, but no such * register seem to be available. The high bits of register 10 are 01 * on the 558 and 559, but apparently not on the 557. *  * The Linux driver computes a checksum on the EEPROM data, but the * value of this checksum is not very well documented. */static voidfxp_autosize_eeprom(sc)	struct fxp_softc *sc;{	u_int16_t reg;	int x;	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.	 * Wait for the dummy zero following a correct address shift.	 */	for (x = 1; x <= 8; x++) {		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,			FXP_EEPROM_EECS | FXP_EEPROM_EESK);		DELAY(1);		if ((CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) & FXP_EEPROM_EEDO) == 0)			break;		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);		DELAY(1);	}	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);	sc->eeprom_size = x;}/* * 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. */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 = sc->eeprom_size; 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);		}#if BYTE_ORDER == BIG_ENDIAN		data[i] = swap16(data[i]);#endif		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);		DELAY(1);	}}#if 0/* * Write to the serial EEPROM. This is not intended to be used * uncautiosly(?). The main intention is to privide a means to * initiate an uninitialized EEPROM during production test. */voidfxp_write_eeprom(sc, data, offset, words)	struct fxp_softc *sc;	u_short *data;	int offset;	int words;{	u_int16_t reg;	int i, x;	int d;	/*	 * Enable writing.	 */	d = (FXP_EEPROM_OPC_WRITENB << 4);	x = 0x100;	while (x != 0) {		if (d & x) {			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);		x >>= 1;	}/* XXXX Need data sheet to verify if raise CS is enough! (pefo) */	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EESK);	DELAY(1);	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);	/*	 * Now write the data words.	 */	for (i = 0; i < words; i++) {#if BYTE_ORDER == BIG_ENDIAN                data[i] = swap16(data[i]);#endif		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);		/*		 * Shift in write command, address and data.		 */		d = (FXP_EEPROM_OPC_WRITE << 6) | ((i + offset) & 0x3f);		d = d << 16 | data[i];		x = 0x1000000;		while (x != 0) {			if (d & x) {				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);			x >>= 1;		}		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);		DELAY(1);		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EESK);		DELAY(1);		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);		DELAY(1);		DELAY(200000);  /* Let write settle */	}	/*	 * Disable writing.	 */	d = (FXP_EEPROM_OPC_WRITDIS << 4);	x = 0x100;	while (x != 0) {		if (d & x) {			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);		x >>= 1;	}	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EESK);	DELAY(1);	CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);	DELAY(1);}#endif/* * 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;#ifdef USE_FXP_MCAST	/*	 * 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;#endif	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.		 */

⌨️ 快捷键说明

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