ixgbe: allow eeprom writes via ethtool
authorEmil Tantilov <emil.s.tantilov@intel.com>
Thu, 6 Oct 2011 08:57:04 +0000 (08:57 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Mon, 17 Oct 2011 12:08:33 +0000 (05:08 -0700)
Implement support for ethtool -E

Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c

index e02e911057de93e2ce9abcc1e68561b12021f685..ef2afefb0cd49dc13e9dcafd3abde34d8e795d4a 100644 (file)
@@ -1305,6 +1305,8 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
 static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
        .init_params            = &ixgbe_init_eeprom_params_generic,
        .read                   = &ixgbe_read_eerd_generic,
+       .write                  = &ixgbe_write_eeprom_generic,
+       .write_buffer           = &ixgbe_write_eeprom_buffer_bit_bang_generic,
        .read_buffer            = &ixgbe_read_eerd_buffer_generic,
        .calc_checksum          = &ixgbe_calc_eeprom_checksum_generic,
        .validate_checksum      = &ixgbe_validate_eeprom_checksum_generic,
index e102ff6fb08d3f0c5998bb688e06ca0d7d76b215..7acfce317f4e670398eee180215dba3c29c36c09 100644 (file)
@@ -814,6 +814,76 @@ static int ixgbe_get_eeprom(struct net_device *netdev,
        return ret_val;
 }
 
+static int ixgbe_set_eeprom(struct net_device *netdev,
+                           struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u16 *eeprom_buff;
+       void *ptr;
+       int max_len, first_word, last_word, ret_val = 0;
+       u16 i;
+
+       if (eeprom->len == 0)
+               return -EINVAL;
+
+       if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
+               return -EINVAL;
+
+       max_len = hw->eeprom.word_size * 2;
+
+       first_word = eeprom->offset >> 1;
+       last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+       eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+       if (!eeprom_buff)
+               return -ENOMEM;
+
+       ptr = eeprom_buff;
+
+       if (eeprom->offset & 1) {
+               /*
+                * need read/modify/write of first changed EEPROM word
+                * only the second byte of the word is being modified
+                */
+               ret_val = hw->eeprom.ops.read(hw, first_word, &eeprom_buff[0]);
+               if (ret_val)
+                       goto err;
+
+               ptr++;
+       }
+       if ((eeprom->offset + eeprom->len) & 1) {
+               /*
+                * need read/modify/write of last changed EEPROM word
+                * only the first byte of the word is being modified
+                */
+               ret_val = hw->eeprom.ops.read(hw, last_word,
+                                         &eeprom_buff[last_word - first_word]);
+               if (ret_val)
+                       goto err;
+       }
+
+       /* Device's eeprom is always little-endian, word addressable */
+       for (i = 0; i < last_word - first_word + 1; i++)
+               le16_to_cpus(&eeprom_buff[i]);
+
+       memcpy(ptr, bytes, eeprom->len);
+
+       for (i = 0; i < last_word - first_word + 1; i++)
+               cpu_to_le16s(&eeprom_buff[i]);
+
+       ret_val = hw->eeprom.ops.write_buffer(hw, first_word,
+                                             last_word - first_word + 1,
+                                             eeprom_buff);
+
+       /* Update the checksum */
+       if (ret_val == 0)
+               hw->eeprom.ops.update_checksum(hw);
+
+err:
+       kfree(eeprom_buff);
+       return ret_val;
+}
+
 static void ixgbe_get_drvinfo(struct net_device *netdev,
                               struct ethtool_drvinfo *drvinfo)
 {
@@ -2524,6 +2594,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
        .get_link               = ethtool_op_get_link,
        .get_eeprom_len         = ixgbe_get_eeprom_len,
        .get_eeprom             = ixgbe_get_eeprom,
+       .set_eeprom             = ixgbe_set_eeprom,
        .get_ringparam          = ixgbe_get_ringparam,
        .set_ringparam          = ixgbe_set_ringparam,
        .get_pauseparam         = ixgbe_get_pauseparam,