fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / gianfar.c
index 218d317..baa3514 100644 (file)
@@ -9,7 +9,7 @@
  * Author: Andy Fleming
  * Maintainer: Kumar Gala
  *
- * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ * Copyright (c) 2002-2006 Freescale Semiconductor, Inc.
  *
  * 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
@@ -64,7 +64,6 @@
  *  The driver then cleans up the buffer.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -120,9 +119,9 @@ struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp);
 static struct net_device_stats *gfar_get_stats(struct net_device *dev);
 static int gfar_set_mac_address(struct net_device *dev);
 static int gfar_change_mtu(struct net_device *dev, int new_mtu);
-static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gfar_error(int irq, void *dev_id);
+static irqreturn_t gfar_transmit(int irq, void *dev_id);
+static irqreturn_t gfar_interrupt(int irq, void *dev_id);
 static void adjust_link(struct net_device *dev);
 static void init_registers(struct net_device *dev);
 static int init_phy(struct net_device *dev);
@@ -134,6 +133,9 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
 #ifdef CONFIG_GFAR_NAPI
 static int gfar_poll(struct net_device *dev, int *budget);
 #endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void gfar_netpoll(struct net_device *dev);
+#endif
 int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
 static void gfar_vlan_rx_register(struct net_device *netdev,
@@ -144,7 +146,7 @@ void gfar_start(struct net_device *dev);
 static void gfar_clear_exact_match(struct net_device *dev);
 static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
 
-extern struct ethtool_ops gfar_ethtool_ops;
+extern const struct ethtool_ops gfar_ethtool_ops;
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Gianfar Ethernet Driver");
@@ -260,6 +262,9 @@ static int gfar_probe(struct platform_device *pdev)
 #ifdef CONFIG_GFAR_NAPI
        dev->poll = gfar_poll;
        dev->weight = GFAR_DEV_WEIGHT;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = gfar_netpoll;
 #endif
        dev->stop = gfar_close;
        dev->get_stats = gfar_get_stats;
@@ -393,6 +398,38 @@ static int gfar_remove(struct platform_device *pdev)
 }
 
 
+/* Reads the controller's registers to determine what interface
+ * connects it to the PHY.
+ */
+static phy_interface_t gfar_get_interface(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       u32 ecntrl = gfar_read(&priv->regs->ecntrl);
+
+       if (ecntrl & ECNTRL_SGMII_MODE)
+               return PHY_INTERFACE_MODE_SGMII;
+
+       if (ecntrl & ECNTRL_TBI_MODE) {
+               if (ecntrl & ECNTRL_REDUCED_MODE)
+                       return PHY_INTERFACE_MODE_RTBI;
+               else
+                       return PHY_INTERFACE_MODE_TBI;
+       }
+
+       if (ecntrl & ECNTRL_REDUCED_MODE) {
+               if (ecntrl & ECNTRL_REDUCED_MII_MODE)
+                       return PHY_INTERFACE_MODE_RMII;
+               else
+                       return PHY_INTERFACE_MODE_RGMII;
+       }
+
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
+               return PHY_INTERFACE_MODE_GMII;
+
+       return PHY_INTERFACE_MODE_MII;
+}
+
+
 /* Initializes driver's PHY state, and attaches to the PHY.
  * Returns 0 on success.
  */
@@ -404,6 +441,7 @@ static int init_phy(struct net_device *dev)
                SUPPORTED_1000baseT_Full : 0;
        struct phy_device *phydev;
        char phy_id[BUS_ID_SIZE];
+       phy_interface_t interface;
 
        priv->oldlink = 0;
        priv->oldspeed = 0;
@@ -411,7 +449,9 @@ static int init_phy(struct net_device *dev)
 
        snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id);
 
