Skip to content

Commit

Permalink
ixgbe: allow eeprom writes via ethtool
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Emil Tantilov authored and Jeff Kirsher committed Oct 17, 2011
1 parent 79488c5 commit 2fa5eef
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 0 deletions.
2 changes: 2 additions & 0 deletions drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
71 changes: 71 additions & 0 deletions drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 2fa5eef

Please sign in to comment.