Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / net / sgiseeq.c
index b71f45f..f95a5b0 100644 (file)
@@ -3,6 +3,9 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  */
+
+#undef DEBUG
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/bitops.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/bitops.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/sgi/hpc3.h>
@@ -32,8 +35,6 @@
 
 #include "sgiseeq.h"
 
-static char *version = "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n";
-
 static char *sgiseeqstr = "SGI Seeq8003";
 
 /*
@@ -61,8 +62,6 @@ static char *sgiseeqstr = "SGI Seeq8003";
                            sp->tx_old + (SEEQ_TX_BUFFERS - 1) - sp->tx_new : \
                            sp->tx_old - sp->tx_new - 1)
 
-#define DEBUG
-
 struct sgiseeq_rx_desc {
        volatile struct hpc_dma_desc rdma;
        volatile signed int buf_vaddr;
@@ -113,9 +112,9 @@ static struct net_device *root_sgiseeq_dev;
 
 static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs)
 {
-       hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ;
+       hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ;
        udelay(20);
-       hregs->rx_reset = 0;
+       hregs->reset = 0;
 }
 
 static inline void reset_hpc3_and_seeq(struct hpc3_ethregs *hregs,
@@ -136,9 +135,10 @@ static inline void seeq_go(struct sgiseeq_private *sp,
        hregs->rx_ctrl = HPC3_ERXCTRL_ACTIVE;
 }
 
-static inline void seeq_load_eaddr(struct net_device *dev,
-                                  struct sgiseeq_regs *sregs)
+static inline void __sgiseeq_set_mac_address(struct net_device *dev)
 {
+       struct sgiseeq_private *sp = netdev_priv(dev);
+       struct sgiseeq_regs *sregs = sp->sregs;
        int i;
 
        sregs->tstat = SEEQ_TCMD_RB0;
@@ -146,6 +146,20 @@ static inline void seeq_load_eaddr(struct net_device *dev,
                sregs->rw.eth_addr[i] = dev->dev_addr[i];
 }
 
+static int sgiseeq_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct sgiseeq_private *sp = netdev_priv(dev);
+       struct sockaddr *sa = addr;
+
+       memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+       spin_lock_irq(&sp->tx_lock);
+       __sgiseeq_set_mac_address(dev);
+       spin_unlock_irq(&sp->tx_lock);
+
+       return 0;
+}
+
 #define TCNTINFO_INIT (HPCDMA_EOX | HPCDMA_ETXD)
 #define RCNTCFG_INIT  (HPCDMA_OWN | HPCDMA_EORP | HPCDMA_XIE)
 #define RCNTINFO_INIT (RCNTCFG_INIT | (PKT_BUF_SZ & HPCDMA_BCNT))
@@ -159,13 +173,7 @@ static int seeq_init_ring(struct net_device *dev)
        sp->rx_new = sp->tx_new = 0;
        sp->rx_old = sp->tx_old = 0;
 
-       seeq_load_eaddr(dev, sp->sregs);
-
-       /* XXX for now just accept packets directly to us
-        * XXX and ether-broadcast.  Will do multicast and
-        * XXX promiscuous mode later. -davem
-        */
-       sp->mode = SEEQ_RCMD_RBCAST;
+       __sgiseeq_set_mac_address(dev);
 
        /* Setup tx ring. */
        for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
@@ -175,7 +183,7 @@ static int seeq_init_ring(struct net_device *dev)
                        buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
                        if (!buffer)
                                return -ENOMEM;
-                       sp->tx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
+                       sp->tx_desc[i].buf_vaddr = CKSEG1ADDR(buffer);
                        sp->tx_desc[i].tdma.pbuf = CPHYSADDR(buffer);
                }
                sp->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT;
@@ -189,7 +197,7 @@ static int seeq_init_ring(struct net_device *dev)
                        buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
                        if (!buffer)
                                return -ENOMEM;
-                       sp->rx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
+                       sp->rx_desc[i].buf_vaddr = CKSEG1ADDR(buffer);
                        sp->rx_desc[i].rdma.pbuf = CPHYSADDR(buffer);
                }
                sp->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT;
@@ -202,7 +210,7 @@ static int seeq_init_ring(struct net_device *dev)
 static struct sgiseeq_private *gpriv;
 static struct net_device *gdev;
 
