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

📄 sunhme.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		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->htable0, hash_table[0]);		hme_write32(hp, &bregs->htable1, hash_table[1]);		hme_write32(hp, &bregs->htable2, hash_table[2]);		hme_write32(hp, &bregs->htable3, hash_table[3]);	} else {		hme_write32(hp, &bregs->htable3, 0);		hme_write32(hp, &bregs->htable2, 0);		hme_write32(hp, &bregs->htable1, 0);		hme_write32(hp, &bregs->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->rx_ring,		    (hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)));	hme_write32(hp, &etxregs->tx_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->cfg)));#ifdef __sparc_v9__	/* XXX Can sun4d do these too? */	if(hp->happy_bursts & DMA_BURST64) {		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		 */		if((hp->happy_flags & HFLAG_PCI) == 0) {			mmu_set_sbus64(hp->happy_sbus_dev,				       hp->happy_bursts);			gcfg |= GREG_CFG_64BIT;		}		HMD(("64>"));		hme_write32(hp, &gregs->cfg, gcfg);	} else#endif	if(hp->happy_bursts & DMA_BURST32) {		HMD(("32>"));		hme_write32(hp, &gregs->cfg, GREG_CFG_BURST32);	} else if(hp->happy_bursts & DMA_BURST16) {		HMD(("16>"));		hme_write32(hp, &gregs->cfg, GREG_CFG_BURST16);	} else {		HMD(("XXX>"));		hme_write32(hp, &gregs->cfg, 0);	}	/* Turn off interrupts we do not want to hear. */	HMD((", enable global interrupts, "));	hme_write32(hp, &gregs->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->tx_rsize)));	hme_write32(hp, &etxregs->tx_rsize, (TX_RING_SIZE >> ETX_RSIZE_SHIFT) - 1);	/* Enable transmitter DVMA. */	HMD(("tx dma enable old[%08x], ",	     hme_read32(hp, &etxregs->cfg)));	hme_write32(hp, &etxregs->cfg,		    hme_read32(hp, &etxregs->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->cfg)));	hme_write32(hp, &erxregs->cfg, ERX_CFG_DEFAULT(RX_OFFSET));	regtmp = hme_read32(hp, &erxregs->cfg);	hme_write32(hp, &erxregs->cfg, ERX_CFG_DEFAULT(RX_OFFSET));	if(hme_read32(hp, &erxregs->cfg) != ERX_CFG_DEFAULT(RX_OFFSET)) {		printk("happy meal: Eieee, rx config register gets greasy fries.\n");		printk("happy meal: Trying to set %08x, reread gives %08lx\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->rx_cfg)));	rxcfg = BIGMAC_RXCFG_HENABLE;	if(hp->dev->flags & IFF_PROMISC)		rxcfg |= BIGMAC_RXCFG_PMISC;	hme_write32(hp, &bregs->rx_cfg, 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->tx_cfg, 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->xif_cfg)));	hme_write32(hp, &bregs->xif_cfg, regtmp);	/* Start things up. */	HMD(("tx old[%08x] and rx [%08x] ON!\n",	     hme_read32(hp, &bregs->tx_cfg),	     hme_read32(hp, &bregs->rx_cfg)));	hme_write32(hp, &bregs->tx_cfg,		    hme_read32(hp, &bregs->tx_cfg) | BIGMAC_TXCFG_ENABLE);	hme_write32(hp, &bregs->rx_cfg,		    hme_read32(hp, &bregs->rx_cfg) | 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){	struct hmeal_tcvregs *tregs	= hp->tcvregs;	struct hmeal_bigmacregs *bregs	= hp->bigmacregs;	struct hmeal_gregs *gregs	= hp->gregs;	happy_meal_stop(hp, gregs);	hme_write32(hp, &tregs->int_mask, 0xffff);	if(hp->happy_flags & HFLAG_FENABLE)		hme_write32(hp, &tregs->cfg,			    hme_read32(hp, &tregs->cfg) & ~(TCV_CFG_BENABLE));	else		hme_write32(hp, &tregs->cfg,			    hme_read32(hp, &tregs->cfg) | TCV_CFG_BENABLE);	happy_meal_transceiver_check(hp, tregs);	switch(hp->tcvr_type) {	case none:		return;	case internal:		hme_write32(hp, &bregs->xif_cfg, 0);		break;	case external:		hme_write32(hp, &bregs->xif_cfg, 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. */static int happy_meal_is_not_so_happy(struct happy_meal *hp,				      struct hmeal_gregs *gregs,				      unsigned long status){	int reset = 0;	/* Only print messages for non-counter related interrupts. */	if(status & (GREG_STAT_RFIFOVF | GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND |		     GREG_STAT_MAXPKTERR | GREG_STAT_RXERR |		     GREG_STAT_RXPERR | GREG_STAT_RXTERR | GREG_STAT_EOPERR |		     GREG_STAT_MIFIRQ | GREG_STAT_TXEACK | GREG_STAT_TXLERR |		     GREG_STAT_TXPERR | GREG_STAT_TXTERR | GREG_STAT_SLVERR |		     GREG_STAT_SLVPERR))		printk("%s: Error interrupt for happy meal, status = %08lx\n",		       hp->dev->name, status);	if(status & GREG_STAT_RFIFOVF) {		/* The receive FIFO overflowwed, usually a DMA error. */		printk("%s: Happy Meal receive FIFO overflow.\n", hp->dev->name);		reset = 1;	}	if(status & GREG_STAT_STSTERR) {		/* BigMAC SQE link test failed. */		printk("%s: Happy Meal BigMAC SQE test failed.\n", hp->dev->name);		reset = 1;	}	if(status & GREG_STAT_TFIFO_UND) {		/* Transmit FIFO underrun, again DMA error likely. */		printk("%s: Happy Meal transmitter FIFO underrun, DMA error.\n",		       hp->dev->name);		reset = 1;	}	if(status & GREG_STAT_MAXPKTERR) {		/* Driver error, tried to transmit something larger		 * than ethernet max mtu.		 */		printk("%s: Happy Meal MAX Packet size error.\n", hp->dev->name);		reset = 1;	}	if(status & GREG_STAT_NORXD) {		/* This is harmless, it just means the system is		 * quite loaded and the incomming packet rate was		 * faster than the interrupt handler could keep up		 * with.		 */		printk(KERN_INFO "%s: Happy Meal out of receive "		       "descriptors, packet dropped.\n",		       hp->dev->name);	}	if(status & (GREG_STAT_RXERR|GREG_STAT_RXPERR|GREG_STAT_RXTERR)) {		/* All sorts of DMA receive errors. */		printk("%s: Happy Meal rx DMA errors [ ", hp->dev->name);		if(status & GREG_STAT_RXERR)			printk("GenericError ");		if(status & GREG_STAT_RXPERR)			printk("ParityError ");		if(status & GREG_STAT_RXTERR)			printk("RxTagBotch ");		printk("]\n");		reset = 1;	}	if(status & GREG_STAT_EOPERR) {		/* Driver bug, didn't set EOP bit in tx descriptor given		 * to the happy meal.		 */		printk("%s: EOP not set in happy meal transmit descriptor!\n",		       hp->dev->name);		reset = 1;	}	if(status & GREG_STAT_MIFIRQ) {		/* MIF signalled an interrupt, were we polling it? */		printk("%s: Happy Meal MIF interrupt.\n", hp->dev->name);	}	if(status &	   (GREG_STAT_TXEACK|GREG_STAT_TXLERR|GREG_STAT_TXPERR|GREG_STAT_TXTERR)) {		/* All sorts of transmit DMA errors. */		printk("%s: Happy Meal tx DMA errors [ ", hp->dev->name);		if(status & GREG_STAT_TXEACK)			printk("GenericError ");		if(status & GREG_STAT_TXLERR)			printk("LateError ");		if(status & GREG_STAT_TXPERR)			printk("ParityErro ");		if(status & GREG_STAT_TXTERR)			printk("TagBotch ");		printk("]\n");		reset = 1;	}	if(status & (GREG_STAT_SLVERR|GREG_STAT_SLVPERR)) {		/* Bus or parity error when cpu accessed happy meal registers		 * or it's internal FIFO's.  Should never see this.		 */		printk("%s: Happy Meal register access SBUS slave (%s) error.\n",		       hp->dev->name,		       (status & GREG_STAT_SLVPERR) ? "parity" : "generic");		reset = 1;	}	if(reset) {		printk("%s: Resetting...\n", hp->dev->name);		happy_meal_init(hp, 1);		return 1;	}	return 0;}static inline void happy_meal_mif_interrupt(struct happy_meal *hp,					    struct hmeal_gregs *gregs,					    struct hmeal_tcvregs *tregs){	printk("%s: Link status change.\n", hp->dev->name);	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);	hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);	/* Use the fastest transmission protocol possible. */	if(hp->sw_lpa & LPA_100FULL) {		printk("%s: Switching to 100Mbps at full duplex.", hp->dev->name);		hp->sw_bmcr |= (BMCR_FULLDPLX | BMCR_SPEED100);	} else if(hp->sw_lpa & LPA_100HALF) {		printk("%s: Switching to 100MBps at half duplex.", hp->dev->name);		hp->sw_bmcr |= BMCR_SPEED100;	} else if(hp->sw_lpa & LPA_10FULL) {		printk("%s: Switching to 10MBps at full duplex.", hp->dev->name);		hp->sw_bmcr |= BMCR_FULLDPLX;	} else {		printk("%s: Using 10Mbps at half duplex.", hp->dev->name);	}	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);	/* Finally stop polling and shut up the MIF. */	happy_meal_poll_stop(hp, tregs);}#ifdef TXDEBUG#define TXD(x) printk x#else#define TXD(x)#endifstatic inline void happy_meal_tx(struct happy_meal *hp){	struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];	struct happy_meal_txd *this;	int elem = hp->tx_old;	TXD(("TX<"));	while(elem != hp->tx_new) {		struct sk_buff *skb;		TXD(("[%d]", elem));		this = &txbase[elem];		if(this->tx_flags & TXFLAG_OWN)			break;		skb = hp->tx_skbs[elem];		hp->tx_skbs[elem] = NULL;		hp->net_stats.tx_bytes+=skb->len;				dev_kfree_skb(skb);		hp->net_stats.tx_packets++;		elem = NEXT_TX(elem);	}	hp->tx_old = elem;	TXD((">"));}#ifdef CONFIG_PCIstatic inline void pci_happy_meal_tx(struct happy_meal *hp){	struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];	struct happy_meal_txd *this;	int elem = hp->tx_old;	TXD(("TX<"));	while(elem != hp->tx_new) {		struct sk_buff *skb;		unsigned int flags;		TXD(("[%d]", elem));		this = &txbase[elem];#ifdef  __sparc_v9__		__asm__ __volatile__("lduwa [%1] %2, %0"				     : "=r" (flags)				     : "r" (&this->tx_flags), "i" (ASI_PL));#else		flags = flip_dword(this->tx_flags);#endif		if(flags & TXFLAG_OWN)			break;		skb = hp->tx_skbs[elem];		hp->tx_skbs[elem] = NULL;		hp->net_stats.tx_bytes+=skb->len;				dev_kfree_skb(skb);		hp->net_stats.tx_packets++;		elem = NEXT_TX(elem);	}	hp->tx_old = elem;	TXD((">"));}#endif#ifndef __sparc_v9__static inline void sun4c_happy_meal_tx(struct happy_meal *hp){	struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];	struct happy_meal_txd *this;	int elem = hp->tx_old;	TXD(("TX<"));	while(elem != hp->tx_new) {		TXD(("[%d]", elem));		this = &txbase[elem];		if(this->tx_flags & TXFLAG_OWN)			break;		hp->net_stats.tx_packets++;		elem = NEXT_TX(elem);	}	hp->tx_old = elem;	TXD((">"));}

⌨️ 快捷键说明

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