📄 1005.tango2enet.patch
字号:
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 linux-2.6.15.ref/arch/mips/configs/tango2_defconfig linux-2.6.15/arch/mips/configs/tango2_defconfig--- linux-2.6.15.ref/arch/mips/configs/tango2_defconfig 2006-08-08 18:30:21.000000000 -0700+++ linux-2.6.15/arch/mips/configs/tango2_defconfig 2006-08-08 19:07:05.000000000 -0700@@ -535,6 +535,8 @@ # # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set+CONFIG_TANGO2_ENET=y+# CONFIG_TANGO2_ENET_OLD is not set # CONFIG_NET_PCI is not set #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 linux-2.6.15.ref/arch/mips/configs/tango3_defconfig linux-2.6.15/arch/mips/configs/tango3_defconfig--- linux-2.6.15.ref/arch/mips/configs/tango3_defconfig 2006-08-08 18:31:08.000000000 -0700+++ linux-2.6.15/arch/mips/configs/tango3_defconfig 2006-08-08 19:07:45.000000000 -0700@@ -530,6 +530,8 @@ # # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set+# CONFIG_TANGO2_ENET is not set+# CONFIG_TANGO2_ENET_OLD is not set # CONFIG_NET_PCI is not set #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 linux-2.6.15.ref/drivers/net/Kconfig linux-2.6.15/drivers/net/Kconfig--- linux-2.6.15.ref/drivers/net/Kconfig 2006-08-08 18:01:20.000000000 -0700+++ linux-2.6.15/drivers/net/Kconfig 2006-08-08 18:47:53.000000000 -0700@@ -1244,6 +1244,24 @@ depends on IBM_EMAC && 440GX default y +config TANGO2_ENET+ tristate "SMP863x Builtin Ethernet support"+ depends on NET_ETHERNET && TANGO2+ select MII+ select CRC32+ help+ This option adds support for the SMP863x integrated Ethernet+ controller. This driver uses NAPI and generic Linux MII+ support.++config TANGO2_ENET_OLD+ tristate "SMP863x Builtin Ethernet support (old driver)"+ depends on NET_ETHERNET && TANGO2+ help+ This option adds support for the SMP863x integrated Ethernet+ controller. This is the orignal driver from Sigma with only+ small changes.+ config NET_PCI bool "EISA, VLB, PCI and on board controllers" depends on NET_ETHERNET && (ISA || EISA || PCI)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 linux-2.6.15.ref/drivers/net/Makefile linux-2.6.15/drivers/net/Makefile--- linux-2.6.15.ref/drivers/net/Makefile 2006-08-08 18:01:20.000000000 -0700+++ linux-2.6.15/drivers/net/Makefile 2006-08-08 18:48:33.000000000 -0700@@ -196,6 +196,10 @@ obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_FEC_8XX) += fec_8xx/ +# For SMP863x ethernet+obj-$(CONFIG_TANGO2_ENET) += tango2_enet.o+obj-$(CONFIG_TANGO2_ENET_OLD) += tango2_enet_old.o+ obj-$(CONFIG_ARM) += arm/ obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_TR) += tokenring/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 linux-2.6.15.ref/drivers/net/tango2_enet.c linux-2.6.15/drivers/net/tango2_enet.c--- linux-2.6.15.ref/drivers/net/tango2_enet.c 1969-12-31 16:00:00.000000000 -0800+++ linux-2.6.15/drivers/net/tango2_enet.c 2006-08-08 18:52:38.000000000 -0700@@ -0,0 +1,1102 @@+/*+ * 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/init.h>+#include <linux/module.h>+#include <linux/etherdevice.h>+#include <linux/delay.h>+#include <linux/ethtool.h>+#include <linux/crc32.h>++#include "tango2_enet.h"++#define PFX "tango2_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 tango2_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 tango2_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 tango2_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 (likely(skb = priv->rx_skbs[priv->last_rx_desc])) {++ /* 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 tango2_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 tango2_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 tango2_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 tango2_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -