linux/drivers/net/tulip/pnic.c
<<
>>
Prefs
   1/*
   2        drivers/net/tulip/pnic.c
   3
   4        Copyright 2000,2001  The Linux Kernel Team
   5        Written/copyright 1994-2001 by Donald Becker.
   6
   7        This software may be used and distributed according to the terms
   8        of the GNU General Public License, incorporated herein by reference.
   9
  10        Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
  11        for more information on this driver.
  12
  13        Please submit bugs to http://bugzilla.kernel.org/ .
  14*/
  15
  16#include <linux/kernel.h>
  17#include <linux/jiffies.h>
  18#include "tulip.h"
  19
  20
  21void pnic_do_nway(struct net_device *dev)
  22{
  23        struct tulip_private *tp = netdev_priv(dev);
  24        void __iomem *ioaddr = tp->base_addr;
  25        u32 phy_reg = ioread32(ioaddr + 0xB8);
  26        u32 new_csr6 = tp->csr6 & ~0x40C40200;
  27
  28        if (phy_reg & 0x78000000) { /* Ignore baseT4 */
  29                if (phy_reg & 0x20000000)               dev->if_port = 5;
  30                else if (phy_reg & 0x40000000)  dev->if_port = 3;
  31                else if (phy_reg & 0x10000000)  dev->if_port = 4;
  32                else if (phy_reg & 0x08000000)  dev->if_port = 0;
  33                tp->nwayset = 1;
  34                new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000;
  35                iowrite32(0x32 | (dev->if_port & 1), ioaddr + CSR12);
  36                if (dev->if_port & 1)
  37                        iowrite32(0x1F868, ioaddr + 0xB8);
  38                if (phy_reg & 0x30000000) {
  39                        tp->full_duplex = 1;
  40                        new_csr6 |= 0x00000200;
  41                }
  42                if (tulip_debug > 1)
  43                        printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n",
  44                                   dev->name, phy_reg, medianame[dev->if_port]);
  45                if (tp->csr6 != new_csr6) {
  46                        tp->csr6 = new_csr6;
  47                        /* Restart Tx */
  48                        tulip_restart_rxtx(tp);
  49                        dev->trans_start = jiffies;
  50                }
  51        }
  52}
  53
  54void pnic_lnk_change(struct net_device *dev, int csr5)
  55{
  56        struct tulip_private *tp = netdev_priv(dev);
  57        void __iomem *ioaddr = tp->base_addr;
  58        int phy_reg = ioread32(ioaddr + 0xB8);
  59
  60        if (tulip_debug > 1)
  61                printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n",
  62                           dev->name, phy_reg, csr5);
  63        if (ioread32(ioaddr + CSR5) & TPLnkFail) {
  64                iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
  65                /* If we use an external MII, then we mustn't use the
  66                 * internal negotiation.
  67                 */
  68                if (tulip_media_cap[dev->if_port] & MediaIsMII)
  69                        return;
  70                if (! tp->nwayset  ||  time_after(jiffies, dev->trans_start + 1*HZ)) {
  71                        tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
  72                        iowrite32(tp->csr6, ioaddr + CSR6);
  73                        iowrite32(0x30, ioaddr + CSR12);
  74                        iowrite32(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
  75                        dev->trans_start = jiffies;
  76                }
  77        } else if (ioread32(ioaddr + CSR5) & TPLnkPass) {
  78                if (tulip_media_cap[dev->if_port] & MediaIsMII) {
  79                        spin_lock(&tp->lock);
  80                        tulip_check_duplex(dev);
  81                        spin_unlock(&tp->lock);
  82                } else {
  83                        pnic_do_nway(dev);
  84                }
  85                iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
  86        }
  87}
  88
  89void pnic_timer(unsigned long data)
  90{
  91        struct net_device *dev = (struct net_device *)data;
  92        struct tulip_private *tp = netdev_priv(dev);
  93        void __iomem *ioaddr = tp->base_addr;
  94        int next_tick = 60*HZ;
  95
  96        if(!ioread32(ioaddr + CSR7)) {
  97                /* the timer was called due to a work overflow
  98                 * in the interrupt handler. Skip the connection
  99                 * checks, the nic is definitively speaking with
 100                 * his link partner.
 101                 */
 102                goto too_good_connection;
 103        }
 104
 105        if (tulip_media_cap[dev->if_port] & MediaIsMII) {
 106                spin_lock_irq(&tp->lock);
 107                if (tulip_check_duplex(dev) > 0)
 108                        next_tick = 3*HZ;
 109                spin_unlock_irq(&tp->lock);
 110        } else {
 111                int csr12 = ioread32(ioaddr + CSR12);
 112                int new_csr6 = tp->csr6 & ~0x40C40200;
 113                int phy_reg = ioread32(ioaddr + 0xB8);
 114                int csr5 = ioread32(ioaddr + CSR5);
 115
 116                if (tulip_debug > 1)
 117                        printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s "
 118                                   "CSR5 %8.8x.\n",
 119                                   dev->name, phy_reg, medianame[dev->if_port], csr5);
 120                if (phy_reg & 0x04000000) {     /* Remote link fault */
 121                        iowrite32(0x0201F078, ioaddr + 0xB8);
 122                        next_tick = 1*HZ;
 123                        tp->nwayset = 0;
 124                } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */
 125                        pnic_do_nway(dev);
 126                        next_tick = 60*HZ;
 127                } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
 128                        if (tulip_debug > 1)
 129                                printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
 130                                           "CSR5 %8.8x, PHY %3.3x.\n",
 131                                           dev->name, medianame[dev->if_port], csr12,
 132                                           ioread32(ioaddr + CSR5), ioread32(ioaddr + 0xB8));
 133                        next_tick = 3*HZ;
 134                        if (tp->medialock) {
 135                        } else if (tp->nwayset  &&  (dev->if_port & 1)) {
 136                                next_tick = 1*HZ;
 137                        } else if (dev->if_port == 0) {
 138                                dev->if_port = 3;
 139                                iowrite32(0x33, ioaddr + CSR12);
 140                                new_csr6 = 0x01860000;
 141                                iowrite32(0x1F868, ioaddr + 0xB8);
 142                        } else {
 143                                dev->if_port = 0;
 144                                iowrite32(0x32, ioaddr + CSR12);
 145                                new_csr6 = 0x00420000;
 146                                iowrite32(0x1F078, ioaddr + 0xB8);
 147                        }
 148                        if (tp->csr6 != new_csr6) {
 149                                tp->csr6 = new_csr6;
 150                                /* Restart Tx */
 151                                tulip_restart_rxtx(tp);
 152                                dev->trans_start = jiffies;
 153                                if (tulip_debug > 1)
 154                                        printk(KERN_INFO "%s: Changing PNIC configuration to %s "
 155                                                   "%s-duplex, CSR6 %8.8x.\n",
 156                                                   dev->name, medianame[dev->if_port],
 157                                                   tp->full_duplex ? "full" : "half", new_csr6);
 158                        }
 159                }
 160        }
 161too_good_connection:
 162        mod_timer(&tp->timer, RUN_AT(next_tick));
 163        if(!ioread32(ioaddr + CSR7)) {
 164                if (tulip_debug > 1)
 165                        printk(KERN_INFO "%s: sw timer wakeup.\n", dev->name);
 166                disable_irq(dev->irq);
 167                tulip_refill_rx(dev);
 168                enable_irq(dev->irq);
 169                iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
 170        }
 171}
 172