]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/gianfar_ethtool.c
Merge 'upstream' branch of rsync://rsync.kernel.org/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6-omap-h63xx.git] / drivers / net / gianfar_ethtool.c
index 28046e9e88ba1f369030c33f29e49395bdb9dc2a..a451de629197b13e1204f59b2707fef1d425e91d 100644 (file)
 
 extern int startup_gfar(struct net_device *dev);
 extern void stop_gfar(struct net_device *dev);
-extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern void gfar_halt(struct net_device *dev);
+extern void gfar_start(struct net_device *dev);
+extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
                     u64 * buf);
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
 
 static char stat_gstrings[][ETH_GSTRING_LEN] = {
        "rx-dropped-by-kernel",
@@ -118,57 +120,56 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = {
        "tx-fragmented-frames",
 };
 
+/* Fill in a buffer with the strings which correspond to the
+ * stats */
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+               memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
+       else
+               memcpy(buf, stat_gstrings,
+                               GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+}
+
 /* Fill in an array of 64-bit statistics from various sources.
  * This array will be appended to the end of the ethtool_stats
  * structure, and returned to user space
  */
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
 {
        int i;
        struct gfar_private *priv = netdev_priv(dev);
-       u32 *rmon = (u32 *) & priv->regs->rmon;
        u64 *extra = (u64 *) & priv->extra_stats;
-       struct gfar_stats *stats = (struct gfar_stats *) buf;
 
-       for (i = 0; i < GFAR_RMON_LEN; i++) {
-               stats->rmon[i] = (u64) (rmon[i]);
-       }
-
-       for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
-               stats->extra[i] = extra[i];
-       }
-}
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+               u32 *rmon = (u32 *) & priv->regs->rmon;
+               struct gfar_stats *stats = (struct gfar_stats *) buf;
 
-/* Returns the number of stats (and their corresponding strings) */
-int gfar_stats_count(struct net_device *dev)
-{
-       return GFAR_STATS_LEN;
-}
+               for (i = 0; i < GFAR_RMON_LEN; i++)
+                       stats->rmon[i] = (u64) (rmon[i]);
 
-void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf)
-{
-       memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+               for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+                       stats->extra[i] = extra[i];
+       } else
+               for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+                       buf[i] = extra[i];
 }
 
-void gfar_fill_stats_normon(struct net_device *dev, 
-               struct ethtool_stats *dummy, u64 * buf)
+/* Returns the number of stats (and their corresponding strings) */
+static int gfar_stats_count(struct net_device *dev)
 {
-       int i;
        struct gfar_private *priv = netdev_priv(dev);
-       u64 *extra = (u64 *) & priv->extra_stats;
 
-       for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
-               buf[i] = extra[i];
-       }
+       if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+               return GFAR_STATS_LEN;
+       else
+               return GFAR_EXTRA_STATS_LEN;
 }
 
-
-int gfar_stats_count_normon(struct net_device *dev)
-{
-       return GFAR_EXTRA_STATS_LEN;
-}
 /* Fills in the drvinfo structure with some basic info */
-void gfar_gdrvinfo(struct net_device *dev, struct
+static void gfar_gdrvinfo(struct net_device *dev, struct
              ethtool_drvinfo *drvinfo)
 {
        strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
@@ -182,7 +183,7 @@ void gfar_gdrvinfo(struct net_device *dev, struct
 }
 
 /* Return the current settings in the ethtool_cmd structure */
-int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct gfar_private *priv = netdev_priv(dev);
        uint gigabit_support = 
@@ -216,13 +217,13 @@ int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 }
 
 /* Return the length of the register structure */
-int gfar_reglen(struct net_device *dev)
+static int gfar_reglen(struct net_device *dev)
 {
        return sizeof (struct gfar);
 }
 
 /* Return a dump of the GFAR register space */
-void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
 {
        int i;
        struct gfar_private *priv = netdev_priv(dev);
@@ -233,13 +234,6 @@ void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regb
                buf[i] = theregs[i];
 }
 
-/* Fill in a buffer with the strings which correspond to the
- * stats */
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
-{
-       memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
-}
-
 /* Convert microseconds to ethernet clock ticks, which changes
  * depending on what speed the controller is running at */
 static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs)
@@ -291,9 +285,12 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
 
 /* Get the coalescing parameters, and put them in the cvals
  * structure.  */
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
+       
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+               return -EOPNOTSUPP;
 
        cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
        cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -337,10 +334,13 @@ int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
  * Both cvals->*_usecs and cvals->*_frames have to be > 0
  * in order for coalescing to be active
  */
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
 
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+               return -EOPNOTSUPP;
+
        /* Set up rx coalescing */
        if ((cvals->rx_coalesce_usecs == 0) ||
            (cvals->rx_max_coalesced_frames == 0))
@@ -379,7 +379,7 @@ int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
 /* Fills in rvals with the current ring parameters.  Currently,
  * rx, rx_mini, and rx_jumbo rings are the same size, as mini and
  * jumbo are ignored by the driver */
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
 
@@ -401,9 +401,8 @@ void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
  * necessary so that we don't mess things up while we're in
  * motion.  We wait for the ring to be clean before reallocating
  * the rings. */
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
 {
-       u32 tempval;
        struct gfar_private *priv = netdev_priv(dev);
        int err = 0;
 
@@ -425,37 +424,54 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
                return -EINVAL;
        }
 
