diff options
author | Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 2016-02-26 13:16:04 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-01 16:24:52 -0500 |
commit | 2db9ce1fd9a34ea560ff120bf763007ddf99c7bb (patch) | |
tree | dc8dfb653918ec6399550b99855b9aa2d07f5c95 | |
parent | 3285f9e8695b26b1e15a58f21aff21087a7e7555 (diff) |
net: dsa: mv88e6xxx: assign default FDB to ports
Restore per-port FDB. Assign them on setup, allow adding and deleting
addresses into them, and dump them.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.c | 96 | ||||
-rw-r--r-- | drivers/net/dsa/mv88e6xxx.h | 2 |
2 files changed, 91 insertions, 7 deletions
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index b4b2f05134ba..0f064889ea08 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c | |||
@@ -1458,14 +1458,82 @@ loadpurge: | |||
1458 | return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_STU_LOAD_PURGE); | 1458 | return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_STU_LOAD_PURGE); |
1459 | } | 1459 | } |
1460 | 1460 | ||
1461 | static int _mv88e6xxx_port_fid(struct dsa_switch *ds, int port, u16 *new, | ||
1462 | u16 *old) | ||
1463 | { | ||
1464 | u16 fid; | ||
1465 | int ret; | ||
1466 | |||
1467 | /* Port's default FID bits 3:0 are located in reg 0x06, offset 12 */ | ||
1468 | ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_BASE_VLAN); | ||
1469 | if (ret < 0) | ||
1470 | return ret; | ||
1471 | |||
1472 | fid = (ret & PORT_BASE_VLAN_FID_3_0_MASK) >> 12; | ||
1473 | |||
1474 | if (new) { | ||
1475 | ret &= ~PORT_BASE_VLAN_FID_3_0_MASK; | ||
1476 | ret |= (*new << 12) & PORT_BASE_VLAN_FID_3_0_MASK; | ||
1477 | |||
1478 | ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, | ||
1479 | ret); | ||
1480 | if (ret < 0) | ||
1481 | return ret; | ||
1482 | } | ||
1483 | |||
1484 | /* Port's default FID bits 11:4 are located in reg 0x05, offset 0 */ | ||
1485 | ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL_1); | ||
1486 | if (ret < 0) | ||
1487 | return ret; | ||
1488 | |||
1489 | fid |= (ret & PORT_CONTROL_1_FID_11_4_MASK) << 4; | ||
1490 | |||
1491 | if (new) { | ||
1492 | ret &= ~PORT_CONTROL_1_FID_11_4_MASK; | ||
1493 | ret |= (*new >> 4) & PORT_CONTROL_1_FID_11_4_MASK; | ||
1494 | |||
1495 | ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_1, | ||
1496 | ret); | ||
1497 | if (ret < 0) | ||
1498 | return ret; | ||
1499 | |||
1500 | netdev_dbg(ds->ports[port], "FID %d (was %d)\n", *new, fid); | ||
1501 | } | ||
1502 | |||
1503 | if (old) | ||
1504 | *old = fid; | ||
1505 | |||
1506 | return 0; | ||
1507 | } | ||
1508 | |||
1509 | static int _mv88e6xxx_port_fid_get(struct dsa_switch *ds, int port, u16 *fid) | ||
1510 | { | ||
1511 | return _mv88e6xxx_port_fid(ds, port, NULL, fid); | ||
1512 | } | ||
1513 | |||
1514 | static int _mv88e6xxx_port_fid_set(struct dsa_switch *ds, int port, u16 fid) | ||
1515 | { | ||
1516 | return _mv88e6xxx_port_fid(ds, port, &fid, NULL); | ||
1517 | } | ||
1518 | |||
1461 | static int _mv88e6xxx_fid_new(struct dsa_switch *ds, u16 *fid) | 1519 | static int _mv88e6xxx_fid_new(struct dsa_switch *ds, u16 *fid) |
1462 | { | 1520 | { |
1521 | struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); | ||
1463 | DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); | 1522 | DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); |
1464 | struct mv88e6xxx_vtu_stu_entry vlan; | 1523 | struct mv88e6xxx_vtu_stu_entry vlan; |
1465 | int err; | 1524 | int i, err; |
1466 | 1525 | ||
1467 | bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); | 1526 | bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); |
1468 | 1527 | ||
1528 | /* Set every FID bit used by the (un)bridged ports */ | ||
1529 | for (i = 0; i < ps->num_ports; ++i) { | ||
1530 | err = _mv88e6xxx_port_fid_get(ds, i, fid); | ||
1531 | if (err) | ||
1532 | return err; | ||
1533 | |||
1534 | set_bit(*fid, fid_bitmap); | ||
1535 | } | ||
1536 | |||
1469 | /* Set every FID bit used by the VLAN entries */ | 1537 | /* Set every FID bit used by the VLAN entries */ |
1470 | err = _mv88e6xxx_vtu_vid_write(ds, GLOBAL_VTU_VID_MASK); | 1538 | err = _mv88e6xxx_vtu_vid_write(ds, GLOBAL_VTU_VID_MASK); |
1471 | if (err) | 1539 | if (err) |
@@ -1824,7 +1892,11 @@ static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port, | |||
1824 | struct mv88e6xxx_vtu_stu_entry vlan; | 1892 | struct mv88e6xxx_vtu_stu_entry vlan; |
1825 | int err; | 1893 | int err; |
1826 | 1894 | ||
1827 | err = _mv88e6xxx_vtu_get(ds, vid, &vlan, false); | 1895 | /* Null VLAN ID corresponds to the port private database */ |
1896 | if (vid == 0) | ||
1897 | err = _mv88e6xxx_port_fid_get(ds, port, &vlan.fid); | ||
1898 | else | ||
1899 | err = _mv88e6xxx_vtu_get(ds, vid, &vlan, false); | ||
1828 | if (err) | 1900 | if (err) |
1829 | return err; | 1901 | return err; |
1830 | 1902 | ||
@@ -1843,10 +1915,6 @@ int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port, | |||
1843 | const struct switchdev_obj_port_fdb *fdb, | 1915 | const struct switchdev_obj_port_fdb *fdb, |
1844 | struct switchdev_trans *trans) | 1916 | struct switchdev_trans *trans) |
1845 | { | 1917 | { |
1846 | /* We don't use per-port FDB */ | ||
1847 | if (fdb->vid == 0) | ||
1848 | return -EOPNOTSUPP; | ||
1849 | |||
1850 | /* We don't need any dynamic resource from the kernel (yet), | 1918 | /* We don't need any dynamic resource from the kernel (yet), |
1851 | * so skip the prepare phase. | 1919 | * so skip the prepare phase. |
1852 | */ | 1920 | */ |
@@ -1982,10 +2050,20 @@ int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, | |||
1982 | struct mv88e6xxx_vtu_stu_entry vlan = { | 2050 | struct mv88e6xxx_vtu_stu_entry vlan = { |
1983 | .vid = GLOBAL_VTU_VID_MASK, /* all ones */ | 2051 | .vid = GLOBAL_VTU_VID_MASK, /* all ones */ |
1984 | }; | 2052 | }; |
2053 | u16 fid; | ||
1985 | int err; | 2054 | int err; |
1986 | 2055 | ||
1987 | mutex_lock(&ps->smi_mutex); | 2056 | mutex_lock(&ps->smi_mutex); |
1988 | 2057 | ||
2058 | /* Dump port's default Filtering Information Database (VLAN ID 0) */ | ||
2059 | err = _mv88e6xxx_port_fid_get(ds, port, &fid); | ||
2060 | if (err) | ||
2061 | goto unlock; | ||
2062 | |||
2063 | err = _mv88e6xxx_port_fdb_dump_one(ds, fid, 0, port, fdb, cb); | ||
2064 | if (err) | ||
2065 | goto unlock; | ||
2066 | |||
1989 | /* Dump VLANs' Filtering Information Databases */ | 2067 | /* Dump VLANs' Filtering Information Databases */ |
1990 | err = _mv88e6xxx_vtu_vid_write(ds, vlan.vid); | 2068 | err = _mv88e6xxx_vtu_vid_write(ds, vlan.vid); |
1991 | if (err) | 2069 | if (err) |
@@ -2286,9 +2364,13 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) | |||
2286 | if (ret) | 2364 | if (ret) |
2287 | goto abort; | 2365 | goto abort; |
2288 | 2366 | ||
2289 | /* Port based VLAN map: do not give each port its own address | 2367 | /* Port based VLAN map: give each port its own address |
2290 | * database, and allow every port to egress frames on all other ports. | 2368 | * database, and allow every port to egress frames on all other ports. |
2291 | */ | 2369 | */ |
2370 | ret = _mv88e6xxx_port_fid_set(ds, port, port + 1); | ||
2371 | if (ret) | ||
2372 | goto abort; | ||
2373 | |||
2292 | reg = BIT(ps->num_ports) - 1; /* all ports */ | 2374 | reg = BIT(ps->num_ports) - 1; /* all ports */ |
2293 | reg &= ~BIT(port); /* except itself */ | 2375 | reg &= ~BIT(port); /* except itself */ |
2294 | ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg); | 2376 | ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg); |
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 9df331e85bf8..85a416620f7c 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h | |||
@@ -133,7 +133,9 @@ | |||
133 | #define PORT_CONTROL_STATE_LEARNING 0x02 | 133 | #define PORT_CONTROL_STATE_LEARNING 0x02 |
134 | #define PORT_CONTROL_STATE_FORWARDING 0x03 | 134 | #define PORT_CONTROL_STATE_FORWARDING 0x03 |
135 | #define PORT_CONTROL_1 0x05 | 135 | #define PORT_CONTROL_1 0x05 |
136 | #define PORT_CONTROL_1_FID_11_4_MASK (0xff << 0) | ||
136 | #define PORT_BASE_VLAN 0x06 | 137 | #define PORT_BASE_VLAN 0x06 |
138 | #define PORT_BASE_VLAN_FID_3_0_MASK (0xf << 12) | ||
137 | #define PORT_DEFAULT_VLAN 0x07 | 139 | #define PORT_DEFAULT_VLAN 0x07 |
138 | #define PORT_DEFAULT_VLAN_MASK 0xfff | 140 | #define PORT_DEFAULT_VLAN_MASK 0xfff |
139 | #define PORT_CONTROL_2 0x08 | 141 | #define PORT_CONTROL_2 0x08 |