-void sgiseeq_dump_rings(void)
+static void sgiseeq_dump_rings(void)
 {
        static int once;
        struct sgiseeq_rx_desc *r = gpriv->rx_desc;
@@ -243,7 +251,6 @@ void sgiseeq_dump_rings(void)
 
 #define TSTAT_INIT_SEEQ (SEEQ_TCMD_IPT|SEEQ_TCMD_I16|SEEQ_TCMD_IC|SEEQ_TCMD_IUF)
 #define TSTAT_INIT_EDLC ((TSTAT_INIT_SEEQ) | SEEQ_TCMD_RB2)
-#define RDMACFG_INIT    (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ)
 
 static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
                     struct sgiseeq_regs *sregs)
@@ -265,8 +272,6 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
                sregs->tstat = TSTAT_INIT_SEEQ;
        }
 
-       hregs->rx_dconfig |= RDMACFG_INIT;
-
        hregs->rx_ndptr = CPHYSADDR(sp->rx_desc);
        hregs->tx_ndptr = CPHYSADDR(sp->tx_desc);
 
@@ -307,9 +312,9 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
                              struct sgiseeq_regs *sregs)
 {
        struct sgiseeq_rx_desc *rd;
-       struct sk_buff *skb = 0;
+       struct sk_buff *skb = NULL;
        unsigned char pkt_status;
-       unsigned char *pkt_pointer = 0;
+       unsigned char *pkt_pointer = NULL;
        int len = 0;
        unsigned int orig_end = PREV_RX(sp->rx_new);
 
@@ -331,10 +336,17 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
                                /* Copy out of kseg1 to avoid silly cache flush. */
                                eth_copy_and_sum(skb, pkt_pointer + 2, len, 0);
                                skb->protocol = eth_type_trans(skb, dev);
-                               netif_rx(skb);
-                               dev->last_rx = jiffies;
-                               sp->stats.rx_packets++;
-                               sp->stats.rx_bytes += len;
+
+                               /* We don't want to receive our own packets */
+                               if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) {
+                                       netif_rx(skb);
+                                       dev->last_rx = jiffies;
+                                       sp->stats.rx_packets++;
+                                       sp->stats.rx_bytes += len;
+                               } else {
+                                       /* Silently drop my own packets */
+                                       dev_kfree_skb_irq(skb);
+                               }
                        } else {
                                printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
                                        dev->name);
@@ -373,7 +385,7 @@ static inline void kick_tx(struct sgiseeq_tx_desc *td,
         */
        while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) ==
              (HPCDMA_XIU | HPCDMA_ETXD))
-               td = (struct sgiseeq_tx_desc *)(long) KSEG1ADDR(td->tdma.pnext);
+               td = (struct sgiseeq_tx_desc *)(long) CKSEG1ADDR(td->tdma.pnext);
        if (td->tdma.cntinfo & HPCDMA_XIU) {
                hregs->tx_ndptr = CPHYSADDR(td);
                hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
@@ -430,7 +442,7 @@ static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs
        spin_lock(&sp->tx_lock);
 
        /* Ack the IRQ and set software state. */
-       hregs->rx_reset = HPC3_ERXRST_CLRIRQ;
+       hregs->reset = HPC3_ERST_CLRIRQ;
 
        /* Always check for received packets. */
        sgiseeq_rx(dev, sp, hregs, sregs);
@@ -477,11 +489,13 @@ static int sgiseeq_close(struct net_device *dev)
 {
        struct sgiseeq_private *sp = netdev_priv(dev);
        struct sgiseeq_regs *sregs = sp->sregs;
+       unsigned int irq = dev->irq;
 
        netif_stop_queue(dev);
 
        /* Shutdown the Seeq. */
        reset_hpc3_and_seeq(sp->hregs, sregs);
+       free_irq(irq, dev);
 
        return 0;
 }
@@ -502,12 +516,6 @@ static inline int sgiseeq_reset(struct net_device *dev)
        return 0;
 }
 
-void sgiseeq_my_reset(void)
-{
-       printk("RESET!\n");
-       sgiseeq_reset(gdev);
-}
-
 static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct sgiseeq_private *sp = netdev_priv(dev);
