diff options
author | Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 2016-07-20 18:18:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-07-21 00:10:54 -0400 |
commit | 855b193290e6a07b343ee3c059ea6b4bd6cdc2bf (patch) | |
tree | c5b5d862b18d9660b75fc74477935db70a00873e /drivers/net/dsa | |
parent | d4673339ce22f1d65ebe05bbdaadabf4efb13d18 (diff) |
net: dsa: mv88e6xxx: rework EEPROM access
The 6352 family of switches and compatibles provide a 8-bit address and
16-bit data access to an optional EEPROM.
Newer chip such as the 6390 family slightly changed the access to 16-bit
address and 8-bit data.
This commit cleans up the EEPROM access code for 16-bit access and makes
it easy to eventually introduce future support for 8-bit access.
Here's a list of notable changes brought by this patch:
- provide Global2 unlocked helpers for EEPROM commands
- remove eeprom_mutex, only reg_lock is necessary for driver functions
- eeprom_len is 0 for chip without EEPROM, so return it directly
- the Running bit must be 0 before r/w, so wait for Busy *and* Running
- remove now unused mv88e6xxx_wait and mv88e6xxx_reg_write
- other than that, the logic (in _{get,set}_eeprom16) didn't change
Chips with an 8-bit EEPROM access will require to implement the
8-suffixed variant of G2 helpers and the related flag:
#define MV88E6XXX_FLAGS_EEPROM8 \
(MV88E6XXX_FLAG_G2_EEPROM_CMD | \
MV88E6XXX_FLAG_G2_EEPROM_ADDR)
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 483 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 39 |
2 files changed, 239 insertions, 283 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 9ba21738569a..f95f1d49fdba 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c | |||
@@ -271,18 +271,6 @@ static int _mv88e6xxx_reg_write(struct mv88e6xxx_chip *chip, int addr, | |||
271 | return mv88e6xxx_write(chip, addr, reg, val); | 271 | return mv88e6xxx_write(chip, addr, reg, val); |
272 | } | 272 | } |
273 | 273 | ||
274 | static int mv88e6xxx_reg_write(struct mv88e6xxx_chip *chip, int addr, | ||
275 | int reg, u16 val) | ||
276 | { | ||
277 | int ret; | ||
278 | |||
279 | mutex_lock(&chip->reg_lock); | ||
280 | ret = _mv88e6xxx_reg_write(chip, addr, reg, val); | ||
281 | mutex_unlock(&chip->reg_lock); | ||
282 | |||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | static int mv88e6xxx_mdio_read_direct(struct mv88e6xxx_chip *chip, | 274 | static int mv88e6xxx_mdio_read_direct(struct mv88e6xxx_chip *chip, |
287 | int addr, int regnum) | 275 | int addr, int regnum) |
288 | { | 276 | { |
@@ -861,259 +849,12 @@ static int _mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int reg, int offset, | |||
861 | return -ETIMEDOUT; | 849 | return -ETIMEDOUT; |
862 | } | 850 | } |
863 | 851 | ||
864 | static int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int reg, | ||
865 | int offset, u16 mask) | ||
866 | { | ||
867 | int ret; | ||
868 | |||
869 | mutex_lock(&chip->reg_lock); | ||
870 | ret = _mv88e6xxx_wait(chip, reg, offset, mask); | ||
871 | mutex_unlock(&chip->reg_lock); | ||
872 | |||
873 | return ret; | ||
874 | } | ||
875 | |||
876 | static int mv88e6xxx_mdio_wait(struct mv88e6xxx_chip *chip) | 852 | static int mv88e6xxx_mdio_wait(struct mv88e6xxx_chip *chip) |
877 | { | 853 | { |
878 | return _mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_SMI_OP, | 854 | return _mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_SMI_OP, |
879 | GLOBAL2_SMI_OP_BUSY); | 855 | GLOBAL2_SMI_OP_BUSY); |
880 | } | 856 | } |
881 | 857 | ||
882 | static int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds) | ||
883 | { | ||
884 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
885 | |||
886 | return mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_EEPROM_OP, | ||
887 | GLOBAL2_EEPROM_OP_LOAD); | ||
888 | } | ||
889 | |||
890 | static int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds) | ||
891 | { | ||
892 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
893 | |||
894 | return mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_EEPROM_OP, | ||
895 | GLOBAL2_EEPROM_OP_BUSY); | ||
896 | } | ||
897 | |||
898 | static int mv88e6xxx_read_eeprom_word(struct dsa_switch *ds, int addr) | ||
899 | { | ||
900 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
901 | int ret; | ||
902 | |||
903 | mutex_lock(&chip->eeprom_mutex); | ||
904 | |||
905 | ret = mv88e6xxx_reg_write(chip, REG_GLOBAL2, GLOBAL2_EEPROM_OP, | ||
906 | GLOBAL2_EEPROM_OP_READ | | ||
907 | (addr & GLOBAL2_EEPROM_OP_ADDR_MASK)); | ||
908 | if (ret < 0) | ||
909 | goto error; | ||
910 | |||
911 | ret = mv88e6xxx_eeprom_busy_wait(ds); | ||
912 | if (ret < 0) | ||
913 | goto error; | ||
914 | |||
915 | ret = mv88e6xxx_reg_read(chip, REG_GLOBAL2, GLOBAL2_EEPROM_DATA); | ||
916 | error: | ||
917 | mutex_unlock(&chip->eeprom_mutex); | ||
918 | return ret; | ||
919 | } | ||
920 | |||
921 | static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) | ||
922 | { | ||
923 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
924 | |||
925 | if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEPROM)) | ||
926 | return chip->eeprom_len; | ||
927 | |||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, | ||
932 | struct ethtool_eeprom *eeprom, u8 *data) | ||
933 | { | ||
934 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
935 | int offset; | ||
936 | int len; | ||
937 | int ret; | ||
938 | |||
939 | if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEPROM)) | ||
940 | return -EOPNOTSUPP; | ||
941 | |||
942 | offset = eeprom->offset; | ||
943 | len = eeprom->len; | ||
944 | eeprom->len = 0; | ||
945 | |||
946 | eeprom->magic = 0xc3ec4951; | ||
947 | |||
948 | ret = mv88e6xxx_eeprom_load_wait(ds); | ||
949 | if (ret < 0) | ||
950 | return ret; | ||
951 | |||
952 | if (offset & 1) { | ||
953 | int word; | ||
954 | |||
955 | word = mv88e6xxx_read_eeprom_word(ds, offset >> 1); | ||
956 | if (word < 0) | ||
957 | return word; | ||
958 | |||
959 | *data++ = (word >> 8) & 0xff; | ||
960 | |||
961 | offset++; | ||
962 | len--; | ||
963 | eeprom->len++; | ||
964 | } | ||
965 | |||
966 | while (len >= 2) { | ||
967 | int word; | ||
968 | |||
969 | word = mv88e6xxx_read_eeprom_word(ds, offset >> 1); | ||
970 | if (word < 0) | ||
971 | return word; | ||
972 | |||
973 | *data++ = word & 0xff; | ||
974 | *data++ = (word >> 8) & 0xff; | ||
975 | |||
976 | offset += 2; | ||
977 | len -= 2; | ||
978 | eeprom->len += 2; | ||
979 | } | ||
980 | |||
981 | if (len) { | ||
982 | int word; | ||
983 | |||
984 | word = mv88e6xxx_read_eeprom_word(ds, offset >> 1); | ||
985 | if (word < 0) | ||
986 | return word; | ||
987 | |||
988 | *data++ = word & 0xff; | ||
989 | |||
990 | offset++; | ||
991 | len--; | ||
992 | eeprom->len++; | ||
993 | } | ||
994 | |||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | static int mv88e6xxx_eeprom_is_readonly(struct dsa_switch *ds) | ||
999 | { | ||
1000 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
1001 | int ret; | ||
1002 | |||
1003 | ret = mv88e6xxx_reg_read(chip, REG_GLOBAL2, GLOBAL2_EEPROM_OP); | ||
1004 | if (ret < 0) | ||
1005 | return ret; | ||
1006 | |||
1007 | if (!(ret & GLOBAL2_EEPROM_OP_WRITE_EN)) | ||
1008 | return -EROFS; | ||
1009 | |||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static int mv88e6xxx_write_eeprom_word(struct dsa_switch *ds, int addr, | ||
1014 | u16 data) | ||
1015 | { | ||
1016 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
1017 | int ret; | ||
1018 | |||
1019 | mutex_lock(&chip->eeprom_mutex); | ||
1020 | |||
1021 | ret = mv88e6xxx_reg_write(chip, REG_GLOBAL2, GLOBAL2_EEPROM_DATA, data); | ||
1022 | if (ret < 0) | ||
1023 | goto error; | ||
1024 | |||
1025 | ret = mv88e6xxx_reg_write(chip, REG_GLOBAL2, GLOBAL2_EEPROM_OP, | ||
1026 | GLOBAL2_EEPROM_OP_WRITE | | ||
1027 | (addr & GLOBAL2_EEPROM_OP_ADDR_MASK)); | ||
1028 | if (ret < 0) | ||
1029 | goto error; | ||
1030 | |||
1031 | ret = mv88e6xxx_eeprom_busy_wait(ds); | ||
1032 | error: | ||
1033 | mutex_unlock(&chip->eeprom_mutex); | ||
1034 | return ret; | ||
1035 | } | ||
1036 | |||
1037 | static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, | ||
1038 | struct ethtool_eeprom *eeprom, u8 *data) | ||
1039 | { | ||
1040 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
1041 | int offset; | ||
1042 | int ret; | ||
1043 | int len; | ||
1044 | |||
1045 | if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEPROM)) | ||
1046 | return -EOPNOTSUPP; | ||
1047 | |||
1048 | if (eeprom->magic != 0xc3ec4951) | ||
1049 | return -EINVAL; | ||
1050 | |||
1051 | ret = mv88e6xxx_eeprom_is_readonly(ds); | ||
1052 | if (ret) | ||
1053 | return ret; | ||
1054 | |||
1055 | offset = eeprom->offset; | ||
1056 | len = eeprom->len; | ||
1057 | eeprom->len = 0; | ||
1058 | |||
1059 | ret = mv88e6xxx_eeprom_load_wait(ds); | ||
1060 | if (ret < 0) | ||
1061 | return ret; | ||
1062 | |||
1063 | if (offset & 1) { | ||
1064 | int word; | ||
1065 | |||
1066 | word = mv88e6xxx_read_eeprom_word(ds, offset >> 1); | ||
1067 | if (word < 0) | ||
1068 | return word; | ||
1069 | |||
1070 | word = (*data++ << 8) | (word & 0xff); | ||
1071 | |||
1072 | ret = mv88e6xxx_write_eeprom_word(ds, offset >> 1, word); | ||
1073 | if (ret < 0) | ||
1074 | return ret; | ||
1075 | |||
1076 | offset++; | ||
1077 | len--; | ||
1078 | eeprom->len++; | ||
1079 | } | ||
1080 | |||
1081 | while (len >= 2) { | ||
1082 | int word; | ||
1083 | |||
1084 | word = *data++; | ||
1085 | word |= *data++ << 8; | ||
1086 | |||
1087 | ret = mv88e6xxx_write_eeprom_word(ds, offset >> 1, word); | ||
1088 | if (ret < 0) | ||
1089 | return ret; | ||
1090 | |||
1091 | offset += 2; | ||
1092 | len -= 2; | ||
1093 | eeprom->len += 2; | ||
1094 | } | ||
1095 | |||
1096 | if (len) { | ||
1097 | int word; | ||
1098 | |||
1099 | word = mv88e6xxx_read_eeprom_word(ds, offset >> 1); | ||
1100 | if (word < 0) | ||
1101 | return word; | ||
1102 | |||
1103 | word = (word & 0xff00) | *data++; | ||
1104 | |||
1105 | ret = mv88e6xxx_write_eeprom_word(ds, offset >> 1, word); | ||
1106 | if (ret < 0) | ||
1107 | return ret; | ||
1108 | |||
1109 | offset++; | ||
1110 | len--; | ||
1111 | eeprom->len++; | ||
1112 | } | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | static int _mv88e6xxx_atu_wait(struct mv88e6xxx_chip *chip) | 858 | static int _mv88e6xxx_atu_wait(struct mv88e6xxx_chip *chip) |
1118 | { | 859 | { |
1119 | return _mv88e6xxx_wait(chip, REG_GLOBAL, GLOBAL_ATU_OP, | 860 | return _mv88e6xxx_wait(chip, REG_GLOBAL, GLOBAL_ATU_OP, |
@@ -3261,6 +3002,58 @@ static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip) | |||
3261 | return err; | 3002 | return err; |
3262 | } | 3003 | } |
3263 | 3004 | ||
3005 | static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip) | ||
3006 | { | ||
3007 | return _mv88e6xxx_wait(chip, REG_GLOBAL2, GLOBAL2_EEPROM_CMD, | ||
3008 | GLOBAL2_EEPROM_CMD_BUSY | | ||
3009 | GLOBAL2_EEPROM_CMD_RUNNING); | ||
3010 | } | ||
3011 | |||
3012 | static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd) | ||
3013 | { | ||
3014 | int err; | ||
3015 | |||
3016 | err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_EEPROM_CMD, cmd); | ||
3017 | if (err) | ||
3018 | return err; | ||
3019 | |||
3020 | return mv88e6xxx_g2_eeprom_wait(chip); | ||
3021 | } | ||
3022 | |||
3023 | static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip, | ||
3024 | u8 addr, u16 *data) | ||
3025 | { | ||
3026 | u16 cmd = GLOBAL2_EEPROM_CMD_OP_READ | addr; | ||
3027 | int err; | ||
3028 | |||
3029 | err = mv88e6xxx_g2_eeprom_wait(chip); | ||
3030 | if (err) | ||
3031 | return err; | ||
3032 | |||
3033 | err = mv88e6xxx_g2_eeprom_cmd(chip, cmd); | ||
3034 | if (err) | ||
3035 | return err; | ||
3036 | |||
3037 | return mv88e6xxx_read(chip, REG_GLOBAL2, GLOBAL2_EEPROM_DATA, data); | ||
3038 | } | ||
3039 | |||
3040 | static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip, | ||
3041 | u8 addr, u16 data) | ||
3042 | { | ||
3043 | u16 cmd = GLOBAL2_EEPROM_CMD_OP_WRITE | addr; | ||
3044 | int err; | ||
3045 | |||
3046 | err = mv88e6xxx_g2_eeprom_wait(chip); | ||
3047 | if (err) | ||
3048 | return err; | ||
3049 | |||
3050 | err = mv88e6xxx_write(chip, REG_GLOBAL2, GLOBAL2_EEPROM_DATA, data); | ||
3051 | if (err) | ||
3052 | return err; | ||
3053 | |||
3054 | return mv88e6xxx_g2_eeprom_cmd(chip, cmd); | ||
3055 | } | ||
3056 | |||
3264 | static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) | 3057 | static int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) |
3265 | { | 3058 | { |
3266 | u16 reg; | 3059 | u16 reg; |
@@ -3345,9 +3138,6 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) | |||
3345 | chip->ds = ds; | 3138 | chip->ds = ds; |
3346 | ds->slave_mii_bus = chip->mdio_bus; | 3139 | ds->slave_mii_bus = chip->mdio_bus; |
3347 | 3140 | ||
3348 | if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEPROM)) | ||
3349 | mutex_init(&chip->eeprom_mutex); | ||
3350 | |||
3351 | mutex_lock(&chip->reg_lock); | 3141 | mutex_lock(&chip->reg_lock); |
3352 | 3142 | ||
3353 | err = mv88e6xxx_switch_reset(chip); | 3143 | err = mv88e6xxx_switch_reset(chip); |
@@ -3670,6 +3460,173 @@ static int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm) | |||
3670 | } | 3460 | } |
3671 | #endif /* CONFIG_NET_DSA_HWMON */ | 3461 | #endif /* CONFIG_NET_DSA_HWMON */ |
3672 | 3462 | ||
3463 | static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) | ||
3464 | { | ||
3465 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
3466 | |||
3467 | return chip->eeprom_len; | ||
3468 | } | ||
3469 | |||
3470 | static int mv88e6xxx_get_eeprom16(struct mv88e6xxx_chip *chip, | ||
3471 | struct ethtool_eeprom *eeprom, u8 *data) | ||
3472 | { | ||
3473 | unsigned int offset = eeprom->offset; | ||
3474 | unsigned int len = eeprom->len; | ||
3475 | u16 val; | ||
3476 | int err; | ||
3477 | |||
3478 | eeprom->len = 0; | ||
3479 | |||
3480 | if (offset & 1) { | ||
3481 | err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); | ||
3482 | if (err) | ||
3483 | return err; | ||
3484 | |||
3485 | *data++ = (val >> 8) & 0xff; | ||
3486 | |||
3487 | offset++; | ||
3488 | len--; | ||
3489 | eeprom->len++; | ||
3490 | } | ||
3491 | |||
3492 | while (len >= 2) { | ||
3493 | err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); | ||
3494 | if (err) | ||
3495 | return err; | ||
3496 | |||
3497 | *data++ = val & 0xff; | ||
3498 | *data++ = (val >> 8) & 0xff; | ||
3499 | |||
3500 | offset += 2; | ||
3501 | len -= 2; | ||
3502 | eeprom->len += 2; | ||
3503 | } | ||
3504 | |||
3505 | if (len) { | ||
3506 | err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); | ||
3507 | if (err) | ||
3508 | return err; | ||
3509 | |||
3510 | *data++ = val & 0xff; | ||
3511 | |||
3512 | offset++; | ||
3513 | len--; | ||
3514 | eeprom->len++; | ||
3515 | } | ||
3516 | |||
3517 | return 0; | ||
3518 | } | ||
3519 | |||
3520 | static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, | ||
3521 | struct ethtool_eeprom *eeprom, u8 *data) | ||
3522 | { | ||
3523 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
3524 | int err; | ||
3525 | |||
3526 | mutex_lock(&chip->reg_lock); | ||
3527 | |||
3528 | if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_EEPROM16)) | ||
3529 | err = mv88e6xxx_get_eeprom16(chip, eeprom, data); | ||
3530 | else | ||
3531 | err = -EOPNOTSUPP; | ||
3532 | |||
3533 | mutex_unlock(&chip->reg_lock); | ||
3534 | |||
3535 | if (err) | ||
3536 | return err; | ||
3537 | |||
3538 | eeprom->magic = 0xc3ec4951; | ||
3539 | |||
3540 | return 0; | ||
3541 | } | ||
3542 | |||
3543 | static int mv88e6xxx_set_eeprom16(struct mv88e6xxx_chip *chip, | ||
3544 | struct ethtool_eeprom *eeprom, u8 *data) | ||
3545 | { | ||
3546 | unsigned int offset = eeprom->offset; | ||
3547 | unsigned int len = eeprom->len; | ||
3548 | u16 val; | ||
3549 | int err; | ||
3550 | |||
3551 | /* Ensure the RO WriteEn bit is set */ | ||
3552 | err = mv88e6xxx_read(chip, REG_GLOBAL2, GLOBAL2_EEPROM_CMD, &val); | ||
3553 | if (err) | ||
3554 | return err; | ||
3555 | |||
3556 | if (!(val & GLOBAL2_EEPROM_CMD_WRITE_EN)) | ||
3557 | return -EROFS; | ||
3558 | |||
3559 | eeprom->len = 0; | ||
3560 | |||
3561 | if (offset & 1) { | ||
3562 | err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); | ||
3563 | if (err) | ||
3564 | return err; | ||
3565 | |||
3566 | val = (*data++ << 8) | (val & 0xff); | ||
3567 | |||
3568 | err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val); | ||
3569 | if (err) | ||
3570 | return err; | ||
3571 | |||
3572 | offset++; | ||
3573 | len--; | ||
3574 | eeprom->len++; | ||
3575 | } | ||
3576 | |||
3577 | while (len >= 2) { | ||
3578 | val = *data++; | ||
3579 | val |= *data++ << 8; | ||
3580 | |||
3581 | err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val); | ||
3582 | if (err) | ||
3583 | return err; | ||
3584 | |||
3585 | offset += 2; | ||
3586 | len -= 2; | ||
3587 | eeprom->len += 2; | ||
3588 | } | ||
3589 | |||
3590 | if (len) { | ||
3591 | err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); | ||
3592 | if (err) | ||
3593 | return err; | ||
3594 | |||
3595 | val = (val & 0xff00) | *data++; | ||
3596 | |||
3597 | err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val); | ||
3598 | if (err) | ||
3599 | return err; | ||
3600 | |||
3601 | offset++; | ||
3602 | len--; | ||
3603 | eeprom->len++; | ||
3604 | } | ||
3605 | |||
3606 | return 0; | ||
3607 | } | ||
3608 | |||
3609 | static int mv88e6xxx_set_eeprom(struct dsa_switch *ds, | ||
3610 | struct ethtool_eeprom *eeprom, u8 *data) | ||
3611 | { | ||
3612 | struct mv88e6xxx_chip *chip = ds_to_priv(ds); | ||
3613 | int err; | ||
3614 | |||
3615 | if (eeprom->magic != 0xc3ec4951) | ||
3616 | return -EINVAL; | ||
3617 | |||
3618 | mutex_lock(&chip->reg_lock); | ||
3619 | |||
3620 | if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_EEPROM16)) | ||
3621 | err = mv88e6xxx_set_eeprom16(chip, eeprom, data); | ||
3622 | else | ||
3623 | err = -EOPNOTSUPP; | ||
3624 | |||
3625 | mutex_unlock(&chip->reg_lock); | ||
3626 | |||
3627 | return err; | ||
3628 | } | ||
3629 | |||
3673 | static const struct mv88e6xxx_info mv88e6xxx_table[] = { | 3630 | static const struct mv88e6xxx_info mv88e6xxx_table[] = { |
3674 | [MV88E6085] = { | 3631 | [MV88E6085] = { |
3675 | .prod_num = PORT_SWITCH_ID_PROD_NUM_6085, | 3632 | .prod_num = PORT_SWITCH_ID_PROD_NUM_6085, |
@@ -4063,7 +4020,7 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) | |||
4063 | if (IS_ERR(chip->reset)) | 4020 | if (IS_ERR(chip->reset)) |
4064 | return PTR_ERR(chip->reset); | 4021 | return PTR_ERR(chip->reset); |
4065 | 4022 | ||
4066 | if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_EEPROM) && | 4023 | if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_EEPROM16) && |
4067 | !of_property_read_u32(np, "eeprom-length", &eeprom_len)) | 4024 | !of_property_read_u32(np, "eeprom-length", &eeprom_len)) |
4068 | chip->eeprom_len = eeprom_len; | 4025 | chip->eeprom_len = eeprom_len; |
4069 | 4026 | ||
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h index 99de41fc90a6..48d6ea77f9bd 100644 --- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | |||
@@ -318,13 +318,14 @@ | |||
318 | #define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 | 318 | #define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4 |
319 | #define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) | 319 | #define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) |
320 | #define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 | 320 | #define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 |
321 | #define GLOBAL2_EEPROM_OP 0x14 | 321 | #define GLOBAL2_EEPROM_CMD 0x14 |
322 | #define GLOBAL2_EEPROM_OP_BUSY BIT(15) | 322 | #define GLOBAL2_EEPROM_CMD_BUSY BIT(15) |
323 | #define GLOBAL2_EEPROM_OP_WRITE ((3 << 12) | GLOBAL2_EEPROM_OP_BUSY) | 323 | #define GLOBAL2_EEPROM_CMD_OP_WRITE ((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY) |
324 | #define GLOBAL2_EEPROM_OP_READ ((4 << 12) | GLOBAL2_EEPROM_OP_BUSY) | 324 | #define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY) |
325 | #define GLOBAL2_EEPROM_OP_LOAD BIT(11) | 325 | #define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY) |
326 | #define GLOBAL2_EEPROM_OP_WRITE_EN BIT(10) | 326 | #define GLOBAL2_EEPROM_CMD_RUNNING BIT(11) |
327 | #define GLOBAL2_EEPROM_OP_ADDR_MASK 0xff | 327 | #define GLOBAL2_EEPROM_CMD_WRITE_EN BIT(10) |
328 | #define GLOBAL2_EEPROM_CMD_ADDR_MASK 0xff | ||
328 | #define GLOBAL2_EEPROM_DATA 0x15 | 329 | #define GLOBAL2_EEPROM_DATA 0x15 |
329 | #define GLOBAL2_PTP_AVB_OP 0x16 | 330 | #define GLOBAL2_PTP_AVB_OP 0x16 |
330 | #define GLOBAL2_PTP_AVB_DATA 0x17 | 331 | #define GLOBAL2_PTP_AVB_DATA 0x17 |
@@ -387,11 +388,6 @@ enum mv88e6xxx_cap { | |||
387 | */ | 388 | */ |
388 | MV88E6XXX_CAP_EEE, | 389 | MV88E6XXX_CAP_EEE, |
389 | 390 | ||
390 | /* EEPROM Command and Data registers. | ||
391 | * See GLOBAL2_EEPROM_OP and GLOBAL2_EEPROM_DATA. | ||
392 | */ | ||
393 | MV88E6XXX_CAP_EEPROM, | ||
394 | |||
395 | /* Switch Global 2 Registers. | 391 | /* Switch Global 2 Registers. |
396 | * The device contains a second set of global 16-bit registers. | 392 | * The device contains a second set of global 16-bit registers. |
397 | */ | 393 | */ |
@@ -404,6 +400,8 @@ enum mv88e6xxx_cap { | |||
404 | MV88E6XXX_CAP_G2_PVT_DATA, /* (0x0c) Cross Chip Port VLAN Data */ | 400 | MV88E6XXX_CAP_G2_PVT_DATA, /* (0x0c) Cross Chip Port VLAN Data */ |
405 | MV88E6XXX_CAP_G2_SWITCH_MAC, /* (0x0d) Switch MAC/WoL/WoF */ | 401 | MV88E6XXX_CAP_G2_SWITCH_MAC, /* (0x0d) Switch MAC/WoL/WoF */ |
406 | MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */ | 402 | MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */ |
403 | MV88E6XXX_CAP_G2_EEPROM_CMD, /* (0x14) EEPROM Command */ | ||
404 | MV88E6XXX_CAP_G2_EEPROM_DATA, /* (0x15) EEPROM Data */ | ||
407 | 405 | ||
408 | /* Multi-chip Addressing Mode. | 406 | /* Multi-chip Addressing Mode. |
409 | * Some chips require an indirect SMI access when their SMI device | 407 | * Some chips require an indirect SMI access when their SMI device |
@@ -443,7 +441,6 @@ enum mv88e6xxx_cap { | |||
443 | 441 | ||
444 | /* Bitmask of capabilities */ | 442 | /* Bitmask of capabilities */ |
445 | #define MV88E6XXX_FLAG_EEE BIT(MV88E6XXX_CAP_EEE) | 443 | #define MV88E6XXX_FLAG_EEE BIT(MV88E6XXX_CAP_EEE) |
446 | #define MV88E6XXX_FLAG_EEPROM BIT(MV88E6XXX_CAP_EEPROM) | ||
447 | #define MV88E6XXX_FLAG_GLOBAL2 BIT(MV88E6XXX_CAP_GLOBAL2) | 444 | #define MV88E6XXX_FLAG_GLOBAL2 BIT(MV88E6XXX_CAP_GLOBAL2) |
448 | #define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT(MV88E6XXX_CAP_G2_MGMT_EN_2X) | 445 | #define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT(MV88E6XXX_CAP_G2_MGMT_EN_2X) |
449 | #define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT(MV88E6XXX_CAP_G2_MGMT_EN_0X) | 446 | #define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT(MV88E6XXX_CAP_G2_MGMT_EN_0X) |
@@ -453,6 +450,8 @@ enum mv88e6xxx_cap { | |||
453 | #define MV88E6XXX_FLAG_G2_PVT_DATA BIT(MV88E6XXX_CAP_G2_PVT_DATA) | 450 | #define MV88E6XXX_FLAG_G2_PVT_DATA BIT(MV88E6XXX_CAP_G2_PVT_DATA) |
454 | #define MV88E6XXX_FLAG_G2_SWITCH_MAC BIT(MV88E6XXX_CAP_G2_SWITCH_MAC) | 451 | #define MV88E6XXX_FLAG_G2_SWITCH_MAC BIT(MV88E6XXX_CAP_G2_SWITCH_MAC) |
455 | #define MV88E6XXX_FLAG_G2_POT BIT(MV88E6XXX_CAP_G2_POT) | 452 | #define MV88E6XXX_FLAG_G2_POT BIT(MV88E6XXX_CAP_G2_POT) |
453 | #define MV88E6XXX_FLAG_G2_EEPROM_CMD BIT(MV88E6XXX_CAP_G2_EEPROM_CMD) | ||
454 | #define MV88E6XXX_FLAG_G2_EEPROM_DATA BIT(MV88E6XXX_CAP_G2_EEPROM_DATA) | ||
456 | #define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP) | 455 | #define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP) |
457 | #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) | 456 | #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) |
458 | #define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE) | 457 | #define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE) |
@@ -462,6 +461,11 @@ enum mv88e6xxx_cap { | |||
462 | #define MV88E6XXX_FLAG_TEMP_LIMIT BIT(MV88E6XXX_CAP_TEMP_LIMIT) | 461 | #define MV88E6XXX_FLAG_TEMP_LIMIT BIT(MV88E6XXX_CAP_TEMP_LIMIT) |
463 | #define MV88E6XXX_FLAG_VTU BIT(MV88E6XXX_CAP_VTU) | 462 | #define MV88E6XXX_FLAG_VTU BIT(MV88E6XXX_CAP_VTU) |
464 | 463 | ||
464 | /* EEPROM Programming via Global2 with 16-bit data */ | ||
465 | #define MV88E6XXX_FLAGS_EEPROM16 \ | ||
466 | (MV88E6XXX_FLAG_G2_EEPROM_CMD | \ | ||
467 | MV88E6XXX_FLAG_G2_EEPROM_DATA) | ||
468 | |||
465 | /* Ingress Rate Limit unit */ | 469 | /* Ingress Rate Limit unit */ |
466 | #define MV88E6XXX_FLAGS_IRL \ | 470 | #define MV88E6XXX_FLAGS_IRL \ |
467 | (MV88E6XXX_FLAG_G2_IRL_CMD | \ | 471 | (MV88E6XXX_FLAG_G2_IRL_CMD | \ |
@@ -513,7 +517,6 @@ enum mv88e6xxx_cap { | |||
513 | 517 | ||
514 | #define MV88E6XXX_FLAGS_FAMILY_6320 \ | 518 | #define MV88E6XXX_FLAGS_FAMILY_6320 \ |
515 | (MV88E6XXX_FLAG_EEE | \ | 519 | (MV88E6XXX_FLAG_EEE | \ |
516 | MV88E6XXX_FLAG_EEPROM | \ | ||
517 | MV88E6XXX_FLAG_GLOBAL2 | \ | 520 | MV88E6XXX_FLAG_GLOBAL2 | \ |
518 | MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ | 521 | MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ |
519 | MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ | 522 | MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ |
@@ -525,6 +528,7 @@ enum mv88e6xxx_cap { | |||
525 | MV88E6XXX_FLAG_TEMP | \ | 528 | MV88E6XXX_FLAG_TEMP | \ |
526 | MV88E6XXX_FLAG_TEMP_LIMIT | \ | 529 | MV88E6XXX_FLAG_TEMP_LIMIT | \ |
527 | MV88E6XXX_FLAG_VTU | \ | 530 | MV88E6XXX_FLAG_VTU | \ |
531 | MV88E6XXX_FLAGS_EEPROM16 | \ | ||
528 | MV88E6XXX_FLAGS_IRL | \ | 532 | MV88E6XXX_FLAGS_IRL | \ |
529 | MV88E6XXX_FLAGS_PVT) | 533 | MV88E6XXX_FLAGS_PVT) |
530 | 534 | ||
@@ -545,7 +549,6 @@ enum mv88e6xxx_cap { | |||
545 | 549 | ||
546 | #define MV88E6XXX_FLAGS_FAMILY_6352 \ | 550 | #define MV88E6XXX_FLAGS_FAMILY_6352 \ |
547 | (MV88E6XXX_FLAG_EEE | \ | 551 | (MV88E6XXX_FLAG_EEE | \ |
548 | MV88E6XXX_FLAG_EEPROM | \ | ||
549 | MV88E6XXX_FLAG_GLOBAL2 | \ | 552 | MV88E6XXX_FLAG_GLOBAL2 | \ |
550 | MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ | 553 | MV88E6XXX_FLAG_G2_MGMT_EN_2X | \ |
551 | MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ | 554 | MV88E6XXX_FLAG_G2_MGMT_EN_0X | \ |
@@ -558,6 +561,7 @@ enum mv88e6xxx_cap { | |||
558 | MV88E6XXX_FLAG_TEMP | \ | 561 | MV88E6XXX_FLAG_TEMP | \ |
559 | MV88E6XXX_FLAG_TEMP_LIMIT | \ | 562 | MV88E6XXX_FLAG_TEMP_LIMIT | \ |
560 | MV88E6XXX_FLAG_VTU | \ | 563 | MV88E6XXX_FLAG_VTU | \ |
564 | MV88E6XXX_FLAGS_EEPROM16 | \ | ||
561 | MV88E6XXX_FLAGS_IRL | \ | 565 | MV88E6XXX_FLAGS_IRL | \ |
562 | MV88E6XXX_FLAGS_PVT) | 566 | MV88E6XXX_FLAGS_PVT) |
563 | 567 | ||
@@ -629,11 +633,6 @@ struct mv88e6xxx_chip { | |||
629 | */ | 633 | */ |
630 | struct mutex stats_mutex; | 634 | struct mutex stats_mutex; |
631 | 635 | ||
632 | /* This mutex serializes eeprom access for chips with | ||
633 | * eeprom support. | ||
634 | */ | ||
635 | struct mutex eeprom_mutex; | ||
636 | |||
637 | struct mv88e6xxx_priv_port ports[DSA_MAX_PORTS]; | 636 | struct mv88e6xxx_priv_port ports[DSA_MAX_PORTS]; |
638 | 637 | ||
639 | /* A switch may have a GPIO line tied to its reset pin. Parse | 638 | /* A switch may have a GPIO line tied to its reset pin. Parse |