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

📄 if_wx.c

📁 国产CPU-龙芯(loongson)BIOS源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $OpenBSD: if_wx.c,v 1.18 2001/10/24 18:25:55 mjacob Exp $ *//* * Principal Author: Matthew Jacob <mjacob@feral.com> * Copyright (c) 1999, 2001 by Traakan Software * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice unmodified, this list of conditions, and the following *    disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Additional Copyright (c) 2001 by Parag Patel * under same licence for MII PHY code. *//* * Intel Gigabit Ethernet (82452/82453) Driver. * Inspired by fxp driver by David Greenman for FreeBSD, and by * Bill Paul's work in other FreeBSD network drivers. *//* * Many bug fixes gratefully acknowledged from: * *	The folks at Sitara Networks *//* * Options *//* * Use only every other 16 byte receive descriptor, leaving the ones * in between empty. This card is most efficient at reading/writing * 32 byte cache lines, so avoid all the (not working for early rev * cards) MWI and/or READ/MODIFY/WRITE cycles updating one descriptor * would have you do. * * This isn't debugged yet. *//* #define	PADDED_CELL	1 *//* * Since the includes are a mess, they'll all be in if_wxvar.h */#include <dev/pci/if_wxvar.h>#ifdef __alpha__#undef vtophys#define	vtophys(va)	alpha_XXX_dmamap((vm_offset_t)(va))#endif /* __alpha__ *//* * Function Prototpes, yadda yadda... */static int wx_intr(void *);static void wx_handle_link_intr(wx_softc_t *);static void wx_check_link(wx_softc_t *);static void wx_handle_rxint(wx_softc_t *);static void wx_gc(wx_softc_t *);static void wx_start(struct ifnet *);static int wx_ioctl(struct ifnet *, IOCTL_CMD_TYPE, caddr_t);static int wx_ifmedia_upd(struct ifnet *);static void wx_ifmedia_sts(struct ifnet *, struct ifmediareq *);static int wx_init(void *);static void wx_hw_stop(wx_softc_t *);static void wx_set_addr(wx_softc_t *, int, u_int8_t *);static int wx_hw_initialize(wx_softc_t *);static void wx_stop(wx_softc_t *);static void wx_txwatchdog(struct ifnet *);static int wx_get_rbuf(wx_softc_t *, rxpkt_t *);static void wx_rxdma_map(wx_softc_t *, rxpkt_t *, struct mbuf *);static INLINE void wx_eeprom_raise_clk(wx_softc_t *, u_int32_t);static INLINE void wx_eeprom_lower_clk(wx_softc_t *, u_int32_t);static INLINE void wx_eeprom_sobits(wx_softc_t *, u_int16_t, u_int16_t);static INLINE u_int16_t wx_eeprom_sibits(wx_softc_t *);static INLINE void wx_eeprom_cleanup(wx_softc_t *);static INLINE u_int16_t wx_read_eeprom_word(wx_softc_t *, int);static void wx_read_eeprom(wx_softc_t *, u_int16_t *, int, int);static int wx_attach_common(wx_softc_t *);static void wx_watchdog(void *);static INLINE void wx_mwi_whackon(wx_softc_t *);static INLINE void wx_mwi_unwhack(wx_softc_t *);static int wx_dring_setup(wx_softc_t *);static void wx_dring_teardown(wx_softc_t *);static int wx_attach_phy(wx_softc_t *);static int wx_miibus_readreg(void *, int, int);static int wx_miibus_writereg(void *, int, int, int);static void wx_miibus_statchg(void *);static u_int32_t wx_mii_shift_in(wx_softc_t *);static void wx_mii_shift_out(wx_softc_t *, u_int32_t, u_int32_t);#define	WX_DISABLE_INT(sc)	WRITE_CSR(sc, WXREG_IMCLR, WXDISABLE)#define	WX_ENABLE_INT(sc)	WRITE_CSR(sc, WXREG_IMASK, sc->wx_ienable)/* * Until we do a bit more work, we can get no bigger than MCLBYTES */#if	0#define	WX_MAXMTU	(WX_MAX_PKT_SIZE_JUMBO - sizeof (struct ether_header))#else#define	WX_MAXMTU	(MCLBYTES - sizeof (struct ether_header))#endif#define	DPRINTF(sc, x)	if (sc->wx_debug) printf x#define	IPRINTF(sc, x)	if (sc->wx_verbose) printf xstatic const char ldn[] = "%s: link down\n";static const char lup[] = "%s: link up\n";static const char sqe[] = "%s: receive sequence error\n";static const char ane[] = "%s: /C/ ordered sets seen- enabling ANE\n";static const char inane[] = "%s: no /C/ ordered sets seen- disabling ANE\n";#define	MATCHARG	void *static int	wx_match(struct device *, MATCHARG, void *);static void	wx_attach(struct device *, struct device *, void *);static void	wx_shutdown(void *);static int	wx_ether_ioctl(struct ifnet *, IOCTL_CMD_TYPE, caddr_t);static int	wx_mc_setup(wx_softc_t *);#define		ether_ioctl	wx_ether_ioctl/* * Life *should* be simple- we only read/write 32 bit values in registers. * Unfortunately, some platforms define bus_space functions in a fashion * such that they cannot be used as part of a for loop, for example. */static INLINE u_int32_t _read_csr (wx_softc_t *, u_int32_t);static INLINE void _write_csr(wx_softc_t *, u_int32_t, u_int32_t);static INLINE u_int32_t_read_csr(wx_softc_t *sc, u_int32_t reg){	return bus_space_read_4(sc->w.st, sc->w.sh, reg);}static INLINE void_write_csr(wx_softc_t *sc, u_int32_t reg, u_int32_t val){	bus_space_write_4(sc->w.st, sc->w.sh, reg, val);}struct cfattach wx_ca = {	sizeof (wx_softc_t), wx_match, wx_attach};struct cfdriver wx_cd = {	0, "wx", DV_IFNET};/* * Check if a device is an 82452. */static intwx_match(struct device *parent, MATCHARG match, void *aux){	struct pci_attach_args *pa = aux;	if (PCI_VENDOR(pa->pa_id) != WX_VENDOR_INTEL) {		return (0);	}	switch (PCI_PRODUCT(pa->pa_id)) {	case WX_PRODUCT_82452:	case WX_PRODUCT_LIVENGOOD:	case WX_PRODUCT_82452_SC:	case WX_PRODUCT_82543:		break;	default:		return (0);	}	return (1);}static voidwx_attach(struct device *parent, struct device *self, void *aux){	wx_softc_t *sc = (wx_softc_t *)self;	struct pci_attach_args *pa = aux;#ifndef PMON	pci_chipset_tag_t pc = pa->pa_pc;#endif	pci_intr_handle_t ih;	const char *intrstr = NULL;	u_int32_t data;	struct ifnet *ifp;	sc->w.pci_pc = pa->pa_pc;	sc->w.pci_tag = pa->pa_tag;	/*	 * Map control/status registers.	 */	if (pci_mapreg_map(pa, WX_MMBA, PCI_MAPREG_TYPE_MEM, 0,	    &sc->w.st, &sc->w.sh, NULL, NULL, 0)) {		printf(": can't map registers\n");		return;	}	sc->wx_idnrev = (PCI_PRODUCT(pa->pa_id) << 16) |		(pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0xff);        /*         * Let the BIOS do it's job- but check for sanity.         */	data = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);	switch ((data >> PCI_CACHELINE_SHIFT) & PCI_CACHELINE_MASK) {	case 4:	case 8:	case 16:	case 32:		break;	default:		data &= ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT);		data |= (8 << PCI_CACHELINE_SHIFT);		pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, data);		break;	}	if (wx_attach_common(sc)) {		printf("\n");		return;	}	if (!IS_LIVENGOOD_CU(sc)) {		printf(": address %s", ether_sprintf(sc->wx_enaddr));	}	/*	 * Allocate our interrupt.	 */	if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,				pa->pa_intrline, &ih)) {		printf(", couldn't map interrupt\n");		return;	}	intrstr = pci_intr_string(pc, ih);	sc->w.ih = pci_intr_establish(pc, ih, IPL_NET, wx_intr, sc,	    self->dv_xname);	if (sc->w.ih == NULL) {		printf(", couldn't establish interrupt\n");		if (intrstr != NULL)			printf(" at %s", intrstr);		printf("\n");		return;	}	if (!IS_LIVENGOOD_CU(sc)) {		printf(", %s\n", intrstr);	}	ifp = &sc->wx_if;	bcopy(sc->wx_name, ifp->if_xname, IFNAMSIZ);	ifp->if_mtu = WX_MAXMTU;	ifp->if_softc = sc;	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;	ifp->if_ioctl = wx_ioctl;	ifp->if_start = wx_start;	ifp->if_watchdog = wx_txwatchdog;	/*	 * Attach the interface.	 */	if_attach(ifp);	ether_ifattach(ifp);	/*	 * 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(wx_shutdown, sc);}static intwx_attach_phy(wx_softc_t *sc){	mii_data_t *mii = WX_MII_FROM_SOFTC(sc);	ifmedia_init(&mii->mii_media, 0, wx_ifmedia_upd, wx_ifmedia_sts);        mii->mii_ifp = &sc->wx_if;	mii->mii_readreg = (mii_readreg_t) wx_miibus_readreg;	mii->mii_writereg = (mii_writereg_t) wx_miibus_writereg;	mii->mii_statchg = (mii_statchg_t) wx_miibus_statchg;	mii_phy_probe(&sc->w.dev, mii, 0xffffffff);	if (LIST_FIRST(&mii->mii_phys) == NULL) {		ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_NONE, 0, NULL);		ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_NONE);	} else {		ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO);	}	return 0;}/* * 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 voidwx_shutdown(void *sc){	wx_hw_stop((wx_softc_t *) sc);}static intwx_ether_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE cmd, caddr_t data){	struct ifaddr *ifa = (struct ifaddr *) data;	int error = 0;	wx_softc_t *sc = SOFTC_IFP(ifp);	switch (cmd) {	case SIOCSIFADDR:		ifp->if_flags |= IFF_UP;		error = wx_init(sc);		if (error) {			ifp->if_flags &= ~IFF_UP;			break;		}		switch (ifa->ifa_addr->sa_family) {#ifdef INET		case AF_INET:			arp_ifinit(&sc->w.arpcom, ifa);			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);			 break;		}#endif		default:			break;		}		break;	default:		error = EINVAL;		break;	}	return (0);}/* * Program multicast addresses. * * This function must be called at splimp, but it may sleep. */static intwx_mc_setup(wx_softc_t *sc){	struct ifnet *ifp = &sc->wx_if;	struct ether_multistep step;	struct ether_multi *enm;	/*	 * XXX: drain TX queue	 */	if (sc->tactive) {		return (EBUSY);	}	wx_stop(sc);	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {		sc->all_mcasts = 1;		return (wx_init(sc));	}	ETHER_FIRST_MULTI(step, &sc->w.arpcom, enm);	while (enm != NULL) {		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0)			continue;		if (sc->wx_nmca >= WX_RAL_TAB_SIZE-1) {			sc->wx_nmca = 0;			sc->all_mcasts = 1;			break;		}		bcopy(enm->enm_addrlo, 		    (void *) &sc->wx_mcaddr[sc->wx_nmca++][0], 6);		ETHER_NEXT_MULTI(step, enm);	}	return (wx_init(sc));}static INLINE voidwx_mwi_whackon(wx_softc_t *sc){	sc->wx_cmdw =	    pci_conf_read(sc->w.pci_pc, sc->w.pci_tag, PCI_COMMAND_STATUS_REG);	pci_conf_write(sc->w.pci_pc, sc->w.pci_tag,	    PCI_COMMAND_STATUS_REG, sc->wx_cmdw & ~MWI);}static INLINE voidwx_mwi_unwhack(wx_softc_t *sc){	if (sc->wx_cmdw & MWI) {		pci_conf_write(sc->w.pci_pc, sc->w.pci_tag,		    PCI_COMMAND_STATUS_REG, sc->wx_cmdw & ~MWI);	}}static intwx_dring_setup(wx_softc_t *sc){	size_t len;	len = sizeof (wxrd_t) * WX_MAX_RDESC;	if (len > NBPG) {		printf("%s: len (%lx) over a page for the receive ring\n",		    sc->wx_name, len);		return (-1);	}	len = NBPG;	sc->rdescriptors = (wxrd_t *) WXMALLOC(len);	if (sc->rdescriptors == NULL) {		printf("%s: could not allocate rcv descriptors\n", sc->wx_name);		return (-1);	}	if (((intptr_t)sc->rdescriptors) & 0xfff) {		printf("%s: rcv descriptors not 4KB aligned\n", sc->wx_name);		return (-1);	}        bzero(sc->rdescriptors, len);	len = sizeof (wxtd_t) * WX_MAX_TDESC;	if (len > NBPG) {		printf("%s: len (%lx) over a page for the xmit ring\n",		    sc->wx_name, len);		return (-1);	}	len = NBPG;	sc->tdescriptors = (wxtd_t *) WXMALLOC(len);	if (sc->tdescriptors == NULL) {		printf("%s: could not allocate xmt descriptors\n", sc->wx_name);		return (-1);	}	if (((intptr_t)sc->tdescriptors) & 0xfff) {		printf("%s: xmt descriptors not 4KB aligned\n", sc->wx_name);		return (-1);	}        bzero(sc->tdescriptors, len);	return (0);}static voidwx_dring_teardown(wx_softc_t *sc){	if (sc->rdescriptors) {		WXFREE(sc->rdescriptors);		sc->rdescriptors = NULL;	}	if (sc->tdescriptors) {		WXFREE(sc->tdescriptors);		sc->tdescriptors = NULL;	}}/* * Do generic parts of attach. Our registers have been mapped * and our interrupt registered. */static intwx_attach_common(wx_softc_t *sc){	size_t len;	u_int32_t tmp;	int ll = 0;	/*	 * First, check for revision support.	 */	if (sc->wx_idnrev < WX_WISEMAN_2_0) {		printf("%s: cannot support ID 0x%x, revision %d chips\n",		    sc->wx_name, sc->wx_idnrev >> 16, sc->wx_idnrev & 0xffff);		return (ENXIO);	}	/*	 * Second, reset the chip.	 */	wx_hw_stop(sc);	/*	 * Third, validate our EEPROM.	 */	/* TBD */	/*	 * Fourth, read eeprom for our MAC address and other things.	 */	wx_read_eeprom(sc, (u_int16_t *)sc->wx_enaddr, WX_EEPROM_MAC_OFF, 3);	/*	 * Fifth, establish some adapter parameters.	 */	sc->wx_dcr = 0;	if (IS_LIVENGOOD_CU(sc)) {		sc->wx_mii = 1;		/* settings to talk to PHY */		sc->wx_dcr |= WXDCR_FRCSPD | WXDCR_FRCDPX | WXDCR_SLU;		WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr);		/*		 * Raise the PHY's reset line to make it operational.		 */		tmp = READ_CSR(sc, WXREG_EXCT);		tmp |= WXPHY_RESET_DIR4;		WRITE_CSR(sc, WXREG_EXCT, tmp);		DELAY(20*1000);		tmp = READ_CSR(sc, WXREG_EXCT);		tmp &= ~WXPHY_RESET4;		WRITE_CSR(sc, WXREG_EXCT, tmp);		DELAY(20*1000);

⌨️ 快捷键说明

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