Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[powerpc.git] / drivers / net / natsemi.c
index 9510030..c6172a7 100644 (file)
@@ -54,8 +54,8 @@
 #include <asm/uaccess.h>
 
 #define DRV_NAME       "natsemi"
-#define DRV_VERSION    "2.0"
-#define DRV_RELDATE    "June 27, 2006"
+#define DRV_VERSION    "2.1"
+#define DRV_RELDATE    "Sept 11, 2006"
 
 #define RX_OFFSET      2
 
@@ -143,9 +143,9 @@ module_param_array(options, int, NULL, 0);
 module_param_array(full_duplex, int, NULL, 0);
 MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
 MODULE_PARM_DESC(debug, "DP8381x default debug level");
-MODULE_PARM_DESC(rx_copybreak, 
+MODULE_PARM_DESC(rx_copybreak,
        "DP8381x copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(options, 
+MODULE_PARM_DESC(options,
        "DP8381x: Bits 0-3: media type, bit 17: full duplex");
 MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
 
@@ -244,18 +244,23 @@ enum {
        MII_EN_SCRM     = 0x0004,       /* enable scrambler (tp) */
 };
 
+enum {
+       NATSEMI_FLAG_IGNORE_PHY         = 0x1,
+};
+
 /* array of board data directly indexed by pci_tbl[x].driver_data */
 static const struct {
        const char *name;
        unsigned long flags;
        unsigned int eeprom_size;
 } natsemi_pci_info[] __devinitdata = {
+       { "Aculab E1/T1 PMXc cPCI carrier card", NATSEMI_FLAG_IGNORE_PHY, 128 },
        { "NatSemi DP8381[56]", 0, 24 },
 };
 
 static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
-       { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_NS, 0x0020, 0x12d9,     0x000c,     0, 0, 0 },
+       { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
        { }     /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl);
@@ -414,7 +419,7 @@ enum TxConfig_bits {
        TxCarrierIgn            = 0x80000000
 };
 
-/* 
+/*
  * Tx Configuration:
  * - 256 byte DMA burst length
  * - fill threshold 512 bytes (i.e. restart DMA when 512 bytes are free)
@@ -568,6 +573,8 @@ struct netdev_private {
        u32 intr_status;
        /* Do not touch the nic registers */
        int hands_off;
+       /* Don't pay attention to the reported link state. */
+       int ignore_phy;
        /* external phy that is used: only valid if dev->if_port != PORT_TP */
        int mii;
        int phy_addr_external;
@@ -623,7 +630,7 @@ static void free_ring(struct net_device *dev);
 static void reinit_ring(struct net_device *dev);
 static void init_registers(struct net_device *dev);
 static int start_tx(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t intr_handler(int irq, void *dev_instance);
 static void netdev_error(struct net_device *dev, int intr_status);
 static int natsemi_poll(struct net_device *dev, int *budget);
 static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do);
@@ -647,7 +654,7 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr);
 static int netdev_close(struct net_device *dev);
 static int netdev_get_regs(struct net_device *dev, u8 *buf);
 static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
 
 static inline void __iomem *ns_ioaddr(struct net_device *dev)
 {
@@ -672,7 +679,7 @@ static void move_int_phy(struct net_device *dev, int addr)
        void __iomem *ioaddr = ns_ioaddr(dev);
        int target = 31;
 
-       /* 
+       /*
         * The internal phy is visible on the external mii bus. Therefore we must
         * move it away before we can send commands to an external phy.
         * There are two addresses we must avoid:
@@ -696,7 +703,10 @@ static void __devinit natsemi_init_media (struct net_device *dev)
        struct netdev_private *np = netdev_priv(dev);
        u32 tmp;
 
-       netif_carrier_off(dev);
+       if (np->ignore_phy)
+               netif_carrier_on(dev);
+       else
+               netif_carrier_off(dev);
 
        /* get the initial settings from hardware */
        tmp            = mdio_read(dev, MII_BMCR);
@@ -806,8 +816,13 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
        np->hands_off = 0;
        np->intr_status = 0;
        np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size;
+       if (natsemi_pci_info[chip_idx].flags & NATSEMI_FLAG_IGNORE_PHY)
+               np->ignore_phy = 1;
+       else
+               np->ignore_phy = 0;
 
        /* Initial port:
+        * - If configured to ignore the PHY set up for external.
         * - If the nic was configured to use an external phy and if find_mii
         *   finds a phy: use external port, first phy that replies.
         * - Otherwise: internal port.
@@ -815,7 +830,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
         * The address would be used to access a phy over the mii bus, but
         * the internal phy is accessed through mapped registers.
         */
-       if (readl(ioaddr + ChipConfig) & CfgExtPhy)
+       if (np->ignore_phy || readl(ioaddr + ChipConfig) & CfgExtPhy)
                dev->if_port = PORT_MII;
        else
                dev->if_port = PORT_TP;
@@ -825,7 +840,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
 
        if (dev->if_port != PORT_TP) {
                np->phy_addr_external = find_mii(dev);
-               if (np->phy_addr_external == PHY_ADDR_NONE) {
+               /* If we're ignoring the PHY it doesn't matter if we can't
+                * find one. */
+               if (!np->ignore_phy && np->phy_addr_external == PHY_ADDR_NONE) {
                        dev->if_port = PORT_TP;
                        np->phy_addr_external = PHY_ADDR_INTERNAL;
                }
@@ -891,6 +908,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
                printk("%02x, IRQ %d", dev->dev_addr[i], irq);
                if (dev->if_port == PORT_TP)
                        printk(", port TP.\n");
+               else if (np->ignore_phy)
+                       printk(", port MII, ignoring PHY\n");
                else
                        printk(", port MII, phy ad %d.\n", np->phy_addr_external);
        }
@@ -1095,7 +1114,7 @@ static void init_phy_fixup(struct net_device *dev)
                        tmp |= BMCR_SPEED100;
                if (np->duplex == DUPLEX_FULL)
                        tmp |= BMCR_FULLDPLX;
-               /* 
+               /*
                 * Note: there is no good way to inform the link partner
                 * that our capabilities changed. The user has to unplug
                 * and replug the network cable after some changes, e.g.
@@ -1236,7 +1255,7 @@ static int switch_port_internal(struct net_device *dev)
        writel(cfg, ioaddr + ChipConfig);
        readl(ioaddr + ChipConfig);
        udelay(1);
-       
+
        /* 2) reset the internal phy: */
        bmcr = readw(ioaddr+BasicControl+(MII_BMCR<<2));
        writel(bmcr | BMCR_RESET, ioaddr+BasicControl+(MII_BMCR<<2));
@@ -1276,7 +1295,7 @@ static int find_mii(struct net_device *dev)
 
        /* Switch to external phy */
        did_switch = switch_port_external(dev);
-               
+
        /* Scan the possible phy addresses:
         *
         * PHY address 0 means that the phy is in isolate mode. Not yet
@@ -1571,9 +1590,13 @@ static void check_link(struct net_device *dev)
 {
        struct netdev_private *np = netdev_priv(dev);
        void __iomem * ioaddr = ns_ioaddr(dev);
-       int duplex;
+       int duplex = np->duplex;
        u16 bmsr;
-       
+
+       /* If we are ignoring the PHY then don't try reading it. */
+       if (np->ignore_phy)
+               goto propagate_state;
+
        /* The link status field is latched: it remains low after a temporary
         * link failure until it's read. We need the current link status,
         * thus read twice.
@@ -1585,7 +1608,7 @@ static void check_link(struct net_device *dev)
                if (netif_carrier_ok(dev)) {
                        if (netif_msg_link(np))
                                printk(KERN_NOTICE "%s: link down.\n",
-                                       dev->name);
+                                      dev->name);
                        netif_carrier_off(dev);
                        undo_cable_magic(dev);
                }
@@ -1609,6 +1632,7 @@ static void check_link(struct net_device *dev)
                        duplex = 1;
        }
 
+propagate_state:
        /* if duplex is set then bit 28 must be set, too */
        if (duplex ^ !!(np->rx_config & RxAcceptTx)) {
                if (netif_msg_link(np))
@@ -2000,6 +2024,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
        struct netdev_private *np = netdev_priv(dev);
        void __iomem * ioaddr = ns_ioaddr(dev);
        unsigned entry;
+       unsigned long flags;
 
        /* Note: Ordering is important here, set the field with the
           "ownership" bit last, and only then increment cur_tx. */
@@ -2013,7 +2038,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 
        np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]);
 
-       spin_lock_irq(&np->lock);
+       spin_lock_irqsave(&np->lock, flags);
 
        if (!np->hands_off) {
                np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len);
@@ -2032,7 +2057,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
                dev_kfree_skb_irq(skb);
                np->stats.tx_dropped++;
        }
-       spin_unlock_irq(&np->lock);
+       spin_unlock_irqrestore(&np->lock, flags);
 
        dev->trans_start = jiffies;
 
@@ -2088,7 +2113,7 @@ static void netdev_tx_done(struct net_device *dev)
 
 /* The interrupt handler doesn't actually handle interrupts itself, it
  * schedules a NAPI poll if there is anything to do. */
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+static irqreturn_t intr_handler(int irq, void *dev_instance)
 {
        struct net_device *dev = dev_instance;
        struct netdev_private *np = netdev_priv(dev);
@@ -2096,7 +2121,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
 
        if (np->hands_off)
                return IRQ_NONE;
-       
+
        /* Reading automatically acknowledges. */
        np->intr_status = readl(ioaddr + IntrStatus);
 
@@ -2106,7 +2131,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
                       dev->name, np->intr_status,
                       readl(ioaddr + IntrMask));
 
-       if (!np->intr_status) 
+       if (!np->intr_status)
                return IRQ_NONE;
 
        prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
@@ -2141,13 +2166,13 @@ static int natsemi_poll(struct net_device *dev, int *budget)
                /* Abnormal error summary/uncommon events handlers. */
                if (np->intr_status & IntrAbnormalSummary)
                        netdev_error(dev, np->intr_status);
-               
+
                if (np->intr_status &
                    (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
                     IntrRxErr | IntrRxOverrun)) {
                        netdev_rx(dev, &work_done, work_to_do);
                }
-               
+
                *budget -= work_done;
                dev->quota -= work_done;
 
@@ -2198,6 +2223,8 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
                pkt_len = (desc_status & DescSizeMask) - 4;
                if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){
                        if (desc_status & DescMore) {
+                               unsigned long flags;
+
                                if (netif_msg_rx_err(np))
                                        printk(KERN_WARNING
                                                "%s: Oversized(?) Ethernet "
@@ -2212,12 +2239,12 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
                                 * reset procedure documented in
                                 * AN-1287. */
 
-                               spin_lock_irq(&np->lock);
+                               spin_lock_irqsave(&np->lock, flags);
                                reset_rx(dev);
                                reinit_rx(dev);
                                writel(np->ring_dma, ioaddr + RxRingPtr);
                                check_link(dev);
-                               spin_unlock_irq(&np->lock);
+                               spin_unlock_irqrestore(&np->lock, flags);
 
                                /* We'll enable RX on exit from this
                                 * function. */
@@ -2372,8 +2399,19 @@ static struct net_device_stats *get_stats(struct net_device *dev)
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void natsemi_poll_controller(struct net_device *dev)
 {
+       struct netdev_private *np = netdev_priv(dev);
+
        disable_irq(dev->irq);
-       intr_handler(dev->irq, dev, NULL);
+
+       /*
+        * A real interrupt might have already reached us at this point
+        * but NAPI might still haven't called us back.  As the interrupt
+        * status register is cleared by reading, we should prevent an
+        * interrupt loss in this case...
+        */
+       if (!np->intr_status)
+               intr_handler(dev->irq, dev);
+
        enable_irq(dev->irq);
 }
 #endif
@@ -2387,9 +2425,6 @@ static void __set_rx_mode(struct net_device *dev)
        u32 rx_mode;
 
        if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
-               /* Unconditionally log net taps. */
-               printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
-                       dev->name);
                rx_mode = RxFilterEnable | AcceptBroadcast
                        | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys;
        } else if ((dev->mc_count > multicast_filter_limit)
@@ -2576,7 +2611,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8
        return res;
 }
 
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
        .get_drvinfo = get_drvinfo,
        .get_regs_len = get_regs_len,
        .get_eeprom_len = get_eeprom_len,
@@ -2747,7 +2782,7 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
         * phy, even if the internal phy is used. This is necessary
         * to work around a deficiency of the ethtool interface:
         * It's only possible to query the settings of the active
-        * port. Therefore 
+        * port. Therefore
         * # ethtool -s ethX port mii
         * actually sends an ioctl to switch to port mii with the
         * settings that are used for the current active port.
@@ -2821,6 +2856,15 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
                return -EINVAL;
        }
 
+       /*
+        * If we're ignoring the PHY then autoneg and the internal
+        * transciever are really not going to work so don't let the
+        * user select them.
+        */
+       if (np->ignore_phy && (ecmd->autoneg == AUTONEG_ENABLE ||
+                              ecmd->port == PORT_TP))
+               return -EINVAL;
+
        /*
         * maxtxpkt, maxrxpkt: ignored for now.
         *