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

📄 sunhme.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
 * the hardware, so we cannot re-read it and get a correct value. * * hp->happy_lock must be held */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 incoming 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);		return 1;	}	return 0;}/* hp->happy_lock must be held */static void happy_meal_mif_interrupt(struct happy_meal *hp){	void __iomem *tregs = hp->tcvregs;	printk(KERN_INFO "%s: Link status change.\n", hp->dev->name);	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);	hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_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, MII_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)#endif/* hp->happy_lock must be held */static 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;	elem = hp->tx_old;	TXD(("TX<"));	while (elem != hp->tx_new) {		struct sk_buff *skb;		u32 flags, dma_addr, dma_len;		int frag;		TXD(("[%d]", elem));		this = &txbase[elem];		flags = hme_read_desc32(hp, &this->tx_flags);		if (flags & TXFLAG_OWN)			break;		skb = hp->tx_skbs[elem];		if (skb_shinfo(skb)->nr_frags) {			int last;			last = elem + skb_shinfo(skb)->nr_frags;			last &= (TX_RING_SIZE - 1);			flags = hme_read_desc32(hp, &txbase[last].tx_flags);			if (flags & TXFLAG_OWN)				break;		}		hp->tx_skbs[elem] = NULL;		hp->net_stats.tx_bytes += skb->len;		for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {			dma_addr = hme_read_desc32(hp, &this->tx_addr);			dma_len = hme_read_desc32(hp, &this->tx_flags);			dma_len &= TXFLAG_SIZE;			hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE);			elem = NEXT_TX(elem);			this = &txbase[elem];		}		dev_kfree_skb_irq(skb);		hp->net_stats.tx_packets++;	}	hp->tx_old = elem;	TXD((">"));	if (netif_queue_stopped(dev) &&	    TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1))		netif_wake_queue(dev);}#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. * * hp->happy_lock must be held */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_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE);			memcpy(copy_skb->data, skb->data, len);			hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE);			/* 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... */		skb->csum = ntohs(csum ^ 0xffff);		skb->ip_summed = CHECKSUM_HW;		RXD(("len=%d csum=%4x]", len, csum));		skb->protocol = eth_type_trans(skb, dev);		netif_rx(skb);		dev->last_rx = jiffies;		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 irqreturn_t 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  = dev->priv;	u32 happy_status       = hme_read32(hp, hp->gregs + GREG_STAT);	HMD(("happy_meal_interrupt: status=%08x ", happy_status));	spin_lock(&hp->happy_lock);	if (happy_status & GREG_STAT_ERRORS) {		HMD(("ERRORS "));		if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status))			goto out;	}	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"));out:	spin_unlock(&hp->happy_lock);	return IRQ_HANDLED;}#ifdef CONFIG_SBUSstatic irqreturn_t 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  = 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;		spin_lock(&hp->happy_lock);		if (happy_status & GREG_STAT_ERRORS) {			HMD(("ERRORS "));			if (happy_meal_is_not_so_happy(hp, happy_status))				goto next;		}		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);		}	next:		spin_unlock(&hp->happy_lock);	}	HMD(("done\n"));	return IRQ_HANDLED;}#endifstatic int happy_meal_open(struct net_device *dev){	struct happy_meal *hp = 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, dev->name, (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"));	spin_lock_irq(&hp->happy_lock);	res = happy_meal_init(hp);	spin_unlock_irq(&hp->happy_lock);	if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO)

⌨️ 快捷键说明

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