aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ks8851.c
diff options
context:
space:
mode:
authorSebastien Jan <s-jan@ti.com>2010-05-05 04:45:54 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-06 00:27:45 -0400
commita84afa40e07b6882ca46a7287d8ca4a8c5430f60 (patch)
tree24c929899871aff4faef2f8d891568ceab9a0087 /drivers/net/ks8851.c
parenta4bdfff74464f86d7e3b8feaf42d18960adc5514 (diff)
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: Sebastien Jan <s-jan@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ks8851.c')
-rw-r--r--drivers/net/ks8851.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c
index 3dba57b72ef8..b4fb07a6f13f 100644
--- a/drivers/net/ks8851.c
+++ b/drivers/net/ks8851.c
@@ -1308,6 +1308,117 @@ static int ks8851_nway_reset(struct net_device *dev)
1308 return mii_nway_restart(&ks->mii); 1308 return mii_nway_restart(&ks->mii);
1309} 1309}
1310 1310
1311static int ks8851_get_eeprom_len(struct net_device *dev)
1312{
1313 struct ks8851_net *ks = netdev_priv(dev);
1314 return ks->eeprom_size;
1315}
1316
1317static int ks8851_get_eeprom(struct net_device *dev,
1318 struct ethtool_eeprom *eeprom, u8 *bytes)
1319{
1320 struct ks8851_net *ks = netdev_priv(dev);
1321 u16 *eeprom_buff;
1322 int first_word;
1323 int last_word;
1324 int ret_val = 0;
1325 u16 i;
1326
1327 if (eeprom->len == 0)
1328 return -EINVAL;
1329
1330 if (eeprom->len > ks->eeprom_size)
1331 return -EINVAL;
1332
1333 eeprom->magic = ks8851_rdreg16(ks, KS_CIDER);
1334
1335 first_word = eeprom->offset >> 1;
1336 last_word = (eeprom->offset + eeprom->len - 1) >> 1;
1337
1338 eeprom_buff = kmalloc(sizeof(u16) *
1339 (last_word - first_word + 1), GFP_KERNEL);
1340 if (!eeprom_buff)
1341 return -ENOMEM;
1342
1343 for (i = 0; i < last_word - first_word + 1; i++)
1344 eeprom_buff[i] = ks8851_eeprom_read(dev, first_word + 1);
1345
1346 /* Device's eeprom is little-endian, word addressable */
1347 for (i = 0; i < last_word - first_word + 1; i++)
1348 le16_to_cpus(&eeprom_buff[i]);
1349
1350 memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
1351 kfree(eeprom_buff);
1352
1353 return ret_val;
1354}
1355
1356static int ks8851_set_eeprom(struct net_device *dev,
1357 struct ethtool_eeprom *eeprom, u8 *bytes)
1358{
1359 struct ks8851_net *ks = netdev_priv(dev);
1360 u16 *eeprom_buff;
1361 void *ptr;
1362 int max_len;
1363 int first_word;
1364 int last_word;
1365 int ret_val = 0;
1366 u16 i;
1367
1368 if (eeprom->len == 0)
1369 return -EOPNOTSUPP;
1370
1371 if (eeprom->len > ks->eeprom_size)
1372 return -EINVAL;
1373
1374 if (eeprom->magic != ks8851_rdreg16(ks, KS_CIDER))
1375 return -EFAULT;
1376
1377 first_word = eeprom->offset >> 1;
1378 last_word = (eeprom->offset + eeprom->len - 1) >> 1;
1379 max_len = (last_word - first_word + 1) * 2;
1380 eeprom_buff = kmalloc(max_len, GFP_KERNEL);
1381 if (!eeprom_buff)
1382 return -ENOMEM;
1383
1384 ptr = (void *)eeprom_buff;
1385
1386 if (eeprom->offset & 1) {
1387 /* need read/modify/write of first changed EEPROM word */
1388 /* only the second byte of the word is being modified */
1389 eeprom_buff[0] = ks8851_eeprom_read(dev, first_word);
1390 ptr++;
1391 }
1392 if ((eeprom->offset + eeprom->len) & 1)
1393 /* need read/modify/write of last changed EEPROM word */
1394 /* only the first byte of the word is being modified */
1395 eeprom_buff[last_word - first_word] =
1396 ks8851_eeprom_read(dev, last_word);
1397
1398
1399 /* Device's eeprom is little-endian, word addressable */
1400 le16_to_cpus(&eeprom_buff[0]);
1401 le16_to_cpus(&eeprom_buff[last_word - first_word]);
1402
1403 memcpy(ptr, bytes, eeprom->len);
1404
1405 for (i = 0; i < last_word - first_word + 1; i++)
1406 eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
1407
1408 ks8851_eeprom_write(dev, EEPROM_OP_EWEN, 0, 0);
1409
1410 for (i = 0; i < last_word - first_word + 1; i++) {
1411 ks8851_eeprom_write(dev, EEPROM_OP_WRITE, first_word + i,
1412 eeprom_buff[i]);
1413 mdelay(EEPROM_WRITE_TIME);
1414 }
1415
1416 ks8851_eeprom_write(dev, EEPROM_OP_EWDS, 0, 0);
1417
1418 kfree(eeprom_buff);
1419 return ret_val;
1420}
1421
1311static const struct ethtool_ops ks8851_ethtool_ops = { 1422static const struct ethtool_ops ks8851_ethtool_ops = {
1312 .get_drvinfo = ks8851_get_drvinfo, 1423 .get_drvinfo = ks8851_get_drvinfo,
1313 .get_msglevel = ks8851_get_msglevel, 1424 .get_msglevel = ks8851_get_msglevel,
@@ -1316,6 +1427,9 @@ static const struct ethtool_ops ks8851_ethtool_ops = {
1316 .set_settings = ks8851_set_settings, 1427 .set_settings = ks8851_set_settings,
1317 .get_link = ks8851_get_link, 1428 .get_link = ks8851_get_link,
1318 .nway_reset = ks8851_nway_reset, 1429 .nway_reset = ks8851_nway_reset,
1430 .get_eeprom_len = ks8851_get_eeprom_len,
1431 .get_eeprom = ks8851_get_eeprom,
1432 .set_eeprom = ks8851_set_eeprom,
1319}; 1433};
1320 1434
1321/* MII interface controls */ 1435/* MII interface controls */