diff options
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx.c')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 408 |
1 files changed, 298 insertions, 110 deletions
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 561342466076..9978245474a7 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c | |||
@@ -517,6 +517,18 @@ static bool mv88e6xxx_6185_family(struct dsa_switch *ds) | |||
517 | return false; | 517 | return false; |
518 | } | 518 | } |
519 | 519 | ||
520 | static bool mv88e6xxx_6320_family(struct dsa_switch *ds) | ||
521 | { | ||
522 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
523 | |||
524 | switch (ps->id) { | ||
525 | case PORT_SWITCH_ID_6320: | ||
526 | case PORT_SWITCH_ID_6321: | ||
527 | return true; | ||
528 | } | ||
529 | return false; | ||
530 | } | ||
531 | |||
520 | static bool mv88e6xxx_6351_family(struct dsa_switch *ds) | 532 | static bool mv88e6xxx_6351_family(struct dsa_switch *ds) |
521 | { | 533 | { |
522 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 534 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
@@ -565,7 +577,7 @@ static int _mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) | |||
565 | { | 577 | { |
566 | int ret; | 578 | int ret; |
567 | 579 | ||
568 | if (mv88e6xxx_6352_family(ds)) | 580 | if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds)) |
569 | port = (port + 1) << 5; | 581 | port = (port + 1) << 5; |
570 | 582 | ||
571 | /* Snapshot the hardware statistics counters for this port. */ | 583 | /* Snapshot the hardware statistics counters for this port. */ |
@@ -796,54 +808,6 @@ void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, | |||
796 | } | 808 | } |
797 | } | 809 | } |
798 | 810 | ||
799 | #ifdef CONFIG_NET_DSA_HWMON | ||
800 | |||
801 | int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) | ||
802 | { | ||
803 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
804 | int ret; | ||
805 | int val; | ||
806 | |||
807 | *temp = 0; | ||
808 | |||
809 | mutex_lock(&ps->smi_mutex); | ||
810 | |||
811 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); | ||
812 | if (ret < 0) | ||
813 | goto error; | ||
814 | |||
815 | /* Enable temperature sensor */ | ||
816 | ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); | ||
817 | if (ret < 0) | ||
818 | goto error; | ||
819 | |||
820 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); | ||
821 | if (ret < 0) | ||
822 | goto error; | ||
823 | |||
824 | /* Wait for temperature to stabilize */ | ||
825 | usleep_range(10000, 12000); | ||
826 | |||
827 | val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); | ||
828 | if (val < 0) { | ||
829 | ret = val; | ||
830 | goto error; | ||
831 | } | ||
832 | |||
833 | /* Disable temperature sensor */ | ||
834 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); | ||
835 | if (ret < 0) | ||
836 | goto error; | ||
837 | |||
838 | *temp = ((val & 0x1f) - 5) * 5; | ||
839 | |||
840 | error: | ||
841 | _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); | ||
842 | mutex_unlock(&ps->smi_mutex); | ||
843 | return ret; | ||
844 | } | ||
845 | #endif /* CONFIG_NET_DSA_HWMON */ | ||
846 | |||
847 | /* Must be called with SMI lock held */ | 811 | /* Must be called with SMI lock held */ |
848 | static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, | 812 | static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, |
849 | u16 mask) | 813 | u16 mask) |
@@ -1000,7 +964,7 @@ static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd) | |||
1000 | { | 964 | { |
1001 | int ret; | 965 | int ret; |
1002 | 966 | ||
1003 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x01, fid); | 967 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid); |
1004 | if (ret < 0) | 968 | if (ret < 0) |
1005 | return ret; | 969 | return ret; |
1006 | 970 | ||
@@ -1127,7 +1091,7 @@ int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask) | |||
1127 | ps->bridge_mask[fid] = br_port_mask; | 1091 | ps->bridge_mask[fid] = br_port_mask; |
1128 | 1092 | ||
1129 | if (fid != ps->fid[port]) { | 1093 | if (fid != ps->fid[port]) { |
1130 | ps->fid_mask |= 1 << ps->fid[port]; | 1094 | clear_bit(ps->fid[port], ps->fid_bitmap); |
1131 | ps->fid[port] = fid; | 1095 | ps->fid[port] = fid; |
1132 | ret = _mv88e6xxx_update_bridge_config(ds, fid); | 1096 | ret = _mv88e6xxx_update_bridge_config(ds, fid); |
1133 | } | 1097 | } |
@@ -1161,9 +1125,16 @@ int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask) | |||
1161 | 1125 | ||
1162 | mutex_lock(&ps->smi_mutex); | 1126 | mutex_lock(&ps->smi_mutex); |
1163 | 1127 | ||
1164 | newfid = __ffs(ps->fid_mask); | 1128 | newfid = find_next_zero_bit(ps->fid_bitmap, VLAN_N_VID, 1); |
1129 | if (unlikely(newfid > ps->num_ports)) { | ||
1130 | netdev_err(ds->ports[port], "all first %d FIDs are used\n", | ||
1131 | ps->num_ports); | ||
1132 | ret = -ENOSPC; | ||
1133 | goto unlock; | ||
1134 | } | ||
1135 | |||
1165 | ps->fid[port] = newfid; | 1136 | ps->fid[port] = newfid; |
1166 | ps->fid_mask &= ~(1 << newfid); | 1137 | set_bit(newfid, ps->fid_bitmap); |
1167 | ps->bridge_mask[fid] &= ~(1 << port); | 1138 | ps->bridge_mask[fid] &= ~(1 << port); |
1168 | ps->bridge_mask[newfid] = 1 << port; | 1139 | ps->bridge_mask[newfid] = 1 << port; |
1169 | 1140 | ||
@@ -1171,6 +1142,7 @@ int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask) | |||
1171 | if (!ret) | 1142 | if (!ret) |
1172 | ret = _mv88e6xxx_update_bridge_config(ds, newfid); | 1143 | ret = _mv88e6xxx_update_bridge_config(ds, newfid); |
1173 | 1144 | ||
1145 | unlock: | ||
1174 | mutex_unlock(&ps->smi_mutex); | 1146 | mutex_unlock(&ps->smi_mutex); |
1175 | 1147 | ||
1176 | return ret; | 1148 | return ret; |
@@ -1210,8 +1182,8 @@ int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state) | |||
1210 | return 0; | 1182 | return 0; |
1211 | } | 1183 | } |
1212 | 1184 | ||
1213 | static int __mv88e6xxx_write_addr(struct dsa_switch *ds, | 1185 | static int _mv88e6xxx_atu_mac_write(struct dsa_switch *ds, |
1214 | const unsigned char *addr) | 1186 | const unsigned char *addr) |
1215 | { | 1187 | { |
1216 | int i, ret; | 1188 | int i, ret; |
1217 | 1189 | ||
@@ -1226,7 +1198,7 @@ static int __mv88e6xxx_write_addr(struct dsa_switch *ds, | |||
1226 | return 0; | 1198 | return 0; |
1227 | } | 1199 | } |
1228 | 1200 | ||
1229 | static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr) | 1201 | static int _mv88e6xxx_atu_mac_read(struct dsa_switch *ds, unsigned char *addr) |
1230 | { | 1202 | { |
1231 | int i, ret; | 1203 | int i, ret; |
1232 | 1204 | ||
@@ -1242,29 +1214,74 @@ static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr) | |||
1242 | return 0; | 1214 | return 0; |
1243 | } | 1215 | } |
1244 | 1216 | ||
1245 | static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port, | 1217 | static int _mv88e6xxx_atu_load(struct dsa_switch *ds, |
1246 | const unsigned char *addr, int state) | 1218 | struct mv88e6xxx_atu_entry *entry) |
1247 | { | 1219 | { |
1248 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 1220 | u16 reg = 0; |
1249 | u8 fid = ps->fid[port]; | ||
1250 | int ret; | 1221 | int ret; |
1251 | 1222 | ||
1252 | ret = _mv88e6xxx_atu_wait(ds); | 1223 | ret = _mv88e6xxx_atu_wait(ds); |
1253 | if (ret < 0) | 1224 | if (ret < 0) |
1254 | return ret; | 1225 | return ret; |
1255 | 1226 | ||
1256 | ret = __mv88e6xxx_write_addr(ds, addr); | 1227 | ret = _mv88e6xxx_atu_mac_write(ds, entry->mac); |
1257 | if (ret < 0) | 1228 | if (ret < 0) |
1258 | return ret; | 1229 | return ret; |
1259 | 1230 | ||
1260 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, | 1231 | if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) { |
1261 | (0x10 << port) | state); | 1232 | unsigned int mask, shift; |
1262 | if (ret) | 1233 | |
1234 | if (entry->trunk) { | ||
1235 | reg |= GLOBAL_ATU_DATA_TRUNK; | ||
1236 | mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK; | ||
1237 | shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT; | ||
1238 | } else { | ||
1239 | mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK; | ||
1240 | shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT; | ||
1241 | } | ||
1242 | |||
1243 | reg |= (entry->portv_trunkid << shift) & mask; | ||
1244 | } | ||
1245 | |||
1246 | reg |= entry->state & GLOBAL_ATU_DATA_STATE_MASK; | ||
1247 | |||
1248 | ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, reg); | ||
1249 | if (ret < 0) | ||
1263 | return ret; | 1250 | return ret; |
1264 | 1251 | ||
1265 | ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_LOAD_DB); | 1252 | return _mv88e6xxx_atu_cmd(ds, entry->fid, GLOBAL_ATU_OP_LOAD_DB); |
1253 | } | ||
1254 | |||
1255 | static int _mv88e6xxx_port_vid_to_fid(struct dsa_switch *ds, int port, u16 vid) | ||
1256 | { | ||
1257 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1266 | 1258 | ||
1267 | return ret; | 1259 | if (vid == 0) |
1260 | return ps->fid[port]; | ||
1261 | |||
1262 | return -ENOENT; | ||
1263 | } | ||
1264 | |||
1265 | static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port, | ||
1266 | const unsigned char *addr, u16 vid, | ||
1267 | u8 state) | ||
1268 | { | ||
1269 | struct mv88e6xxx_atu_entry entry = { 0 }; | ||
1270 | int ret; | ||
1271 | |||
1272 | ret = _mv88e6xxx_port_vid_to_fid(ds, port, vid); | ||
1273 | if (ret < 0) | ||
1274 | return ret; | ||
1275 | |||
1276 | entry.fid = ret; | ||
1277 | entry.state = state; | ||
1278 | ether_addr_copy(entry.mac, addr); | ||
1279 | if (state != GLOBAL_ATU_DATA_STATE_UNUSED) { | ||
1280 | entry.trunk = false; | ||
1281 | entry.portv_trunkid = BIT(port); | ||
1282 | } | ||
1283 | |||
1284 | return _mv88e6xxx_atu_load(ds, &entry); | ||
1268 | } | 1285 | } |
1269 | 1286 | ||
1270 | int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, | 1287 | int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, |
@@ -1277,7 +1294,7 @@ int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, | |||
1277 | int ret; | 1294 | int ret; |
1278 | 1295 | ||
1279 | mutex_lock(&ps->smi_mutex); | 1296 | mutex_lock(&ps->smi_mutex); |
1280 | ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, state); | 1297 | ret = _mv88e6xxx_port_fdb_load(ds, port, addr, vid, state); |
1281 | mutex_unlock(&ps->smi_mutex); | 1298 | mutex_unlock(&ps->smi_mutex); |
1282 | 1299 | ||
1283 | return ret; | 1300 | return ret; |
@@ -1290,61 +1307,99 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, | |||
1290 | int ret; | 1307 | int ret; |
1291 | 1308 | ||
1292 | mutex_lock(&ps->smi_mutex); | 1309 | mutex_lock(&ps->smi_mutex); |
1293 | ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, | 1310 | ret = _mv88e6xxx_port_fdb_load(ds, port, addr, vid, |
1294 | GLOBAL_ATU_DATA_STATE_UNUSED); | 1311 | GLOBAL_ATU_DATA_STATE_UNUSED); |
1295 | mutex_unlock(&ps->smi_mutex); | 1312 | mutex_unlock(&ps->smi_mutex); |
1296 | 1313 | ||
1297 | return ret; | 1314 | return ret; |
1298 | } | 1315 | } |
1299 | 1316 | ||
1300 | static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, | 1317 | static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid, |
1301 | unsigned char *addr, bool *is_static) | 1318 | const unsigned char *addr, |
1319 | struct mv88e6xxx_atu_entry *entry) | ||
1302 | { | 1320 | { |
1303 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 1321 | struct mv88e6xxx_atu_entry next = { 0 }; |
1304 | u8 fid = ps->fid[port]; | 1322 | int ret; |
1305 | int ret, state; | 1323 | |
1324 | next.fid = fid; | ||
1306 | 1325 | ||
1307 | ret = _mv88e6xxx_atu_wait(ds); | 1326 | ret = _mv88e6xxx_atu_wait(ds); |
1308 | if (ret < 0) | 1327 | if (ret < 0) |
1309 | return ret; | 1328 | return ret; |
1310 | 1329 | ||
1311 | ret = __mv88e6xxx_write_addr(ds, addr); | 1330 | ret = _mv88e6xxx_atu_mac_write(ds, addr); |
1312 | if (ret < 0) | 1331 | if (ret < 0) |
1313 | return ret; | 1332 | return ret; |
1314 | 1333 | ||
1315 | do { | 1334 | ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB); |
1316 | ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB); | 1335 | if (ret < 0) |
1317 | if (ret < 0) | 1336 | return ret; |
1318 | return ret; | ||
1319 | 1337 | ||
1320 | ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA); | 1338 | ret = _mv88e6xxx_atu_mac_read(ds, next.mac); |
1321 | if (ret < 0) | 1339 | if (ret < 0) |
1322 | return ret; | 1340 | return ret; |
1323 | state = ret & GLOBAL_ATU_DATA_STATE_MASK; | ||
1324 | if (state == GLOBAL_ATU_DATA_STATE_UNUSED) | ||
1325 | return -ENOENT; | ||
1326 | } while (!(((ret >> 4) & 0xff) & (1 << port))); | ||
1327 | 1341 | ||
1328 | ret = __mv88e6xxx_read_addr(ds, addr); | 1342 | ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA); |
1329 | if (ret < 0) | 1343 | if (ret < 0) |
1330 | return ret; | 1344 | return ret; |
1331 | 1345 | ||
1332 | *is_static = state == (is_multicast_ether_addr(addr) ? | 1346 | next.state = ret & GLOBAL_ATU_DATA_STATE_MASK; |
1333 | GLOBAL_ATU_DATA_STATE_MC_STATIC : | 1347 | if (next.state != GLOBAL_ATU_DATA_STATE_UNUSED) { |
1334 | GLOBAL_ATU_DATA_STATE_UC_STATIC); | 1348 | unsigned int mask, shift; |
1349 | |||
1350 | if (ret & GLOBAL_ATU_DATA_TRUNK) { | ||
1351 | next.trunk = true; | ||
1352 | mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK; | ||
1353 | shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT; | ||
1354 | } else { | ||
1355 | next.trunk = false; | ||
1356 | mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK; | ||
1357 | shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT; | ||
1358 | } | ||
1335 | 1359 | ||
1360 | next.portv_trunkid = (ret & mask) >> shift; | ||
1361 | } | ||
1362 | |||
1363 | *entry = next; | ||
1336 | return 0; | 1364 | return 0; |
1337 | } | 1365 | } |
1338 | 1366 | ||
1339 | /* get next entry for port */ | 1367 | /* get next entry for port */ |
1340 | int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, | 1368 | int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, |
1341 | unsigned char *addr, bool *is_static) | 1369 | unsigned char *addr, u16 *vid, bool *is_static) |
1342 | { | 1370 | { |
1343 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 1371 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
1372 | struct mv88e6xxx_atu_entry next; | ||
1373 | u16 fid; | ||
1344 | int ret; | 1374 | int ret; |
1345 | 1375 | ||
1346 | mutex_lock(&ps->smi_mutex); | 1376 | mutex_lock(&ps->smi_mutex); |
1347 | ret = __mv88e6xxx_port_getnext(ds, port, addr, is_static); | 1377 | |
1378 | ret = _mv88e6xxx_port_vid_to_fid(ds, port, *vid); | ||
1379 | if (ret < 0) | ||
1380 | goto unlock; | ||
1381 | fid = ret; | ||
1382 | |||
1383 | do { | ||
1384 | if (is_broadcast_ether_addr(addr)) { | ||
1385 | ret = -ENOENT; | ||
1386 | goto unlock; | ||
1387 | } | ||
1388 | |||
1389 | ret = _mv88e6xxx_atu_getnext(ds, fid, addr, &next); | ||
1390 | if (ret < 0) | ||
1391 | goto unlock; | ||
1392 | |||
1393 | ether_addr_copy(addr, next.mac); | ||
1394 | |||
1395 | if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED) | ||
1396 | continue; | ||
1397 | } while (next.trunk || (next.portv_trunkid & BIT(port)) == 0); | ||
1398 | |||
1399 | *is_static = next.state == (is_multicast_ether_addr(addr) ? | ||
1400 | GLOBAL_ATU_DATA_STATE_MC_STATIC : | ||
1401 | GLOBAL_ATU_DATA_STATE_UC_STATIC); | ||
1402 | unlock: | ||
1348 | mutex_unlock(&ps->smi_mutex); | 1403 | mutex_unlock(&ps->smi_mutex); |
1349 | 1404 | ||
1350 | return ret; | 1405 | return ret; |
@@ -1377,7 +1432,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) | |||
1377 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 1432 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1378 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || | 1433 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
1379 | mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || | 1434 | mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || |
1380 | mv88e6xxx_6065_family(ds)) { | 1435 | mv88e6xxx_6065_family(ds) || mv88e6xxx_6320_family(ds)) { |
1381 | /* MAC Forcing register: don't force link, speed, | 1436 | /* MAC Forcing register: don't force link, speed, |
1382 | * duplex or flow control state to any particular | 1437 | * duplex or flow control state to any particular |
1383 | * values on physical ports, but force the CPU port | 1438 | * values on physical ports, but force the CPU port |
@@ -1423,7 +1478,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) | |||
1423 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 1478 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1424 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || | 1479 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
1425 | mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || | 1480 | mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || |
1426 | mv88e6xxx_6185_family(ds)) | 1481 | mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds)) |
1427 | reg = PORT_CONTROL_IGMP_MLD_SNOOP | | 1482 | reg = PORT_CONTROL_IGMP_MLD_SNOOP | |
1428 | PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP | | 1483 | PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP | |
1429 | PORT_CONTROL_STATE_FORWARDING; | 1484 | PORT_CONTROL_STATE_FORWARDING; |
@@ -1431,7 +1486,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) | |||
1431 | if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) | 1486 | if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) |
1432 | reg |= PORT_CONTROL_DSA_TAG; | 1487 | reg |= PORT_CONTROL_DSA_TAG; |
1433 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 1488 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1434 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { | 1489 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
1490 | mv88e6xxx_6320_family(ds)) { | ||
1435 | if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) | 1491 | if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) |
1436 | reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA; | 1492 | reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA; |
1437 | else | 1493 | else |
@@ -1441,14 +1497,15 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) | |||
1441 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 1497 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1442 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || | 1498 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
1443 | mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || | 1499 | mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || |
1444 | mv88e6xxx_6185_family(ds)) { | 1500 | mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds)) { |
1445 | if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) | 1501 | if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) |
1446 | reg |= PORT_CONTROL_EGRESS_ADD_TAG; | 1502 | reg |= PORT_CONTROL_EGRESS_ADD_TAG; |
1447 | } | 1503 | } |
1448 | } | 1504 | } |
1449 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 1505 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1450 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || | 1506 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
1451 | mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds)) { | 1507 | mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || |
1508 | mv88e6xxx_6320_family(ds)) { | ||
1452 | if (ds->dsa_port_mask & (1 << port)) | 1509 | if (ds->dsa_port_mask & (1 << port)) |
1453 | reg |= PORT_CONTROL_FRAME_MODE_DSA; | 1510 | reg |= PORT_CONTROL_FRAME_MODE_DSA; |
1454 | if (port == dsa_upstream_port(ds)) | 1511 | if (port == dsa_upstream_port(ds)) |
@@ -1473,11 +1530,11 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) | |||
1473 | reg = 0; | 1530 | reg = 0; |
1474 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 1531 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1475 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || | 1532 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
1476 | mv88e6xxx_6095_family(ds)) | 1533 | mv88e6xxx_6095_family(ds) || mv88e6xxx_6320_family(ds)) |
1477 | reg = PORT_CONTROL_2_MAP_DA; | 1534 | reg = PORT_CONTROL_2_MAP_DA; |
1478 | 1535 | ||
1479 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 1536 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1480 | mv88e6xxx_6165_family(ds)) | 1537 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6320_family(ds)) |
1481 | reg |= PORT_CONTROL_2_JUMBO_10240; | 1538 | reg |= PORT_CONTROL_2_JUMBO_10240; |
1482 | 1539 | ||
1483 | if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) { | 1540 | if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) { |
@@ -1514,7 +1571,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) | |||
1514 | goto abort; | 1571 | goto abort; |
1515 | 1572 | ||
1516 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 1573 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1517 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { | 1574 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
1575 | mv88e6xxx_6320_family(ds)) { | ||
1518 | /* Do not limit the period of time that this port can | 1576 | /* Do not limit the period of time that this port can |
1519 | * be paused for by the remote end or the period of | 1577 | * be paused for by the remote end or the period of |
1520 | * time that this port can pause the remote end. | 1578 | * time that this port can pause the remote end. |
@@ -1564,7 +1622,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) | |||
1564 | 1622 | ||
1565 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 1623 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1566 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || | 1624 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
1567 | mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) { | 1625 | mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || |
1626 | mv88e6xxx_6320_family(ds)) { | ||
1568 | /* Rate Control: disable ingress rate limiting. */ | 1627 | /* Rate Control: disable ingress rate limiting. */ |
1569 | ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), | 1628 | ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), |
1570 | PORT_RATE_CONTROL, 0x0001); | 1629 | PORT_RATE_CONTROL, 0x0001); |
@@ -1584,9 +1643,9 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) | |||
1584 | * ports, and allow each of the 'real' ports to only talk to | 1643 | * ports, and allow each of the 'real' ports to only talk to |
1585 | * the upstream port. | 1644 | * the upstream port. |
1586 | */ | 1645 | */ |
1587 | fid = __ffs(ps->fid_mask); | 1646 | fid = port + 1; |
1588 | ps->fid[port] = fid; | 1647 | ps->fid[port] = fid; |
1589 | ps->fid_mask &= ~(1 << fid); | 1648 | set_bit(fid, ps->fid_bitmap); |
1590 | 1649 | ||
1591 | if (!dsa_is_cpu_port(ds, port)) | 1650 | if (!dsa_is_cpu_port(ds, port)) |
1592 | ps->bridge_mask[fid] = 1 << port; | 1651 | ps->bridge_mask[fid] = 1 << port; |
@@ -1683,7 +1742,7 @@ static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds, | |||
1683 | unsigned char addr[6]; | 1742 | unsigned char addr[6]; |
1684 | int ret, data, state; | 1743 | int ret, data, state; |
1685 | 1744 | ||
1686 | ret = __mv88e6xxx_write_addr(ds, bcast); | 1745 | ret = _mv88e6xxx_atu_mac_write(ds, bcast); |
1687 | if (ret < 0) | 1746 | if (ret < 0) |
1688 | return ret; | 1747 | return ret; |
1689 | 1748 | ||
@@ -1698,7 +1757,7 @@ static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds, | |||
1698 | state = data & GLOBAL_ATU_DATA_STATE_MASK; | 1757 | state = data & GLOBAL_ATU_DATA_STATE_MASK; |
1699 | if (state == GLOBAL_ATU_DATA_STATE_UNUSED) | 1758 | if (state == GLOBAL_ATU_DATA_STATE_UNUSED) |
1700 | break; | 1759 | break; |
1701 | ret = __mv88e6xxx_read_addr(ds, addr); | 1760 | ret = _mv88e6xxx_atu_mac_read(ds, addr); |
1702 | if (ret < 0) | 1761 | if (ret < 0) |
1703 | return ret; | 1762 | return ret; |
1704 | mv88e6xxx_atu_show_entry(s, dbnum, addr, data); | 1763 | mv88e6xxx_atu_show_entry(s, dbnum, addr, data); |
@@ -1885,8 +1944,6 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) | |||
1885 | 1944 | ||
1886 | ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0; | 1945 | ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0; |
1887 | 1946 | ||
1888 | ps->fid_mask = (1 << DSA_MAX_PORTS) - 1; | ||
1889 | |||
1890 | INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work); | 1947 | INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work); |
1891 | 1948 | ||
1892 | name = kasprintf(GFP_KERNEL, "dsa%d", ds->index); | 1949 | name = kasprintf(GFP_KERNEL, "dsa%d", ds->index); |
@@ -1913,6 +1970,7 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) | |||
1913 | int mv88e6xxx_setup_global(struct dsa_switch *ds) | 1970 | int mv88e6xxx_setup_global(struct dsa_switch *ds) |
1914 | { | 1971 | { |
1915 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | 1972 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); |
1973 | int ret; | ||
1916 | int i; | 1974 | int i; |
1917 | 1975 | ||
1918 | /* Set the default address aging time to 5 minutes, and | 1976 | /* Set the default address aging time to 5 minutes, and |
@@ -1976,7 +2034,8 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds) | |||
1976 | (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT)); | 2034 | (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT)); |
1977 | 2035 | ||
1978 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 2036 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1979 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { | 2037 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
2038 | mv88e6xxx_6320_family(ds)) { | ||
1980 | /* Send all frames with destination addresses matching | 2039 | /* Send all frames with destination addresses matching |
1981 | * 01:80:c2:00:00:2x to the CPU port. | 2040 | * 01:80:c2:00:00:2x to the CPU port. |
1982 | */ | 2041 | */ |
@@ -1995,7 +2054,8 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds) | |||
1995 | 2054 | ||
1996 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || | 2055 | if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || |
1997 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || | 2056 | mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || |
1998 | mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) { | 2057 | mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || |
2058 | mv88e6xxx_6320_family(ds)) { | ||
1999 | /* Disable ingress rate limiting by resetting all | 2059 | /* Disable ingress rate limiting by resetting all |
2000 | * ingress rate limit registers to their initial | 2060 | * ingress rate limit registers to their initial |
2001 | * state. | 2061 | * state. |
@@ -2009,9 +2069,11 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds) | |||
2009 | REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, GLOBAL_STATS_OP_FLUSH_ALL); | 2069 | REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, GLOBAL_STATS_OP_FLUSH_ALL); |
2010 | 2070 | ||
2011 | /* Wait for the flush to complete. */ | 2071 | /* Wait for the flush to complete. */ |
2012 | _mv88e6xxx_stats_wait(ds); | 2072 | mutex_lock(&ps->smi_mutex); |
2073 | ret = _mv88e6xxx_stats_wait(ds); | ||
2074 | mutex_unlock(&ps->smi_mutex); | ||
2013 | 2075 | ||
2014 | return 0; | 2076 | return ret; |
2015 | } | 2077 | } |
2016 | 2078 | ||
2017 | int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active) | 2079 | int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active) |
@@ -2162,6 +2224,132 @@ mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum, | |||
2162 | return ret; | 2224 | return ret; |
2163 | } | 2225 | } |
2164 | 2226 | ||
2227 | #ifdef CONFIG_NET_DSA_HWMON | ||
2228 | |||
2229 | static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp) | ||
2230 | { | ||
2231 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
2232 | int ret; | ||
2233 | int val; | ||
2234 | |||
2235 | *temp = 0; | ||
2236 | |||
2237 | mutex_lock(&ps->smi_mutex); | ||
2238 | |||
2239 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); | ||
2240 | if (ret < 0) | ||
2241 | goto error; | ||
2242 | |||
2243 | /* Enable temperature sensor */ | ||
2244 | ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); | ||
2245 | if (ret < 0) | ||
2246 | goto error; | ||
2247 | |||
2248 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); | ||
2249 | if (ret < 0) | ||
2250 | goto error; | ||
2251 | |||
2252 | /* Wait for temperature to stabilize */ | ||
2253 | usleep_range(10000, 12000); | ||
2254 | |||
2255 | val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); | ||
2256 | if (val < 0) { | ||
2257 | ret = val; | ||
2258 | goto error; | ||
2259 | } | ||
2260 | |||
2261 | /* Disable temperature sensor */ | ||
2262 | ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); | ||
2263 | if (ret < 0) | ||
2264 | goto error; | ||
2265 | |||
2266 | *temp = ((val & 0x1f) - 5) * 5; | ||
2267 | |||
2268 | error: | ||
2269 | _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); | ||
2270 | mutex_unlock(&ps->smi_mutex); | ||
2271 | return ret; | ||
2272 | } | ||
2273 | |||
2274 | static int mv88e63xx_get_temp(struct dsa_switch *ds, int *temp) | ||
2275 | { | ||
2276 | int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; | ||
2277 | int ret; | ||
2278 | |||
2279 | *temp = 0; | ||
2280 | |||
2281 | ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27); | ||
2282 | if (ret < 0) | ||
2283 | return ret; | ||
2284 | |||
2285 | *temp = (ret & 0xff) - 25; | ||
2286 | |||
2287 | return 0; | ||
2288 | } | ||
2289 | |||
2290 | int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) | ||
2291 | { | ||
2292 | if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds)) | ||
2293 | return mv88e63xx_get_temp(ds, temp); | ||
2294 | |||
2295 | return mv88e61xx_get_temp(ds, temp); | ||
2296 | } | ||
2297 | |||
2298 | int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp) | ||
2299 | { | ||
2300 | int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; | ||
2301 | int ret; | ||
2302 | |||
2303 | if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds)) | ||
2304 | return -EOPNOTSUPP; | ||
2305 | |||
2306 | *temp = 0; | ||
2307 | |||
2308 | ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); | ||
2309 | if (ret < 0) | ||
2310 | return ret; | ||
2311 | |||
2312 | *temp = (((ret >> 8) & 0x1f) * 5) - 25; | ||
2313 | |||
2314 | return 0; | ||
2315 | } | ||
2316 | |||
2317 | int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp) | ||
2318 | { | ||
2319 | int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; | ||
2320 | int ret; | ||
2321 | |||
2322 | if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds)) | ||
2323 | return -EOPNOTSUPP; | ||
2324 | |||
2325 | ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); | ||
2326 | if (ret < 0) | ||
2327 | return ret; | ||
2328 | temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); | ||
2329 | return mv88e6xxx_phy_page_write(ds, phy, 6, 26, | ||
2330 | (ret & 0xe0ff) | (temp << 8)); | ||
2331 | } | ||
2332 | |||
2333 | int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm) | ||
2334 | { | ||
2335 | int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; | ||
2336 | int ret; | ||
2337 | |||
2338 | if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds)) | ||
2339 | return -EOPNOTSUPP; | ||
2340 | |||
2341 | *alarm = false; | ||
2342 | |||
2343 | ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); | ||
2344 | if (ret < 0) | ||
2345 | return ret; | ||
2346 | |||
2347 | *alarm = !!(ret & 0x40); | ||
2348 | |||
2349 | return 0; | ||
2350 | } | ||
2351 | #endif /* CONFIG_NET_DSA_HWMON */ | ||
2352 | |||
2165 | static int __init mv88e6xxx_init(void) | 2353 | static int __init mv88e6xxx_init(void) |
2166 | { | 2354 | { |
2167 | #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) | 2355 | #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) |