-       /* Stop the controller so we don't rx any more frames */
-       /* But first, make sure we clear the bits */
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
-       gfar_write(&priv->regs->dmactrl, tempval);
+       if (dev->flags & IFF_UP) {
+               unsigned long flags;
 
-       tempval = gfar_read(&priv->regs->dmactrl);
-       tempval |= (DMACTRL_GRS | DMACTRL_GTS);
-       gfar_write(&priv->regs->dmactrl, tempval);
+               /* Halt TX and RX, and process the frames which
+                * have already been received */
+               spin_lock_irqsave(&priv->lock, flags);
+               gfar_halt(dev);
+               gfar_clean_rx_ring(dev, priv->rx_ring_size);
+               spin_unlock_irqrestore(&priv->lock, flags);
 
-       while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
-               cpu_relax();
+               /* Now we take down the rings to rebuild them */
+               stop_gfar(dev);
+       }
 
-       /* Note that rx is not clean right now */
-       priv->rxclean = 0;
+       /* Change the size */
+       priv->rx_ring_size = rvals->rx_pending;
+       priv->tx_ring_size = rvals->tx_pending;
 
-       if (dev->flags & IFF_UP) {
-               /* Tell the driver to process the rest of the frames */
-               gfar_receive(0, (void *) dev, NULL);
+       /* Rebuild the rings with the new size */
+       if (dev->flags & IFF_UP)
+               err = startup_gfar(dev);
 
-               /* Now wait for it to be done */
-               wait_event_interruptible(priv->rxcleanupq, priv->rxclean);
+       return err;
+}
 
-               /* Ok, all packets have been handled.  Now we bring it down,
-                * change the ring size, and bring it up */
+static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+       int err = 0;
 
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return -EOPNOTSUPP;
+
+       if (dev->flags & IFF_UP) {
+               unsigned long flags;
+
+               /* Halt TX and RX, and process the frames which
+                * have already been received */
+               spin_lock_irqsave(&priv->lock, flags);
+               gfar_halt(dev);
+               gfar_clean_rx_ring(dev, priv->rx_ring_size);
+               spin_unlock_irqrestore(&priv->lock, flags);
+
+               /* Now we take down the rings to rebuild them */
                stop_gfar(dev);
        }
 
-       priv->rx_ring_size = rvals->rx_pending;
-       priv->tx_ring_size = rvals->tx_pending;
+       priv->rx_csum_enable = data;
 
        if (dev->flags & IFF_UP)
                err = startup_gfar(dev);
@@ -463,6 +479,61 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
        return err;
 }
 
+static uint32_t gfar_get_rx_csum(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return 0;
+
+       return priv->rx_csum_enable;
+}
+
+static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+       unsigned long flags;
+       struct gfar_private *priv = netdev_priv(dev);
+
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return -EOPNOTSUPP;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       gfar_halt(dev);
+
+       if (data)
+               dev->features |= NETIF_F_IP_CSUM;
+       else
+               dev->features &= ~NETIF_F_IP_CSUM;
+
+       gfar_start(dev);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static uint32_t gfar_get_tx_csum(struct net_device *dev)
+{
+       struct gfar_private *priv = netdev_priv(dev);
+
+       if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+               return 0;
+
+       return (dev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+static uint32_t gfar_get_msglevel(struct net_device *dev)
+{       
+       struct gfar_private *priv = netdev_priv(dev);
+       return priv->msg_enable;
+}       
+        
+static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
+{       
+       struct gfar_private *priv = netdev_priv(dev);
+       priv->msg_enable = data;
+}
+
+
 struct ethtool_ops gfar_ethtool_ops = {
        .get_settings = gfar_gsettings,
        .get_drvinfo = gfar_gdrvinfo,
@@ -476,52 +547,10 @@ struct ethtool_ops gfar_ethtool_ops = {
        .get_strings = gfar_gstrings,
        .get_stats_count = gfar_stats_count,
        .get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_nocoalesce_ethtool_ops = {
-       .get_settings = gfar_gsettings,
-       .get_drvinfo = gfar_gdrvinfo,
-       .get_regs_len = gfar_reglen,
-       .get_regs = gfar_get_regs,
-       .get_link = ethtool_op_get_link,
-       .get_ringparam = gfar_gringparam,
-       .set_ringparam = gfar_sringparam,
-       .get_strings = gfar_gstrings_normon,
-       .get_stats_count = gfar_stats_count_normon,
-       .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops gfar_nocoalesce_ethtool_ops = {
-       .get_settings = gfar_gsettings,
-       .get_drvinfo = gfar_gdrvinfo,
-       .get_regs_len = gfar_reglen,
-       .get_regs = gfar_get_regs,
-       .get_link = ethtool_op_get_link,
-       .get_ringparam = gfar_gringparam,
-       .set_ringparam = gfar_sringparam,
-       .get_strings = gfar_gstrings,
-       .get_stats_count = gfar_stats_count,
-       .get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_ethtool_ops = {
-       .get_settings = gfar_gsettings,
-       .get_drvinfo = gfar_gdrvinfo,
-       .get_regs_len = gfar_reglen,
-       .get_regs = gfar_get_regs,
-       .get_link = ethtool_op_get_link,
-       .get_coalesce = gfar_gcoalesce,
-       .set_coalesce = gfar_scoalesce,
-       .get_ringparam = gfar_gringparam,
-       .set_ringparam = gfar_sringparam,
-       .get_strings = gfar_gstrings_normon,
-       .get_stats_count = gfar_stats_count_normon,
-       .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops *gfar_op_array[] = {
-       &gfar_ethtool_ops,
-       &gfar_normon_ethtool_ops,
-       &gfar_nocoalesce_ethtool_ops,
-       &gfar_normon_nocoalesce_ethtool_ops
+       .get_rx_csum = gfar_get_rx_csum,
+       .get_tx_csum = gfar_get_tx_csum,
+       .set_rx_csum = gfar_set_rx_csum,
+       .set_tx_csum = gfar_set_tx_csum,
+       .get_msglevel = gfar_get_msglevel,
+       .set_msglevel = gfar_set_msglevel,
 };