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

📄 sunhme.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (hp->sw_bmsr & BMSR_10HALF)			hp->sw_advertise |= (ADVERTISE_10HALF);		else			hp->sw_advertise &= ~(ADVERTISE_10HALF);		if (hp->sw_bmsr & BMSR_10FULL)			hp->sw_advertise |= (ADVERTISE_10FULL);		else			hp->sw_advertise &= ~(ADVERTISE_10FULL);		if (hp->sw_bmsr & BMSR_100HALF)			hp->sw_advertise |= (ADVERTISE_100HALF);		else			hp->sw_advertise &= ~(ADVERTISE_100HALF);		if (hp->sw_bmsr & BMSR_100FULL)			hp->sw_advertise |= (ADVERTISE_100FULL);		else			hp->sw_advertise &= ~(ADVERTISE_100FULL);		happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise);		/* XXX Currently no Happy Meal cards I know off support 100BaseT4,		 * XXX and this is because the DP83840 does not support it, changes		 * XXX would need to be made to the tx/rx logic in the driver as well		 * XXX so I completely skip checking for it in the BMSR for now.		 */#ifdef AUTO_SWITCH_DEBUG		ASD(("%s: Advertising [ ", hp->dev->name));		if (hp->sw_advertise & ADVERTISE_10HALF)			ASD(("10H "));		if (hp->sw_advertise & ADVERTISE_10FULL)			ASD(("10F "));		if (hp->sw_advertise & ADVERTISE_100HALF)			ASD(("100H "));		if (hp->sw_advertise & ADVERTISE_100FULL)			ASD(("100F "));#endif		/* Enable Auto-Negotiation, this is usually on already... */		hp->sw_bmcr |= BMCR_ANENABLE;		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);		/* Restart it to make sure it is going. */		hp->sw_bmcr |= BMCR_ANRESTART;		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);		/* BMCR_ANRESTART self clears when the process has begun. */		timeout = 64;  /* More than enough. */		while (--timeout) {			hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);			if (!(hp->sw_bmcr & BMCR_ANRESTART))				break; /* got it. */			udelay(10);		}		if (!timeout) {			printk(KERN_ERR "%s: Happy Meal would not start auto negotiation "			       "BMCR=0x%04x\n", hp->dev->name, hp->sw_bmcr);			printk(KERN_NOTICE "%s: Performing force link detection.\n",			       hp->dev->name);			goto force_link;		} else {			hp->timer_state = arbwait;		}	} else {force_link:		/* Force the link up, trying first a particular mode.		 * Either we are here at the request of ethtool or		 * because the Happy Meal would not start to autoneg.		 */		/* Disable auto-negotiation in BMCR, enable the duplex and		 * speed setting, init the timer state machine, and fire it off.		 */		if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {			hp->sw_bmcr = BMCR_SPEED100;		} else {			if (ep->speed == SPEED_100)				hp->sw_bmcr = BMCR_SPEED100;			else				hp->sw_bmcr = 0;			if (ep->duplex == DUPLEX_FULL)				hp->sw_bmcr |= BMCR_FULLDPLX;		}		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);		if (!is_lucent_phy(hp)) {			/* OK, seems we need do disable the transceiver for the first			 * tick to make sure we get an accurate link state at the			 * second tick.			 */			hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,							       DP83840_CSCONFIG);			hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);			happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,					      hp->sw_csconfig);		}		hp->timer_state = ltrywait;	}	hp->timer_ticks = 0;	hp->happy_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */	hp->happy_timer.data = (unsigned long) hp;	hp->happy_timer.function = &happy_meal_timer;	add_timer(&hp->happy_timer);}#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */static int happy_meal_init(struct happy_meal *hp, int from_irq){	unsigned long gregs        = hp->gregs;	unsigned long etxregs      = hp->etxregs;	unsigned long erxregs      = hp->erxregs;	unsigned long bregs        = hp->bigmacregs;	unsigned long tregs        = hp->tcvregs;	u32 regtmp, rxcfg;	unsigned char *e = &hp->dev->dev_addr[0];	/* If auto-negotiation timer is running, kill it. */	del_timer(&hp->happy_timer);	HMD(("happy_meal_init: happy_flags[%08x] ",	     hp->happy_flags));	if (!(hp->happy_flags & HFLAG_INIT)) {		HMD(("set HFLAG_INIT, "));		hp->happy_flags |= HFLAG_INIT;		happy_meal_get_counters(hp, bregs);	}	/* Stop polling. */	HMD(("to happy_meal_poll_stop\n"));	happy_meal_poll_stop(hp, tregs);	/* Stop transmitter and receiver. */	HMD(("happy_meal_init: to happy_meal_stop\n"));	happy_meal_stop(hp, gregs);	/* Alloc and reset the tx/rx descriptor chains. */	HMD(("happy_meal_init: to happy_meal_init_rings\n"));	happy_meal_init_rings(hp, from_irq);	/* Shut up the MIF. */	HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ",	     hme_read32(hp, tregs + TCVR_IMASK)));	hme_write32(hp, tregs + TCVR_IMASK, 0xffff);	/* See if we can enable the MIF frame on this card to speak to the DP83840. */	if (hp->happy_flags & HFLAG_FENABLE) {		HMD(("use frame old[%08x], ",		     hme_read32(hp, tregs + TCVR_CFG)));		hme_write32(hp, tregs + TCVR_CFG,			    hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_BENABLE));	} else {		HMD(("use bitbang old[%08x], ",		     hme_read32(hp, tregs + TCVR_CFG)));		hme_write32(hp, tregs + TCVR_CFG,			    hme_read32(hp, tregs + TCVR_CFG) | TCV_CFG_BENABLE);	}	/* Check the state of the transceiver. */	HMD(("to happy_meal_transceiver_check\n"));	happy_meal_transceiver_check(hp, tregs);	/* Put the Big Mac into a sane state. */	HMD(("happy_meal_init: "));	switch(hp->tcvr_type) {	case none:		/* Cannot operate if we don't know the transceiver type! */		HMD(("AAIEEE no transceiver type, EAGAIN"));		return -EAGAIN;	case internal:		/* Using the MII buffers. */		HMD(("internal, using MII, "));		hme_write32(hp, bregs + BMAC_XIFCFG, 0);		break;	case external:		/* Not using the MII, disable it. */		HMD(("external, disable MII, "));		hme_write32(hp, bregs + BMAC_XIFCFG, BIGMAC_XCFG_MIIDISAB);		break;	};	if (happy_meal_tcvr_reset(hp, tregs))		return -EAGAIN;	/* Reset the Happy Meal Big Mac transceiver and the receiver. */	HMD(("tx/rx reset, "));	happy_meal_tx_reset(hp, bregs);	happy_meal_rx_reset(hp, bregs);	/* Set jam size and inter-packet gaps to reasonable defaults. */	HMD(("jsize/ipg1/ipg2, "));	hme_write32(hp, bregs + BMAC_JSIZE, DEFAULT_JAMSIZE);	hme_write32(hp, bregs + BMAC_IGAP1, DEFAULT_IPG1);	hme_write32(hp, bregs + BMAC_IGAP2, DEFAULT_IPG2);	/* Load up the MAC address and random seed. */	HMD(("rseed/macaddr, "));	/* The docs recommend to use the 10LSB of our MAC here. */	hme_write32(hp, bregs + BMAC_RSEED, ((e[5] | e[4]<<8)&0x3ff));	hme_write32(hp, bregs + BMAC_MACADDR2, ((e[4] << 8) | e[5]));	hme_write32(hp, bregs + BMAC_MACADDR1, ((e[2] << 8) | e[3]));	hme_write32(hp, bregs + BMAC_MACADDR0, ((e[0] << 8) | e[1]));	HMD(("htable, "));	if ((hp->dev->flags & IFF_ALLMULTI) ||	    (hp->dev->mc_count > 64)) {		hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff);		hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff);		hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff);		hme_write32(hp, bregs + BMAC_HTABLE3, 0xffff);	} else if ((hp->dev->flags & IFF_PROMISC) == 0) {		u16 hash_table[4];		struct dev_mc_list *dmi = hp->dev->mc_list;		char *addrs;		int i, j, bit, byte;		u32 crc, poly = CRC_POLYNOMIAL_LE;		for (i = 0; i < 4; i++)			hash_table[i] = 0;		for (i = 0; i < hp->dev->mc_count; i++) {			addrs = dmi->dmi_addr;			dmi = dmi->next;			if (!(*addrs & 1))				continue;			crc = 0xffffffffU;			for (byte = 0; byte < 6; byte++) {				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {					int test;					test = ((bit ^ crc) & 0x01);					crc >>= 1;					if (test)						crc = crc ^ poly;				}			}			crc >>= 26;			hash_table[crc >> 4] |= 1 << (crc & 0xf);		}		hme_write32(hp, bregs + BMAC_HTABLE0, hash_table[0]);		hme_write32(hp, bregs + BMAC_HTABLE1, hash_table[1]);		hme_write32(hp, bregs + BMAC_HTABLE2, hash_table[2]);		hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]);	} else {		hme_write32(hp, bregs + BMAC_HTABLE3, 0);		hme_write32(hp, bregs + BMAC_HTABLE2, 0);		hme_write32(hp, bregs + BMAC_HTABLE1, 0);		hme_write32(hp, bregs + BMAC_HTABLE0, 0);	}	/* Set the RX and TX ring ptrs. */	HMD(("ring ptrs rxr[%08x] txr[%08x]\n",	     (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)),	     (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))));	hme_write32(hp, erxregs + ERX_RING,		    (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)));	hme_write32(hp, etxregs + ETX_RING,		    (hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)));	/* Set the supported burst sizes. */	HMD(("happy_meal_init: old[%08x] bursts<",	     hme_read32(hp, gregs + GREG_CFG)));#ifndef __sparc__	/* It is always PCI and can handle 64byte bursts. */	hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64);#else	if ((hp->happy_bursts & DMA_BURST64) &&	    ((hp->happy_flags & HFLAG_PCI) != 0#ifdef CONFIG_SBUS	     || sbus_can_burst64(hp->happy_dev)#endif	     || 0)) {		u32 gcfg = GREG_CFG_BURST64;		/* I have no idea if I should set the extended		 * transfer mode bit for Cheerio, so for now I		 * do not.  -DaveM		 */#ifdef CONFIG_SBUS		if ((hp->happy_flags & HFLAG_PCI) == 0 &&		    sbus_can_dma_64bit(hp->happy_dev)) {			sbus_set_sbus64(hp->happy_dev,					hp->happy_bursts);			gcfg |= GREG_CFG_64BIT;		}#endif		HMD(("64>"));		hme_write32(hp, gregs + GREG_CFG, gcfg);	} else if (hp->happy_bursts & DMA_BURST32) {		HMD(("32>"));		hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST32);	} else if (hp->happy_bursts & DMA_BURST16) {		HMD(("16>"));		hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST16);	} else {		HMD(("XXX>"));		hme_write32(hp, gregs + GREG_CFG, 0);	}#endif /* __sparc__ */	/* Turn off interrupts we do not want to hear. */	HMD((", enable global interrupts, "));	hme_write32(hp, gregs + GREG_IMASK,		    (GREG_IMASK_GOTFRAME | GREG_IMASK_RCNTEXP |		     GREG_IMASK_SENTFRAME | GREG_IMASK_TXPERR));	/* Set the transmit ring buffer size. */	HMD(("tx rsize=%d oreg[%08x], ", (int)TX_RING_SIZE,	     hme_read32(hp, etxregs + ETX_RSIZE)));	hme_write32(hp, etxregs + ETX_RSIZE, (TX_RING_SIZE >> ETX_RSIZE_SHIFT) - 1);	/* Enable transmitter DVMA. */	HMD(("tx dma enable old[%08x], ",	     hme_read32(hp, etxregs + ETX_CFG)));	hme_write32(hp, etxregs + ETX_CFG,		    hme_read32(hp, etxregs + ETX_CFG) | ETX_CFG_DMAENABLE);	/* This chip really rots, for the receiver sometimes when you	 * write to it's control registers not all the bits get there	 * properly.  I cannot think of a sane way to provide complete	 * coverage for this hardware bug yet.	 */	HMD(("erx regs bug old[%08x]\n",	     hme_read32(hp, erxregs + ERX_CFG)));	hme_write32(hp, erxregs + ERX_CFG, ERX_CFG_DEFAULT(RX_OFFSET));	regtmp = hme_read32(hp, erxregs + ERX_CFG);	hme_write32(hp, erxregs + ERX_CFG, ERX_CFG_DEFAULT(RX_OFFSET));	if (hme_read32(hp, erxregs + ERX_CFG) != ERX_CFG_DEFAULT(RX_OFFSET)) {		printk(KERN_ERR "happy meal: Eieee, rx config register gets greasy fries.\n");		printk(KERN_ERR "happy meal: Trying to set %08x, reread gives %08x\n",		       ERX_CFG_DEFAULT(RX_OFFSET), regtmp);		/* XXX Should return failure here... */	}	/* Enable Big Mac hash table filter. */	HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ",	     hme_read32(hp, bregs + BMAC_RXCFG)));	rxcfg = BIGMAC_RXCFG_HENABLE;	if (hp->dev->flags & IFF_PROMISC)		rxcfg |= BIGMAC_RXCFG_PMISC;	hme_write32(hp, bregs + BMAC_RXCFG, rxcfg);	/* Let the bits settle in the chip. */	udelay(10);	/* Ok, configure the Big Mac transmitter. */	HMD(("BIGMAC init, "));	regtmp = 0;	if (hp->happy_flags & HFLAG_FULL)		regtmp |= BIGMAC_TXCFG_FULLDPLX;	hme_write32(hp, bregs + BMAC_TXCFG, regtmp | BIGMAC_TXCFG_DGIVEUP);	/* Enable the output drivers no matter what. */	regtmp = BIGMAC_XCFG_ODENABLE;	/* If card can do lance mode, enable it. */	if (hp->happy_flags & HFLAG_LANCE)		regtmp |= (DEFAULT_IPG0 << 5) | BIGMAC_XCFG_LANCE;	/* Disable the MII buffers if using external transceiver. */	if (hp->tcvr_type == external)		regtmp |= BIGMAC_XCFG_MIIDISAB;	HMD(("XIF config old[%08x], ",	     hme_read32(hp, bregs + BMAC_XIFCFG)));	hme_write32(hp, bregs + BMAC_XIFCFG, regtmp);	/* Start things up. */	HMD(("tx old[%08x] and rx [%08x] ON!\n",	     hme_read32(hp, bregs + BMAC_TXCFG),	     hme_read32(hp, bregs + BMAC_RXCFG)));	hme_write32(hp, bregs + BMAC_TXCFG,		    hme_read32(hp, bregs + BMAC_TXCFG) | BIGMAC_TXCFG_ENABLE);	hme_write32(hp, bregs + BMAC_RXCFG,		    hme_read32(hp, bregs + BMAC_RXCFG) | BIGMAC_RXCFG_ENABLE);	/* Get the autonegotiation started, and the watch timer ticking. */	happy_meal_begin_auto_negotiation(hp, tregs, NULL);	/* Success. */	return 0;}static void happy_meal_set_initial_advertisement(struct happy_meal *hp){	unsigned long tregs	= hp->tcvregs;	unsigned long bregs	= hp->bigmacregs;	unsigned long gregs	= hp->gregs;	happy_meal_stop(hp, gregs);	hme_write32(hp, tregs + TCVR_IMASK, 0xffff);	if (hp->happy_flags & HFLAG_FENABLE)		hme_write32(hp, tregs + TCVR_CFG,			    hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_BENABLE));	else		hme_write32(hp, tregs + TCVR_CFG,			    hme_read32(hp, tregs + TCVR_CFG) | TCV_CFG_BENABLE);	happy_meal_transceiver_check(hp, tregs);	switch(hp->tcvr_type) {	case none:		return;	case internal:		hme_write32(hp, bregs + BMAC_XIFCFG, 0);		break;	case external:		hme_write32(hp, bregs + BMAC_XIFCFG, BIGMAC_XCFG_MIIDISAB);		break;	};	if (happy_meal_tcvr_reset(hp, tregs))		return;	/* Latch PHY registers as of now. */	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);	/* Advertise everything we can support. */	if (hp->sw_bmsr & BMSR_10HALF)		hp->sw_advertise |= (ADVERTISE_10HALF);	else		hp->sw_advertise &= ~(ADVERTISE_10HALF);	if (hp->sw_bmsr & BMSR_10FULL)		hp->sw_advertise |= (ADVERTISE_10FULL);	else		hp->sw_advertise &= ~(ADVERTISE_10FULL);	if (hp->sw_bmsr & BMSR_100HALF)		hp->sw_advertise |= (ADVERTISE_100HALF);	else		hp->sw_advertise &= ~(ADVERTISE_100HALF);	if (hp->sw_bmsr & BMSR_100FULL)		hp->sw_advertise |= (ADVERTISE_100FULL);	else		hp->sw_advertise &= ~(ADVERTISE_100FULL);	/* Update the PHY advertisement register. */	happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise);}/* Once status is latched (by happy_meal_interrupt) it is cleared by * the hardware, so we cannot re-read it and get a correct value.

⌨️ 快捷键说明

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