Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a84afa40 authored by Sebastien Jan's avatar Sebastien Jan Committed by David S. Miller
Browse files

ks8851: companion eeprom access through ethtool



Accessing ks8851 companion eeprom permits modifying the ks8851 stored
MAC address.

Example how to change the MAC address using ethtool, to set the
01:23:45:67:89:AB MAC address:
$ echo "0:AB8976452301" | xxd -r > mac.bin
$ sudo ethtool -E eth0 magic 0x8870 offset 2 < mac.bin

Signed-off-by: default avatarSebastien Jan <s-jan@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a4bdfff7
Loading
Loading
Loading
Loading
+114 −0
Original line number Original line Diff line number Diff line
@@ -1308,6 +1308,117 @@ static int ks8851_nway_reset(struct net_device *dev)
	return mii_nway_restart(&ks->mii);
	return mii_nway_restart(&ks->mii);
}
}


static int ks8851_get_eeprom_len(struct net_device *dev)
{
	struct ks8851_net *ks = netdev_priv(dev);
	return ks->eeprom_size;
}

static int ks8851_get_eeprom(struct net_device *dev,
			    struct ethtool_eeprom *eeprom, u8 *bytes)
{
	struct ks8851_net *ks = netdev_priv(dev);
	u16 *eeprom_buff;
	int first_word;
	int last_word;
	int ret_val = 0;
	u16 i;

	if (eeprom->len == 0)
		return -EINVAL;

	if (eeprom->len > ks->eeprom_size)
		return -EINVAL;

	eeprom->magic = ks8851_rdreg16(ks, KS_CIDER);

	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;

	eeprom_buff = kmalloc(sizeof(u16) *
			(last_word - first_word + 1), GFP_KERNEL);
	if (!eeprom_buff)
		return -ENOMEM;

	for (i = 0; i < last_word - first_word + 1; i++)
		eeprom_buff[i] = ks8851_eeprom_read(dev, first_word + 1);

	/* Device's eeprom is little-endian, word addressable */
	for (i = 0; i < last_word - first_word + 1; i++)
		le16_to_cpus(&eeprom_buff[i]);

	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
	kfree(eeprom_buff);

	return ret_val;
}

static int ks8851_set_eeprom(struct net_device *dev,
			    struct ethtool_eeprom *eeprom, u8 *bytes)
{
	struct ks8851_net *ks = netdev_priv(dev);
	u16 *eeprom_buff;
	void *ptr;
	int max_len;
	int first_word;
	int last_word;
	int ret_val = 0;
	u16 i;

	if (eeprom->len == 0)
		return -EOPNOTSUPP;

	if (eeprom->len > ks->eeprom_size)
		return -EINVAL;

	if (eeprom->magic != ks8851_rdreg16(ks, KS_CIDER))
		return -EFAULT;

	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
	max_len = (last_word - first_word + 1) * 2;
	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
	if (!eeprom_buff)
		return -ENOMEM;

	ptr = (void *)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 */
		eeprom_buff[0] = ks8851_eeprom_read(dev, first_word);
		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 */
		eeprom_buff[last_word - first_word] =
					ks8851_eeprom_read(dev, last_word);


	/* Device's eeprom is little-endian, word addressable */
	le16_to_cpus(&eeprom_buff[0]);
	le16_to_cpus(&eeprom_buff[last_word - first_word]);

	memcpy(ptr, bytes, eeprom->len);

	for (i = 0; i < last_word - first_word + 1; i++)
		eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);

	ks8851_eeprom_write(dev, EEPROM_OP_EWEN, 0, 0);

	for (i = 0; i < last_word - first_word + 1; i++) {
		ks8851_eeprom_write(dev, EEPROM_OP_WRITE, first_word + i,
							eeprom_buff[i]);
		mdelay(EEPROM_WRITE_TIME);
	}

	ks8851_eeprom_write(dev, EEPROM_OP_EWDS, 0, 0);

	kfree(eeprom_buff);
	return ret_val;
}

static const struct ethtool_ops ks8851_ethtool_ops = {
static const struct ethtool_ops ks8851_ethtool_ops = {
	.get_drvinfo	= ks8851_get_drvinfo,
	.get_drvinfo	= ks8851_get_drvinfo,
	.get_msglevel	= ks8851_get_msglevel,
	.get_msglevel	= ks8851_get_msglevel,
@@ -1316,6 +1427,9 @@ static const struct ethtool_ops ks8851_ethtool_ops = {
	.set_settings	= ks8851_set_settings,
	.set_settings	= ks8851_set_settings,
	.get_link	= ks8851_get_link,
	.get_link	= ks8851_get_link,
	.nway_reset	= ks8851_nway_reset,
	.nway_reset	= ks8851_nway_reset,
	.get_eeprom_len	= ks8851_get_eeprom_len,
	.get_eeprom	= ks8851_get_eeprom,
	.set_eeprom	= ks8851_set_eeprom,
};
};


/* MII interface controls */
/* MII interface controls */