ethtool: Add reset operation
Ben Hutchings [Mon, 5 Oct 2009 10:59:58 +0000 (10:59 +0000)]
After updating firmware stored in flash, users may wish to reset the
relevant hardware and start the new firmware immediately.  This should
not be completely automatic as it may be disruptive.

A selective reset may also be useful for debugging or diagnostics.

This adds a separate reset operation which takes flags indicating the
components to be reset.  Drivers are allowed to reset only a subset of
those requested, and must indicate the actual subset.  This allows the
use of generic component masks and some future expansion.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

include/linux/ethtool.h
net/core/ethtool.c

index aa0dcb3..eb1a48d 100644 (file)
@@ -498,6 +498,7 @@ struct ethtool_ops {
        int     (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, void *);
        int     (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
        int     (*flash_device)(struct net_device *, struct ethtool_flash *);
+       int     (*reset)(struct net_device *, u32 *);
 };
 #endif /* __KERNEL__ */
 
@@ -555,6 +556,7 @@ struct ethtool_ops {
 #define        ETHTOOL_SRXCLSRLDEL     0x00000031 /* Delete RX classification rule */
 #define        ETHTOOL_SRXCLSRLINS     0x00000032 /* Insert RX classification rule */
 #define        ETHTOOL_FLASHDEV        0x00000033 /* Flash firmware to device */
+#define        ETHTOOL_RESET           0x00000034 /* Reset hardware */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
@@ -685,4 +687,34 @@ struct ethtool_ops {
 
 #define        RX_CLS_FLOW_DISC        0xffffffffffffffffULL
 
+/* Reset flags */
+/* The reset() operation must clear the flags for the components which
+ * were actually reset.  On successful return, the flags indicate the
+ * components which were not reset, either because they do not exist
+ * in the hardware or because they cannot be reset independently.  The
+ * driver must never reset any components that were not requested.
+ */
+enum ethtool_reset_flags {
+       /* These flags represent components dedicated to the interface
+        * the command is addressed to.  Shift any flag left by
+        * ETH_RESET_SHARED_SHIFT to reset a shared component of the
+        * same type.
+        */
+       ETH_RESET_MGMT          = 1 << 0,       /* Management processor */
+       ETH_RESET_IRQ           = 1 << 1,       /* Interrupt requester */
+       ETH_RESET_DMA           = 1 << 2,       /* DMA engine */
+       ETH_RESET_FILTER        = 1 << 3,       /* Filtering/flow direction */
+       ETH_RESET_OFFLOAD       = 1 << 4,       /* Protocol offload */
+       ETH_RESET_MAC           = 1 << 5,       /* Media access controller */
+       ETH_RESET_PHY           = 1 << 6,       /* Transceiver/PHY */
+       ETH_RESET_RAM           = 1 << 7,       /* RAM shared between
+                                                * multiple components */
+
+       ETH_RESET_DEDICATED     = 0x0000ffff,   /* All components dedicated to
+                                                * this interface */
+       ETH_RESET_ALL           = 0xffffffff,   /* All components used by this
+                                                * interface, even if shared */
+};
+#define ETH_RESET_SHARED_SHIFT 16
+
 #endif /* _LINUX_ETHTOOL_H */
index e195108..d8aee58 100644 (file)
@@ -302,6 +302,26 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
        return ret;
 }
 
+static int ethtool_reset(struct net_device *dev, char __user *useraddr)
+{
+       struct ethtool_value reset;
+       int ret;
+
+       if (!dev->ethtool_ops->reset)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&reset, useraddr, sizeof(reset)))
+               return -EFAULT;
+
+       ret = dev->ethtool_ops->reset(dev, &reset.data);
+       if (ret)
+               return ret;
+
+       if (copy_to_user(useraddr, &reset, sizeof(reset)))
+               return -EFAULT;
+       return 0;
+}
+
 static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
 {
        struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
@@ -1089,6 +1109,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_FLASHDEV:
                rc = ethtool_flash_device(dev, useraddr);
                break;
+       case ETHTOOL_RESET:
+               rc = ethtool_reset(dev, useraddr);
+               break;
        default:
                rc = -EOPNOTSUPP;
        }