-       phydev = phy_connect(dev, phy_id, &adjust_link, 0);
+       interface = gfar_get_interface(dev);
+
+       phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface);
 
        if (IS_ERR(phydev)) {
                printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
@@ -948,7 +988,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Set up checksumming */
        if (likely((dev->features & NETIF_F_IP_CSUM)
-                       && (CHECKSUM_HW == skb->ip_summed))) {
+                       && (CHECKSUM_PARTIAL == skb->ip_summed))) {
                fcb = gfar_add_fcb(skb, txbdp);
                status |= TXBD_TOE;
                gfar_tx_checksum(skb, fcb);
@@ -1064,7 +1104,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
                tempval |= TCTRL_VLINS;
 
                gfar_write(&priv->regs->tctrl, tempval);
-               
+
                /* Enable VLAN tag extraction */
                tempval = gfar_read(&priv->regs->rctrl);
                tempval |= RCTRL_VLEX;
@@ -1174,7 +1214,7 @@ static void gfar_timeout(struct net_device *dev)
 }
 
 /* Interrupt Handler for Transmit complete */
-static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gfar_transmit(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *) dev_id;
        struct gfar_private *priv = netdev_priv(dev);
@@ -1306,7 +1346,7 @@ static inline void count_errors(unsigned short status, struct gfar_private *priv
        }
 }
 
-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t gfar_receive(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *) dev_id;
        struct gfar_private *priv = netdev_priv(dev);
@@ -1537,8 +1577,35 @@ static int gfar_poll(struct net_device *dev, int *budget)
 }
 #endif
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void gfar_netpoll(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+
+       /* If the device has multiple interrupts, run tx/rx */
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
+               disable_irq(priv->interruptTransmit);
+               disable_irq(priv->interruptReceive);
+               disable_irq(priv->interruptError);
+               gfar_interrupt(priv->interruptTransmit, dev);
+               enable_irq(priv->interruptError);
+               enable_irq(priv->interruptReceive);
+               enable_irq(priv->interruptTransmit);
+       } else {
+               disable_irq(priv->interruptTransmit);
+               gfar_interrupt(priv->interruptTransmit, dev);
+               enable_irq(priv->interruptTransmit);
+       }
+}
+#endif
+
 /* The interrupt handler for devices with one interrupt */
-static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gfar_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct gfar_private *priv = netdev_priv(dev);
@@ -1551,11 +1618,11 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        /* Check for reception */
        if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0))
-               gfar_receive(irq, dev_id, regs);
+               gfar_receive(irq, dev_id);
 
        /* Check for transmit completion */
        if ((events & IEVENT_TXF) || (events & IEVENT_TXB))
-               gfar_transmit(irq, dev_id, regs);
+               gfar_transmit(irq, dev_id);
 
        /* Update error statistics */
        if (events & IEVENT_TXE) {
@@ -1579,7 +1646,7 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                priv->stats.rx_errors++;
                priv->extra_stats.rx_bsy++;
 
-               gfar_receive(irq, dev_id, regs);
+               gfar_receive(irq, dev_id);
 
 #ifndef CONFIG_GFAR_NAPI
                /* Clear the halt bit in RSTAT */
@@ -1709,9 +1776,6 @@ static void gfar_set_multi(struct net_device *dev)
        u32 tempval;
 
        if(dev->flags & IFF_PROMISC) {
-               if (netif_msg_drv(priv))
-                       printk(KERN_INFO "%s: Entering promiscuous mode.\n",
-                                       dev->name);
                /* Set RCTRL to PROM */
                tempval = gfar_read(&regs->rctrl);
                tempval |= RCTRL_PROM;
@@ -1722,7 +1786,7 @@ static void gfar_set_multi(struct net_device *dev)
                tempval &= ~(RCTRL_PROM);
                gfar_write(&regs->rctrl, tempval);
        }
-       
+
        if(dev->flags & IFF_ALLMULTI) {
                /* Set the hash to rx all multicast frames */
                gfar_write(&regs->igaddr0, 0xffffffff);
@@ -1861,7 +1925,7 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr)
 }
 
 /* GFAR error interrupt handler */
-static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gfar_error(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct gfar_private *priv = netdev_priv(dev);
@@ -1902,7 +1966,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
                priv->stats.rx_errors++;
                priv->extra_stats.rx_bsy++;
 
-               gfar_receive(irq, dev_id, regs);
+               gfar_receive(irq, dev_id);
 
 #ifndef CONFIG_GFAR_NAPI
                /* Clear the halt bit in RSTAT */
@@ -1958,7 +2022,7 @@ static int __init gfar_init(void)
 
        if (err)
                gfar_mdio_exit();
-       
+
        return err;
 }