@@ -583,6 +591,22 @@ static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev)
 
 static void sgiseeq_set_multicast(struct net_device *dev)
 {
+       struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+       unsigned char oldmode = sp->mode;
+
+       if(dev->flags & IFF_PROMISC)
+               sp->mode = SEEQ_RCMD_RANY;
+       else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count)
+               sp->mode = SEEQ_RCMD_RBMCAST;
+       else
+               sp->mode = SEEQ_RCMD_RBCAST;
+
+       /* XXX I know this sucks, but is there a better way to reprogram
+        * XXX the receiver? At least, this shouldn't happen too often.
+        */
+
+       if (oldmode != sp->mode)
+               sgiseeq_reset(dev);
 }
 
 static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs)
@@ -612,7 +636,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs)
 
 #define ALIGNED(x)  ((((unsigned long)(x)) + 0xf) & ~(0xf))
 
-static int sgiseeq_init(struct hpc3_regs* regs, int irq)
+static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
 {
        struct sgiseeq_init_block *sr;
        struct sgiseeq_private *sp;
@@ -648,16 +672,17 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq)
        gpriv = sp;
        gdev = dev;
 #endif
-       sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0];
-       sp->hregs = &hpc3c0->ethregs;
+       sp->sregs = (struct sgiseeq_regs *) &hpcregs->eth_ext[0];
+       sp->hregs = &hpcregs->ethregs;
        sp->name = sgiseeqstr;
+       sp->mode = SEEQ_RCMD_RBCAST;
 
        sp->rx_desc = (struct sgiseeq_rx_desc *)
-                     KSEG1ADDR(ALIGNED(&sp->srings->rxvector[0]));
+                     CKSEG1ADDR(ALIGNED(&sp->srings->rxvector[0]));
        dma_cache_wback_inv((unsigned long)&sp->srings->rxvector,
                            sizeof(sp->srings->rxvector));
        sp->tx_desc = (struct sgiseeq_tx_desc *)
-                     KSEG1ADDR(ALIGNED(&sp->srings->txvector[0]));
+                     CKSEG1ADDR(ALIGNED(&sp->srings->txvector[0]));
        dma_cache_wback_inv((unsigned long)&sp->srings->txvector,
                            sizeof(sp->srings->txvector));
 
@@ -665,6 +690,11 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq)
        setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
        setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
 
+       /* Setup PIO and DMA transfer timing */
+       sp->hregs->pconfig = 0x161;
+       sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
+                            HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
+
        /* Reset the chip. */
        hpc3_eth_reset(sp->hregs);
 
@@ -681,6 +711,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq)
        dev->watchdog_timeo     = (200 * HZ) / 1000;
        dev->get_stats          = sgiseeq_get_stats;
        dev->set_multicast_list = sgiseeq_set_multicast;
+       dev->set_mac_address    = sgiseeq_set_mac_address;
        dev->irq                = irq;
 
        if (register_netdev(dev)) {
@@ -690,7 +721,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq)
                goto err_out_free_page;
        }
 
-       printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name);
+       printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr);
        for (i = 0; i < 6; i++)
                printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
 
@@ -700,7 +731,7 @@ static int sgiseeq_init(struct hpc3_regs* regs, int irq)
        return 0;
 
 err_out_free_page:
-       free_page((unsigned long) sp);
+       free_page((unsigned long) sp->srings);
 err_out_free_dev:
        kfree(dev);
 
@@ -710,8 +741,6 @@ err_out:
 
 static int __init sgiseeq_probe(void)
 {
-       printk(version);
-
        /* On board adapter on 1st HPC is always present */
        return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
 }
@@ -720,15 +749,12 @@ static void __exit sgiseeq_exit(void)
 {
        struct net_device *next, *dev;
        struct sgiseeq_private *sp;
-       int irq;
 
        for (dev = root_sgiseeq_dev; dev; dev = next) {
                sp = (struct sgiseeq_private *) netdev_priv(dev);
                next = sp->next_module;
-               irq = dev->irq;
                unregister_netdev(dev);
-               free_irq(irq, dev);
-               free_page((unsigned long) sp);
+               free_page((unsigned long) sp->srings);
                free_netdev(dev);
        }
 }
@@ -736,4 +762,6 @@ static void __exit sgiseeq_exit(void)
 module_init(sgiseeq_probe);
 module_exit(sgiseeq_exit);
 
+MODULE_DESCRIPTION("SGI Seeq 8003 driver");
+MODULE_AUTHOR("Linux/MIPS Mailing List <linux-mips@linux-mips.org>");
 MODULE_LICENSE("GPL");