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

📄 1022.ethernet.patch

📁 sm86xx内核源包括补丁( GPL )的
💻 PATCH
📖 第 1 页 / 共 5 页
字号:
diff -Naur --exclude=CVS --exclude='*.o' --exclude='*.a' --exclude='*.so' --exclude='*.elf' --exclude=System.map --exclude=Makefile.d --exclude='*log' --exclude='*log2' --exclude='*~' --exclude='.*~' --exclude='.#*' --exclude='*.bak' --exclude='*.orig' --exclude='*.rej' --exclude='core.[0-9]*' --exclude=.depend --exclude='.*.o.flags' --exclude='*.gz' --exclude=.depend --exclude='.*.o.flags' --exclude='*.gz' --exclude=vmlinux --exclude=vmlinux.bin --exclude=yamon-02.06-SIGMADESIGNS-01_el.bin linuxmips-2.4.30.ref/drivers/net/Config.in linuxmips-2.4.30/drivers/net/Config.in--- linuxmips-2.4.30.ref/drivers/net/Config.in	2007-06-11 10:36:00.000000000 -0700+++ linuxmips-2.4.30/drivers/net/Config.in	2007-06-11 10:40:45.000000000 -0700@@ -24,6 +24,12 @@ comment 'Ethernet (10 or 100Mbit)' bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET if [ "$CONFIG_NET_ETHERNET" = "y" ]; then+   if [ "$CONFIG_TANGO2" = "y" ]; then+      if [ "$CONFIG_TANGO2_ES4" = "y" -o "$CONFIG_TANGO2_ES6" = "y" ]; then+         tristate '  SMP863x Builtin Ethernet support' CONFIG_EM86XX_ENET+         tristate '  SMP863x Builtin Ethernet support (new driver)' CONFIG_EM86XX_ENET_NEW+      fi+   fi    if [ "$CONFIG_ARM" = "y" ]; then         dep_bool '  ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110       tristate '  Cirrus Logic CS8900A support' CONFIG_ARM_CIRRUSdiff -Naur --exclude=CVS --exclude='*.o' --exclude='*.a' --exclude='*.so' --exclude='*.elf' --exclude=System.map --exclude=Makefile.d --exclude='*log' --exclude='*log2' --exclude='*~' --exclude='.*~' --exclude='.#*' --exclude='*.bak' --exclude='*.orig' --exclude='*.rej' --exclude='core.[0-9]*' --exclude=.depend --exclude='.*.o.flags' --exclude='*.gz' --exclude=.depend --exclude='.*.o.flags' --exclude='*.gz' --exclude=vmlinux --exclude=vmlinux.bin --exclude=yamon-02.06-SIGMADESIGNS-01_el.bin linuxmips-2.4.30.ref/drivers/net/em86xx_enet.c linuxmips-2.4.30/drivers/net/em86xx_enet.c--- linuxmips-2.4.30.ref/drivers/net/em86xx_enet.c	1969-12-31 16:00:00.000000000 -0800+++ linuxmips-2.4.30/drivers/net/em86xx_enet.c	2007-06-11 10:40:45.000000000 -0700@@ -0,0 +1,1112 @@+/*+ * New driver for SMP863x builtin Ethernet mac+ *+ * This driver uses NAPI and generic linux MII support.+ *+ * Tx path limits the number of interrupt by reclaiming sent buffer in+ * a timer.  In case  the tx starts  to go  faster, it will  switch to+ * interrupt mode.+ *+ * Note that OOM condition is not handled correctly, and can leave the+ * rx path  in bad  shape. down/up the  interface should make  it work+ * again though. But anyway, it's not likely to happen.+ *+ * Copyright (C) 2005 Maxime Bizon <mbizon@freebox.fr>+ *+ * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation; either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program; if not, write to the Free Software+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.+ */++#include <linux/config.h>+#include <linux/kernel.h>+#include <linux/netdevice.h>+#include <linux/etherdevice.h>+#include <linux/spinlock.h>+#include <linux/interrupt.h>+#include <linux/signal.h>+#include <linux/sched.h>+#include <linux/module.h>+#include <linux/compatmac.h>+#include <linux/mm.h>+#include <linux/init.h>+#include <linux/timer.h>+#include <linux/mii.h>+#include <linux/ethtool.h>+#include <linux/crc32.h>+#include <linux/delay.h>++#include "em86xx_enet.h"++#define PFX	"em86xx_enet: "++static struct net_device *gdev;+static int gphy_id = -1;++/*+ * mdio read/write callback, can run from userspace or timer+ */+static __inline int enet_mdio_read(struct net_device *dev, int phy_id,+				   int location)+{+	int val;++	while (enet_readl(ENET_MAC_MIIAR) & MIIAR_BUSY);+	enet_writel(ENET_MAC_MIIAR, MIIAR_ADDR(phy_id) | MIIAR_REG(location));+	udelay(1);+	while (enet_readl(ENET_MAC_MIIAR) & MIIAR_BUSY);+	val = enet_readl(ENET_MAC_MIIDR);++	return val;+}++static void enet_mdio_write(struct net_device *dev, int phy_id,+				     int location, int val)+{+	enet_writel(ENET_MAC_MIIDR, val);+	enet_writel(ENET_MAC_MIIAR,+		    MIIAR_ADDR(phy_id) | MIIAR_REG(location) | MIIAR_WRITE);+	udelay(1);+	while (enet_readl(ENET_MAC_MIIAR) & MIIAR_BUSY);+}++/*+ * enable/disable interrupt helpers+ * need proper locks since we will call them from any context+ */+static __inline void enet_disable_interrupts(struct em86xx_enet_priv *priv,+					     int rx_only)+{+	unsigned long flags, val;++	spin_lock_irqsave(&priv->ier_lock, flags);+	if (rx_only) {+		val = enet_readl(ENET_DMA_IER);+		val &= ~IER_R;+		enet_writel(ENET_DMA_IER, val);+	} else+		enet_writel(ENET_DMA_IER, 0);+	spin_unlock_irqrestore(&priv->ier_lock, flags);+}++static __inline void enet_enable_interrupts(struct em86xx_enet_priv *priv,+					    int rx_only)+{+	unsigned long flags, val;++	spin_lock_irqsave(&priv->ier_lock, flags);+	if (rx_only) {+		val = enet_readl(ENET_DMA_IER);+		val |= IER_R;+		enet_writel(ENET_DMA_IER, val);+	} else+		enet_writel(ENET_DMA_IER, IER_NIS | IER_R | IER_T);+	spin_unlock_irqrestore(&priv->ier_lock, flags);+}+++/*+ * rx poll func, called by network core+ */+static int enet_poll(struct net_device *dev, int *budget)+{+	struct em86xx_enet_priv *priv;+	int limit, received;++	priv = netdev_priv(dev);++	/* calculate how many rx packet we are allowed to fetch */+	limit = *budget;+	if (*budget > dev->quota)+		limit = dev->quota;+	received = 0;++	/* process no more than "limit" done rx */+	do {+		volatile struct enet_rx_desc *rx;+		struct sk_buff *skb;+		uint32_t rdes0_cache;+		unsigned int len;++		rx = &priv->rx_descs[priv->last_rx_desc];++		/* we  need  multiple  read  on this  volatile,  avoid+		 * memory access at each time */+		rdes0_cache = rx->rdes0;+		if (rdes0_cache & RDES0_OWN) {+			break;+		}++		if (limit <= 0)+			break;+		--limit;++		if ((skb = priv->rx_skbs[priv->last_rx_desc]) != NULL) {++			/* we don't handle multipacket frame */+			if (!(rdes0_cache & RDES0_FIRST) ||+			    !(rdes0_cache & RDES0_LAST)) {+				/* we don't handle multipacket frame */+				priv->stats.rx_errors++;+				priv->stats.rx_length_errors++;+				goto rearm;+			}++			/* check for CRC */+			if (rdes0_cache & RDES0_CRC) {+				priv->stats.rx_errors++;+				priv->stats.rx_crc_errors++;+				goto rearm;+			}++			/* sanity check on len field */+			len = RDES0_FRAME_LEN(rdes0_cache);+			if (rdes0_cache & (RDES0_TOO_LONG | RDES0_TRUNC) ||+			    len > RX_BUF_SIZE) {+				priv->stats.rx_errors++;+				priv->stats.rx_length_errors++;+				goto rearm;+			}++			/* check remaining error */+			if (rdes0_cache & (RDES0_ERR_SUM | RDES0_COLLISION |+					   RDES0_WATCHDOG_TMOUT |+					   RDES0_MII_ERROR)) {+				priv->stats.rx_errors++;+				goto rearm;+			}++			/* ok, seems  valid, adjust skb  proto and len+			 * and give it to kernel */+			skb->dev = dev;+			skb_put(skb, len);+			skb->protocol = eth_type_trans(skb, dev);+			netif_receive_skb(skb);++			priv->stats.rx_packets++;+			priv->stats.rx_bytes += len;+			dev->last_rx = jiffies;+			priv->rx_skbs[priv->last_rx_desc] = NULL;+			/* we will realloc an skb for this slot */+		}++		skb = dev_alloc_skb(RX_BUF_SIZE + SKB_RESERVE_SIZE);+		if (unlikely(!skb))+			break;++		skb_reserve(skb, SKB_RESERVE_SIZE);+		rx->rdes2 = PHYSADDR(skb->data);+		dma_cache_inv((unsigned long)skb->data, RX_BUF_SIZE);+		priv->rx_skbs[priv->last_rx_desc] = skb;++rearm:+		/* rearm descriptor */+		wmb();+		rx->rdes0 = RDES0_OWN;+		priv->last_rx_desc++;+		priv->last_rx_desc &= (ENET_RX_DESC_COUNT - 1);+		received++;++	} while (1);++	dev->quota -= received;+	*budget -= received;++	if (limit <= 0) {+		/* breaked, but there is still work to do */+		return 1;+	}++        netif_rx_complete(dev);+	enet_enable_interrupts(priv, 1);++	return 0;+}++/*+ * tx reclaim func. Called by timer or tx done tasklet to reclaim sent+ * buffers.+ */+static void enet_tx_reclaim(unsigned long data)+{+	struct net_device *dev;+	struct em86xx_enet_priv *priv;+	volatile struct enet_tx_desc *tx;++	dev = (struct net_device *)data;+	priv = netdev_priv(dev);++	spin_lock(&priv->tx_lock);++	while (priv->free_tx_desc_count < ENET_TX_DESC_COUNT) {+		uint32_t tdes0_cache;+		struct sk_buff *skb;++		tx = &priv->tx_descs[priv->dirty_tx_desc];++		tdes0_cache = tx->tdes0;+		if (tdes0_cache & TDES0_OWN)+			break;++		skb = priv->tx_skbs[priv->dirty_tx_desc];+		priv->stats.tx_packets++;++		/* check  for  transmission  errors and  update  stats+		 * accordingly */+		if (tdes0_cache & (TDES0_ERR_SUM | TDES0_CARRIER_LOST |+				   TDES0_NO_CARRIER | TDES0_LATE_COLLISION |+				   TDES0_EXC_COLLISION | TDES0_HEARTBEAT |+				   TDES0_EXC_DEFERAL | TDES0_UNDERFLOW)) {+			priv->stats.tx_errors++;+		} else {+			priv->stats.tx_bytes += skb->len;+		}++		dev_kfree_skb(skb);+		priv->tx_skbs[priv->dirty_tx_desc] = NULL;+		priv->dirty_tx_desc++;+		priv->dirty_tx_desc %= ENET_TX_DESC_COUNT;+		priv->free_tx_desc_count++;+	}++	if (priv->free_tx_desc_count != 0 && netif_queue_stopped(dev))+		netif_wake_queue(dev);++	spin_unlock(&priv->tx_lock);+}++/*+ * tx done timer callback, just call tx_done and reschedule timer+ */+static void enet_tx_reclaim_timer(unsigned long data)+{+	struct net_device *dev;+	struct em86xx_enet_priv *priv;++	dev = (struct net_device *)data;+	priv = netdev_priv(dev);+	enet_tx_reclaim(data);++	priv->tx_reclaim_timer.expires = jiffies + TX_RECLAIM_TIMER_FREQ;+	add_timer(&priv->tx_reclaim_timer);+}+++/*+ * tx request callback+ */+static int enet_xmit(struct sk_buff *skb, struct net_device *dev)+{+	struct em86xx_enet_priv *priv;+	volatile struct enet_tx_desc *tx;+	unsigned long tdes1_cache;++	spin_lock(&priv->tx_lock);++	priv = netdev_priv(dev);+	tx = &priv->tx_descs[priv->next_tx_desc];++	/* make sure the next free tx desc is available */+	if (unlikely(priv->free_tx_desc_count == 0)) {+		/* no, this  should not happen since  queue is stopped+		 * before we run out of tx desc */+		printk(KERN_WARNING PFX "no free tx desc to handle pkt\n");+		dev_kfree_skb(skb);+		netif_stop_queue(dev);+		spin_unlock(&priv->tx_lock);+		return 0;+	}++	/* fill the tx desc with this skb address */+	tdes1_cache = (TDES1_FIRST | TDES1_LAST);+	if (priv->next_tx_desc == ENET_TX_DESC_COUNT - 1)+		tdes1_cache |= TDES1_TER;++	/* if we  start to  run low  on free tx  desc, then  enable tx+	 * interrupt to reclaim them faster */+	if (priv->free_tx_desc_count == ENET_TX_DESC_LOW) {+		tdes1_cache |= (TDES1_ENABLE_ISR);+	}+	tdes1_cache |= TDES1_TBS1(skb->len);++	tx->tdes1 = tdes1_cache;+	tx->tdes2 = PHYSADDR(skb->data);+	dma_cache_wback((unsigned long)skb->data, skb->len);++	/* keep a pointer to it for later and give it to dma  */+	priv->tx_skbs[priv->next_tx_desc] = skb;+	wmb();+	tx->tdes0 = TDES0_OWN;++	/* kick tx dma in case it was suspended */+	wmb();+	enet_writel(ENET_DMA_TPDR, 0x1);++	priv->next_tx_desc++;+	priv->next_tx_desc %= ENET_TX_DESC_COUNT;++	/* if next  tx descriptor is not  clean, then we  have to stop+	 * queue */+	if (unlikely(--priv->free_tx_desc_count == 0))+		netif_stop_queue(dev);++	spin_unlock(&priv->tx_lock);++	return 0;+}++/*+ * our  irq handler, just  ack it  and schedule  the right  tasklet to+ * handle this+ */+static irqreturn_t enet_isr(int irq, void *dev_id, struct pt_regs *regs)+{+	struct net_device *dev;+	struct em86xx_enet_priv *priv;+	unsigned long val;++	dev = (struct net_device *)dev_id;+	priv = netdev_priv(dev);++	/* fetch status & ack them */+	val = enet_readl(ENET_DMA_SR);+	enet_writel(ENET_DMA_SR, val);++	/* handle interrupt */+	if (val & SR_NIS) {+		if (val & SR_T) {+			tasklet_schedule(&priv->tx_reclaim_tasklet);+		}++		if (val & SR_R) {+			if (netif_rx_schedule_prep(dev)) {+				/* disable rx interrupt */+				enet_disable_interrupts(priv, 1);++				/* ack  any  interrupt  that may  have+				 * arrived  between last ack  to avoid+				 * reentering */+				enet_writel(ENET_DMA_SR, SR_NIS | SR_R);+				__netif_rx_schedule(dev);+			}+		}+	}++        return IRQ_HANDLED;+}++/*+ * start/stop dma engine+ */+static __inline void enet_start_dma(struct em86xx_enet_priv *priv)+{+	/* send start command to rx & tx dma */+	enet_writel(ENET_DMA_CR, CR_SF | CR_SR | CR_ST);+}++static __inline void enet_stop_dma(struct em86xx_enet_priv *priv)+{+	unsigned long val;++	/* send stop command to rx & tx dma */+	enet_writel(ENET_DMA_CR, 0);++	/* wait for them to reach stopped state, should not be long */+	do {+		udelay(1);+		val = enet_readl(ENET_DMA_SR);+		if ((val & SR_TPS) && (val & SR_RPS))+			break;+	} while (1);+}++/*+ * reconfigure mac for new link state+ */+static void enet_link_reconfigure(struct net_device *dev)+{+	struct em86xx_enet_priv *priv;+	unsigned long val;++	priv = netdev_priv(dev);++	if (dev->flags & IFF_UP)+		enet_stop_dma(priv);++	/* reflect duplex status in dma register */+	spin_lock(&priv->maccr_lock);+	val = enet_readl(ENET_MAC_MACCR);+	if (priv->mii.full_duplex)+		val |= MACCR_F;+	else

⌨️ 快捷键说明

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