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

📄 sunhme.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 */static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status){	int reset = 0;		/* Only print messages for non-counter related interrupts. */	if (status & (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(KERN_ERR "%s: Error interrupt for happy meal, status = %08x\n",		       hp->dev->name, status);	if (status & GREG_STAT_RFIFOVF) {		/* Receive FIFO overflow is harmless and the hardware will take		   care of it, just some packets are lost. Who cares. */		printk(KERN_DEBUG "%s: Happy Meal receive FIFO overflow.\n", hp->dev->name);	}	if (status & GREG_STAT_STSTERR) {		/* BigMAC SQE link test failed. */		printk(KERN_ERR "%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(KERN_ERR "%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(KERN_ERR "%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(KERN_ERR "%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(KERN_ERR "%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(KERN_ERR "%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(KERN_ERR "%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(KERN_ERR "%s: Happy Meal register access SBUS slave (%s) error.\n",		       hp->dev->name,		       (status & GREG_STAT_SLVPERR) ? "parity" : "generic");		reset = 1;	}	if (reset) {		printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name);		happy_meal_init(hp, 1);		return 1;	}	return 0;}static void happy_meal_mif_interrupt(struct happy_meal *hp){	unsigned long tregs = hp->tcvregs;	printk(KERN_INFO "%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(KERN_INFO "%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(KERN_INFO "%s: Switching to 100MBps at half duplex.", hp->dev->name);		hp->sw_bmcr |= BMCR_SPEED100;	} else if (hp->sw_lpa & LPA_10FULL) {		printk(KERN_INFO "%s: Switching to 10MBps at full duplex.", hp->dev->name);		hp->sw_bmcr |= BMCR_FULLDPLX;	} else {		printk(KERN_INFO "%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 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;	struct net_device *dev = hp->dev;	int elem;	spin_lock(&hp->happy_lock);	elem = hp->tx_old;	TXD(("TX<"));	while (elem != hp->tx_new) {		struct sk_buff *skb;		u32 flags, dma_addr;		TXD(("[%d]", elem));		this = &txbase[elem];		flags = hme_read_desc32(hp, &this->tx_flags);		if (flags & TXFLAG_OWN)			break;		dma_addr = hme_read_desc32(hp, &this->tx_addr);		skb = hp->tx_skbs[elem];		hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE);		hp->tx_skbs[elem] = NULL;		hp->net_stats.tx_bytes += skb->len;		dev_kfree_skb_irq(skb);		hp->net_stats.tx_packets++;		elem = NEXT_TX(elem);	}	hp->tx_old = elem;	TXD((">"));	if (netif_queue_stopped(dev) &&	    TX_BUFFS_AVAIL(hp) > 0)		netif_wake_queue(dev);	spin_unlock(&hp->happy_lock);}#ifdef RXDEBUG#define RXD(x) printk x#else#define RXD(x)#endif/* Originally I used to handle the allocation failure by just giving back just * that one ring buffer to the happy meal.  Problem is that usually when that * condition is triggered, the happy meal expects you to do something reasonable * with all of the packets it has DMA'd in.  So now I just drop the entire * ring when we cannot get a new skb and give them all back to the happy meal, * maybe things will be "happier" now. */static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev){	struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0];	struct happy_meal_rxd *this;	int elem = hp->rx_new, drops = 0;	u32 flags;	RXD(("RX<"));	this = &rxbase[elem];	while (!((flags = hme_read_desc32(hp, &this->rx_flags)) & RXFLAG_OWN)) {		struct sk_buff *skb;		int len = flags >> 16;		u16 csum = flags & RXFLAG_CSUM;		u32 dma_addr = hme_read_desc32(hp, &this->rx_addr);		RXD(("[%d ", elem));		/* Check for errors. */		if ((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) {			RXD(("ERR(%08x)]", flags));			hp->net_stats.rx_errors++;			if (len < ETH_ZLEN)				hp->net_stats.rx_length_errors++;			if (len & (RXFLAG_OVERFLOW >> 16)) {				hp->net_stats.rx_over_errors++;				hp->net_stats.rx_fifo_errors++;			}			/* Return it to the Happy meal. */	drop_it:			hp->net_stats.rx_dropped++;			hme_write_rxd(hp, this,				      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),				      dma_addr);			goto next;		}		skb = hp->rx_skbs[elem];		if (len > RX_COPY_THRESHOLD) {			struct sk_buff *new_skb;			/* Now refill the entry, if we can. */			new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);			if (new_skb == NULL) {				drops++;				goto drop_it;			}			hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);			hp->rx_skbs[elem] = new_skb;			new_skb->dev = dev;			skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));			hme_write_rxd(hp, this,				      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),				      hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));			skb_reserve(new_skb, RX_OFFSET);			/* Trim the original skb for the netif. */			skb_trim(skb, len);		} else {			struct sk_buff *copy_skb = dev_alloc_skb(len + 2);			if (copy_skb == NULL) {				drops++;				goto drop_it;			}			copy_skb->dev = dev;			skb_reserve(copy_skb, 2);			skb_put(copy_skb, len);			hme_dma_sync(hp, dma_addr, len, DMA_FROMDEVICE);			memcpy(copy_skb->data, skb->data, len);			/* Reuse original ring buffer. */			hme_write_rxd(hp, this,				      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),				      dma_addr);			skb = copy_skb;		}		/* This card is _fucking_ hot... */		if (!(csum ^ 0xffff))			skb->ip_summed = CHECKSUM_UNNECESSARY;		else			skb->ip_summed = CHECKSUM_NONE;		RXD(("len=%d csum=%4x]", len, csum));		skb->protocol = eth_type_trans(skb, dev);		netif_rx(skb);		hp->net_stats.rx_packets++;		hp->net_stats.rx_bytes += len;	next:		elem = NEXT_RX(elem);		this = &rxbase[elem];	}	hp->rx_new = elem;	if (drops)		printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name);	RXD((">"));}static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = (struct net_device *) dev_id;	struct happy_meal *hp  = (struct happy_meal *) dev->priv;	u32 happy_status       = hme_read32(hp, hp->gregs + GREG_STAT);	HMD(("happy_meal_interrupt: status=%08x ", happy_status));	if (happy_status & GREG_STAT_ERRORS) {		HMD(("ERRORS "));		if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status))			return;	}	if (happy_status & GREG_STAT_MIFIRQ) {		HMD(("MIFIRQ "));		happy_meal_mif_interrupt(hp);	}	if (happy_status & GREG_STAT_TXALL) {		HMD(("TXALL "));		happy_meal_tx(hp);	}	if (happy_status & GREG_STAT_RXTOHOST) {		HMD(("RXTOHOST "));		happy_meal_rx(hp, dev);	}	HMD(("done\n"));}#ifdef CONFIG_SBUSstatic void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs){	struct quattro *qp = (struct quattro *) cookie;	int i;	for (i = 0; i < 4; i++) {		struct net_device *dev = qp->happy_meals[i];		struct happy_meal *hp  = (struct happy_meal *) dev->priv;		u32 happy_status       = hme_read32(hp, hp->gregs + GREG_STAT);		HMD(("quattro_interrupt: status=%08x ", happy_status));		if (!(happy_status & (GREG_STAT_ERRORS |				      GREG_STAT_MIFIRQ |				      GREG_STAT_TXALL |				      GREG_STAT_RXTOHOST)))			continue;		if (happy_status & GREG_STAT_ERRORS) {			HMD(("ERRORS "));			if (happy_meal_is_not_so_happy(hp, happy_status))				break;		}		if (happy_status & GREG_STAT_MIFIRQ) {			HMD(("MIFIRQ "));			happy_meal_mif_interrupt(hp);		}		if (happy_status & GREG_STAT_TXALL) {			HMD(("TXALL "));			happy_meal_tx(hp);		}		if (happy_status & GREG_STAT_RXTOHOST) {			HMD(("RXTOHOST "));			happy_meal_rx(hp, dev);		}	}	HMD(("done\n"));}#endifstatic int happy_meal_open(struct net_device *dev){	struct happy_meal *hp = (struct happy_meal *) dev->priv;	int res;	HMD(("happy_meal_open: "));	/* On SBUS Quattro QFE cards, all hme interrupts are concentrated	 * into a single source which we register handling at probe time.	 */	if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) {		if (request_irq(dev->irq, &happy_meal_interrupt,				SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {			HMD(("EAGAIN\n"));#ifdef __sparc__			printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",			       __irq_itoa(dev->irq));#else			printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n",			       dev->irq);#endif			return -EAGAIN;		}	}	HMD(("to happy_meal_init\n"));	res = happy_meal_init(hp, 0);	if (!res) {		MOD_INC_USE_COUNT;	}	return res;}static int happy_meal_close(struct net_device *dev){	struct happy_meal *hp = (struct happy_meal *) dev->priv;	happy_meal_stop(hp, hp->gregs);	happy_meal_clean_rings(hp);	/* If auto-negotiation timer is running, kill it. */	del_timer(&hp->happy_timer);	/* On Quattro QFE cards, all hme interrupts are concentrated	 * into a single source which we register handling at probe	 * time and never unregister.	 */	if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO)		free_irq(dev->irq, (void *)dev);	MOD_DEC_USE_COUNT;	return 0;}#ifdef SXDEBUG#define SXD(x) printk x#else#define SXD(x)#endif#ifdef CONFIG_SBUSstatic void happy_meal_tx_timeout(struct net_device *dev){	struct happy_meal *hp = (struct happy_meal *) dev->priv;	printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);	tx_dump_log();	printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,		hme_read32(hp, h

⌨️ 快捷键说明

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