/*
- * drivers/net/gianfar_ethtool.c
+ * drivers/net/gianfar_ethtool.c
*
- * Gianfar Ethernet Driver
- * Ethtool support for Gianfar Enet
- * Based on e1000 ethtool support
+ * Gianfar Ethernet Driver
+ * Ethtool support for Gianfar Enet
+ * Based on e1000 ethtool support
*
- * Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala
*
- * Copyright 2004 Freescale Semiconductor, Inc
+ * Copyright (c) 2003,2004 Freescale Semiconductor, Inc.
*
- * This software may be used and distributed according to
- * the terms of the GNU Public License, Version 2, incorporated herein
- * by reference.
+ * This software may be used and distributed according to
+ * the terms of the GNU Public License, Version 2, incorporated herein
+ * by reference.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/crc32.h>
#include <asm/types.h>
#include <asm/uaccess.h>
#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
#include "gianfar.h"
#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-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_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,
+#define GFAR_MAX_COAL_USECS 0xffff
+#define GFAR_MAX_COAL_FRAMES 0xff
+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",
- "RX Large Frame Errors",
- "RX Short Frame Errors",
- "RX Non-Octet Errors",
- "RX CRC Errors",
- "RX Overrun Errors",
- "RX Busy Errors",
- "RX Babbling Errors",
- "RX Truncated Frames",
- "Ethernet Bus Error",
- "TX Babbling Errors",
- "TX Underrun Errors",
- "RX SKB Missing Errors",
- "TX Timeout Errors",
- "tx&rx 64B frames",
- "tx&rx 65-127B frames",
- "tx&rx 128-255B frames",
- "tx&rx 256-511B frames",
- "tx&rx 512-1023B frames",
- "tx&rx 1024-1518B frames",
- "tx&rx 1519-1522B Good VLAN",
- "RX bytes",
- "RX Packets",
- "RX FCS Errors",
- "Receive Multicast Packet",
- "Receive Broadcast Packet",
- "RX Control Frame Packets",
- "RX Pause Frame Packets",
- "RX Unknown OP Code",
- "RX Alignment Error",
- "RX Frame Length Error",
- "RX Code Error",
- "RX Carrier Sense Error",
- "RX Undersize Packets",
- "RX Oversize Packets",
- "RX Fragmented Frames",
- "RX Jabber Frames",
- "RX Dropped Frames",
- "TX Byte Counter",
- "TX Packets",
- "TX Multicast Packets",
- "TX Broadcast Packets",
- "TX Pause Control Frames",
- "TX Deferral Packets",
- "TX Excessive Deferral Packets",
- "TX Single Collision Packets",
- "TX Multiple Collision Packets",
- "TX Late Collision Packets",
- "TX Excessive Collision Packets",
- "TX Total Collision",
- "RESERVED",
- "TX Dropped Frames",
- "TX Jabber Frames",
- "TX FCS Errors",
- "TX Control Frames",
- "TX Oversize Frames",
- "TX Undersize Frames",
- "TX Fragmented Frames",
+ "rx-dropped-by-kernel",
+ "rx-large-frame-errors",
+ "rx-short-frame-errors",
+ "rx-non-octet-errors",
+ "rx-crc-errors",
+ "rx-overrun-errors",
+ "rx-busy-errors",
+ "rx-babbling-errors",
+ "rx-truncated-frames",
+ "ethernet-bus-error",
+ "tx-babbling-errors",
+ "tx-underrun-errors",
+ "rx-skb-missing-errors",
+ "tx-timeout-errors",
+ "tx-rx-64-frames",
+ "tx-rx-65-127-frames",
+ "tx-rx-128-255-frames",
+ "tx-rx-256-511-frames",
+ "tx-rx-512-1023-frames",
+ "tx-rx-1024-1518-frames",
+ "tx-rx-1519-1522-good-vlan",
+ "rx-bytes",
+ "rx-packets",
+ "rx-fcs-errors",
+ "receive-multicast-packet",
+ "receive-broadcast-packet",
+ "rx-control-frame-packets",
+ "rx-pause-frame-packets",
+ "rx-unknown-op-code",
+ "rx-alignment-error",
+ "rx-frame-length-error",
+ "rx-code-error",
+ "rx-carrier-sense-error",
+ "rx-undersize-packets",
+ "rx-oversize-packets",
+ "rx-fragmented-frames",
+ "rx-jabber-frames",
+ "rx-dropped-frames",
+ "tx-byte-counter",
+ "tx-packets",
+ "tx-multicast-packets",
+ "tx-broadcast-packets",
+ "tx-pause-control-frames",
+ "tx-deferral-packets",
+ "tx-excessive-deferral-packets",
+ "tx-single-collision-packets",
+ "tx-multiple-collision-packets",
+ "tx-late-collision-packets",
+ "tx-excessive-collision-packets",
+ "tx-total-collision",
+ "reserved",
+ "tx-dropped-frames",
+ "tx-jabber-frames",
+ "tx-fcs-errors",
+ "tx-control-frames",
+ "tx-oversize-frames",
+ "tx-undersize-frames",
+ "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 = (struct gfar_private *) dev->priv;
- u32 *rmon = (u32 *) & priv->regs->rmon;
+ struct gfar_private *priv = netdev_priv(dev);
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 __iomem *rmon = (u32 __iomem *) & 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) gfar_read(&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 = (struct gfar_private *) dev->priv;
- u64 *extra = (u64 *) & priv->extra_stats;
+ struct gfar_private *priv = netdev_priv(dev);
- 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, gfar_driver_name, GFAR_INFOSTR_LEN);
+ strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN);
strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN);
strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN);
drvinfo->eedump_len = 0;
}
+
+static int gfar_ssettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+
+ if (NULL == phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(phydev, cmd);
+}
+
+
/* 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 = (struct gfar_private *) dev->priv;
- uint gigabit_support =
- priv->einfo->flags & GFAR_HAS_GIGABIT ? SUPPORTED_1000baseT_Full : 0;
- uint gigabit_advert =
- priv->einfo->flags & GFAR_HAS_GIGABIT ? ADVERTISED_1000baseT_Full: 0;
-
- cmd->supported = (SUPPORTED_10baseT_Half
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | gigabit_support | SUPPORTED_Autoneg);
-
- /* For now, we always advertise everything */
- cmd->advertising = (ADVERTISED_10baseT_Half
- | ADVERTISED_100baseT_Half
- | ADVERTISED_100baseT_Full
- | gigabit_advert | ADVERTISED_Autoneg);
-
- cmd->speed = priv->speed;
- cmd->duplex = priv->duplexity;
- cmd->port = PORT_MII;
- cmd->phy_address = priv->einfo->phyid;
- cmd->transceiver = XCVR_EXTERNAL;
- cmd->autoneg = AUTONEG_ENABLE;
+ struct gfar_private *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+
+ if (NULL == phydev)
+ return -ENODEV;
+
cmd->maxtxpkt = priv->txcount;
cmd->maxrxpkt = priv->rxcount;
- return 0;
+ return phy_ethtool_gset(phydev, 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 = (struct gfar_private *) dev->priv;
- u32 *theregs = (u32 *) priv->regs;
+ struct gfar_private *priv = netdev_priv(dev);
+ u32 __iomem *theregs = (u32 __iomem *) priv->regs;
u32 *buf = (u32 *) regbuf;
for (i = 0; i < sizeof (struct gfar) / sizeof (u32); i++)
- buf[i] = theregs[i];
-}
-
-/* Return the link state 1 is up, 0 is down */
-u32 gfar_get_link(struct net_device *dev)
-{
- struct gfar_private *priv = (struct gfar_private *) dev->priv;
- return (u32) priv->link;
-}
-
-/* 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);
+ buf[i] = gfar_read(&theregs[i]);
}
/* Convert microseconds to ethernet clock ticks, which changes
unsigned int count;
/* The timer is different, depending on the interface speed */
- switch (priv->speed) {
- case 1000:
+ switch (priv->phydev->speed) {
+ case SPEED_1000:
count = GFAR_GBIT_TIME;
break;
- case 100:
+ case SPEED_100:
count = GFAR_100_TIME;
break;
- case 10:
+ case SPEED_10:
default:
count = GFAR_10_TIME;
break;
unsigned int count;
/* The timer is different, depending on the interface speed */
- switch (priv->speed) {
- case 1000:
+ switch (priv->phydev->speed) {
+ case SPEED_1000:
count = GFAR_GBIT_TIME;
break;
- case 100:
+ case SPEED_100:
count = GFAR_100_TIME;
break;
- case 10:
+ case SPEED_10:
default:
count = GFAR_10_TIME;
break;
/* 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 = (struct gfar_private *) dev->priv;
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+ return -EOPNOTSUPP;
+
+ if (NULL == priv->phydev)
+ return -ENODEV;
cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
cvals->rx_max_coalesced_frames = priv->rxcount;
* 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 = (struct gfar_private *) dev->priv;
+ 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) ||
else
priv->rxcoalescing = 1;
+ if (NULL == priv->phydev)
+ return -ENODEV;
+
+ /* Check the bounds of the values */
+ if (cvals->rx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
+ pr_info("Coalescing is limited to %d microseconds\n",
+ GFAR_MAX_COAL_USECS);
+ return -EINVAL;
+ }
+
+ if (cvals->rx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
+ pr_info("Coalescing is limited to %d frames\n",
+ GFAR_MAX_COAL_FRAMES);
+ return -EINVAL;
+ }
+
priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs);
priv->rxcount = cvals->rx_max_coalesced_frames;
else
priv->txcoalescing = 1;
+ /* Check the bounds of the values */
+ if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
+ pr_info("Coalescing is limited to %d microseconds\n",
+ GFAR_MAX_COAL_USECS);
+ return -EINVAL;
+ }
+
+ if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
+ pr_info("Coalescing is limited to %d frames\n",
+ GFAR_MAX_COAL_FRAMES);
+ return -EINVAL;
+ }
+
priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs);
priv->txcount = cvals->tx_max_coalesced_frames;
/* 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 = (struct gfar_private *) dev->priv;
+ struct gfar_private *priv = netdev_priv(dev);
rvals->rx_max_pending = GFAR_RX_MAX_RING_SIZE;
rvals->rx_mini_max_pending = GFAR_RX_MAX_RING_SIZE;
* 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 = (struct gfar_private *) dev->priv;
+ struct gfar_private *priv = netdev_priv(dev);
int err = 0;
if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE)
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;
+
+ /* Halt TX and RX, and process the frames which
+ * have already been received */
+ spin_lock_irqsave(&priv->txlock, flags);
+ spin_lock(&priv->rxlock);
+
+ gfar_halt(dev);
+ gfar_clean_rx_ring(dev, priv->rx_ring_size);
+
+ spin_unlock(&priv->rxlock);
+ spin_unlock_irqrestore(&priv->txlock, flags);
+
+ /* Now we take down the rings to rebuild them */
+ stop_gfar(dev);
+ }
+
+ /* Change the size */
+ priv->rx_ring_size = rvals->rx_pending;
+ priv->tx_ring_size = rvals->tx_pending;
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval |= (DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ /* Rebuild the rings with the new size */
+ if (dev->flags & IFF_UP)
+ err = startup_gfar(dev);
- while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
- cpu_relax();
+ return err;
+}
- /* Note that rx is not clean right now */
- priv->rxclean = 0;
+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) {
- /* Tell the driver to process the rest of the frames */
- gfar_receive(0, (void *) dev, NULL);
+ unsigned long flags;
+
+ /* Halt TX and RX, and process the frames which
+ * have already been received */
+ spin_lock_irqsave(&priv->txlock, flags);
+ spin_lock(&priv->rxlock);
- /* Now wait for it to be done */
- wait_event_interruptible(priv->rxcleanupq, priv->rxclean);
+ gfar_halt(dev);
+ gfar_clean_rx_ring(dev, priv->rx_ring_size);
- /* Ok, all packets have been handled. Now we bring it down,
- * change the ring size, and bring it up */
+ spin_unlock(&priv->rxlock);
+ spin_unlock_irqrestore(&priv->txlock, 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);
return err;
}
-struct ethtool_ops gfar_ethtool_ops = {
+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->txlock, 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->txlock, 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;
+}
+
+
+const struct ethtool_ops gfar_ethtool_ops = {
.get_settings = gfar_gsettings,
+ .set_settings = gfar_ssettings,
.get_drvinfo = gfar_gdrvinfo,
.get_regs_len = gfar_reglen,
.get_regs = gfar_get_regs,
- .get_link = gfar_get_link,
+ .get_link = ethtool_op_get_link,
.get_coalesce = gfar_gcoalesce,
.set_coalesce = gfar_scoalesce,
.get_ringparam = gfar_gringparam,
.get_strings = gfar_gstrings,
.get_stats_count = gfar_stats_count,
.get_ethtool_stats = gfar_fill_stats,
+ .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,
};