diff options
| author | Sebastien Jan <s-jan@ti.com> | 2010-05-05 04:45:54 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-05-06 00:27:45 -0400 |
| commit | a84afa40e07b6882ca46a7287d8ca4a8c5430f60 (patch) | |
| tree | 24c929899871aff4faef2f8d891568ceab9a0087 | |
| parent | a4bdfff74464f86d7e3b8feaf42d18960adc5514 (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>
| -rw-r--r-- | drivers/net/ks8851.c | 114 |
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 | ||
| 1311 | static 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 | |||
| 1317 | static 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 | |||
| 1356 | static 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 | |||
| 1311 | static const struct ethtool_ops ks8851_ethtool_ops = { | 1422 | static 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 */ |
