Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: vsc73xx: implement FDB operations

This commit introduces implementations of three functions:
.port_fdb_dump
.port_fdb_add
.port_fdb_del

The FDB database organization is the same as in other old Vitesse chips:
It has 2048 rows and 4 columns (buckets). The row index is calculated by
the hash function 'vsc73xx_calc_hash' and the FDB entry must be placed
exactly into row[hash]. The chip selects the bucket number by itself.

Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
Link: https://patch.msgid.link/20240827123938.582789-1-paweldembicki@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Pawel Dembicki and committed by
Paolo Abeni
075e3d30 da4f3b72

+357
+355
drivers/net/dsa/vitesse-vsc73xx-core.c
··· 46 46 #define VSC73XX_BLOCK_MII_EXTERNAL 0x1 /* External MDIO subblock */ 47 47 48 48 #define CPU_PORT 6 /* CPU port */ 49 + #define VSC73XX_NUM_FDB_ROWS 2048 50 + #define VSC73XX_NUM_BUCKETS 4 49 51 50 52 /* MAC Block registers */ 51 53 #define VSC73XX_MAC_CFG 0x00 ··· 199 197 #define VSC73XX_SRCMASKS_MIRROR BIT(26) 200 198 #define VSC73XX_SRCMASKS_PORTS_MASK GENMASK(7, 0) 201 199 200 + #define VSC73XX_MACHDATA_VID GENMASK(27, 16) 201 + #define VSC73XX_MACHDATA_MAC0 GENMASK(15, 8) 202 + #define VSC73XX_MACHDATA_MAC1 GENMASK(7, 0) 203 + #define VSC73XX_MACLDATA_MAC2 GENMASK(31, 24) 204 + #define VSC73XX_MACLDATA_MAC3 GENMASK(23, 16) 205 + #define VSC73XX_MACLDATA_MAC4 GENMASK(15, 8) 206 + #define VSC73XX_MACLDATA_MAC5 GENMASK(7, 0) 207 + 208 + #define VSC73XX_HASH0_VID_FROM_MASK GENMASK(5, 0) 209 + #define VSC73XX_HASH0_MAC0_FROM_MASK GENMASK(7, 4) 210 + #define VSC73XX_HASH1_MAC0_FROM_MASK GENMASK(3, 0) 211 + #define VSC73XX_HASH1_MAC1_FROM_MASK GENMASK(7, 1) 212 + #define VSC73XX_HASH2_MAC1_FROM_MASK BIT(0) 213 + #define VSC73XX_HASH2_MAC2_FROM_MASK GENMASK(7, 0) 214 + #define VSC73XX_HASH2_MAC3_FROM_MASK GENMASK(7, 6) 215 + #define VSC73XX_HASH3_MAC3_FROM_MASK GENMASK(5, 0) 216 + #define VSC73XX_HASH3_MAC4_FROM_MASK GENMASK(7, 3) 217 + #define VSC73XX_HASH4_MAC4_FROM_MASK GENMASK(2, 0) 218 + 219 + #define VSC73XX_HASH0_VID_TO_MASK GENMASK(9, 4) 220 + #define VSC73XX_HASH0_MAC0_TO_MASK GENMASK(3, 0) 221 + #define VSC73XX_HASH1_MAC0_TO_MASK GENMASK(10, 7) 222 + #define VSC73XX_HASH1_MAC1_TO_MASK GENMASK(6, 0) 223 + #define VSC73XX_HASH2_MAC1_TO_MASK BIT(10) 224 + #define VSC73XX_HASH2_MAC2_TO_MASK GENMASK(9, 2) 225 + #define VSC73XX_HASH2_MAC3_TO_MASK GENMASK(1, 0) 226 + #define VSC73XX_HASH3_MAC3_TO_MASK GENMASK(10, 5) 227 + #define VSC73XX_HASH3_MAC4_TO_MASK GENMASK(4, 0) 228 + #define VSC73XX_HASH4_MAC4_TO_MASK GENMASK(10, 8) 229 + 230 + #define VSC73XX_MACTINDX_SHADOW BIT(13) 231 + #define VSC73XX_MACTINDX_BUCKET_MSK GENMASK(12, 11) 232 + #define VSC73XX_MACTINDX_INDEX_MSK GENMASK(10, 0) 233 + 202 234 #define VSC73XX_MACACCESS_CPU_COPY BIT(14) 203 235 #define VSC73XX_MACACCESS_FWD_KILL BIT(13) 204 236 #define VSC73XX_MACACCESS_IGNORE_VLAN BIT(12) ··· 366 330 struct vsc73xx_counter { 367 331 u8 counter; 368 332 const char *name; 333 + }; 334 + 335 + struct vsc73xx_fdb { 336 + u16 vid; 337 + u8 port; 338 + u8 mac[ETH_ALEN]; 339 + bool valid; 369 340 }; 370 341 371 342 /* Counters are named according to the MIB standards where applicable. ··· 847 804 848 805 ds->untag_bridge_pvid = true; 849 806 ds->max_num_bridges = DSA_TAG_8021Q_MAX_NUM_BRIDGES; 807 + ds->fdb_isolation = true; 850 808 851 809 /* Issue RESET */ 852 810 vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GLORESET, ··· 1898 1854 vsc73xx_refresh_fwd_map(ds, port, state); 1899 1855 } 1900 1856 1857 + static u16 vsc73xx_calc_hash(const unsigned char *addr, u16 vid) 1858 + { 1859 + /* VID 5-0, MAC 47-44 */ 1860 + u16 hash = FIELD_PREP(VSC73XX_HASH0_VID_TO_MASK, 1861 + FIELD_GET(VSC73XX_HASH0_VID_FROM_MASK, vid)) | 1862 + FIELD_PREP(VSC73XX_HASH0_MAC0_TO_MASK, 1863 + FIELD_GET(VSC73XX_HASH0_MAC0_FROM_MASK, addr[0])); 1864 + /* MAC 43-33 */ 1865 + hash ^= FIELD_PREP(VSC73XX_HASH1_MAC0_TO_MASK, 1866 + FIELD_GET(VSC73XX_HASH1_MAC0_FROM_MASK, addr[0])) | 1867 + FIELD_PREP(VSC73XX_HASH1_MAC1_TO_MASK, 1868 + FIELD_GET(VSC73XX_HASH1_MAC1_FROM_MASK, addr[1])); 1869 + /* MAC 32-22 */ 1870 + hash ^= FIELD_PREP(VSC73XX_HASH2_MAC1_TO_MASK, 1871 + FIELD_GET(VSC73XX_HASH2_MAC1_FROM_MASK, addr[1])) | 1872 + FIELD_PREP(VSC73XX_HASH2_MAC2_TO_MASK, 1873 + FIELD_GET(VSC73XX_HASH2_MAC2_FROM_MASK, addr[2])) | 1874 + FIELD_PREP(VSC73XX_HASH2_MAC3_TO_MASK, 1875 + FIELD_GET(VSC73XX_HASH2_MAC3_FROM_MASK, addr[3])); 1876 + /* MAC 21-11 */ 1877 + hash ^= FIELD_PREP(VSC73XX_HASH3_MAC3_TO_MASK, 1878 + FIELD_GET(VSC73XX_HASH3_MAC3_FROM_MASK, addr[3])) | 1879 + FIELD_PREP(VSC73XX_HASH3_MAC4_TO_MASK, 1880 + FIELD_GET(VSC73XX_HASH3_MAC4_FROM_MASK, addr[4])); 1881 + /* MAC 10-0 */ 1882 + hash ^= FIELD_PREP(VSC73XX_HASH4_MAC4_TO_MASK, 1883 + FIELD_GET(VSC73XX_HASH4_MAC4_FROM_MASK, addr[4])) | 1884 + addr[5]; 1885 + 1886 + return hash; 1887 + } 1888 + 1889 + static int 1890 + vsc73xx_port_wait_for_mac_table_cmd(struct vsc73xx *vsc) 1891 + { 1892 + int ret, err; 1893 + u32 val; 1894 + 1895 + ret = read_poll_timeout(vsc73xx_read, err, 1896 + err < 0 || 1897 + ((val & VSC73XX_MACACCESS_CMD_MASK) == 1898 + VSC73XX_MACACCESS_CMD_IDLE), 1899 + VSC73XX_POLL_SLEEP_US, VSC73XX_POLL_TIMEOUT_US, 1900 + false, vsc, VSC73XX_BLOCK_ANALYZER, 1901 + 0, VSC73XX_MACACCESS, &val); 1902 + if (ret) 1903 + return ret; 1904 + return err; 1905 + } 1906 + 1907 + static int vsc73xx_port_read_mac_table_row(struct vsc73xx *vsc, u16 index, 1908 + struct vsc73xx_fdb *fdb) 1909 + { 1910 + int ret, i; 1911 + u32 val; 1912 + 1913 + if (!fdb) 1914 + return -EINVAL; 1915 + if (index >= VSC73XX_NUM_FDB_ROWS) 1916 + return -EINVAL; 1917 + 1918 + for (i = 0; i < VSC73XX_NUM_BUCKETS; i++) { 1919 + ret = vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, 1920 + VSC73XX_MACTINDX, 1921 + (i ? 0 : VSC73XX_MACTINDX_SHADOW) | 1922 + FIELD_PREP(VSC73XX_MACTINDX_BUCKET_MSK, i) | 1923 + index); 1924 + if (ret) 1925 + return ret; 1926 + 1927 + ret = vsc73xx_port_wait_for_mac_table_cmd(vsc); 1928 + if (ret) 1929 + return ret; 1930 + 1931 + ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0, 1932 + VSC73XX_MACACCESS, 1933 + VSC73XX_MACACCESS_CMD_MASK, 1934 + VSC73XX_MACACCESS_CMD_READ_ENTRY); 1935 + if (ret) 1936 + return ret; 1937 + 1938 + ret = vsc73xx_port_wait_for_mac_table_cmd(vsc); 1939 + if (ret) 1940 + return ret; 1941 + 1942 + ret = vsc73xx_read(vsc, VSC73XX_BLOCK_ANALYZER, 0, 1943 + VSC73XX_MACACCESS, &val); 1944 + if (ret) 1945 + return ret; 1946 + 1947 + fdb[i].valid = FIELD_GET(VSC73XX_MACACCESS_VALID, val); 1948 + if (!fdb[i].valid) 1949 + continue; 1950 + 1951 + fdb[i].port = FIELD_GET(VSC73XX_MACACCESS_DEST_IDX_MASK, val); 1952 + 1953 + ret = vsc73xx_read(vsc, VSC73XX_BLOCK_ANALYZER, 0, 1954 + VSC73XX_MACHDATA, &val); 1955 + if (ret) 1956 + return ret; 1957 + 1958 + fdb[i].vid = FIELD_GET(VSC73XX_MACHDATA_VID, val); 1959 + fdb[i].mac[0] = FIELD_GET(VSC73XX_MACHDATA_MAC0, val); 1960 + fdb[i].mac[1] = FIELD_GET(VSC73XX_MACHDATA_MAC1, val); 1961 + 1962 + ret = vsc73xx_read(vsc, VSC73XX_BLOCK_ANALYZER, 0, 1963 + VSC73XX_MACLDATA, &val); 1964 + if (ret) 1965 + return ret; 1966 + 1967 + fdb[i].mac[2] = FIELD_GET(VSC73XX_MACLDATA_MAC2, val); 1968 + fdb[i].mac[3] = FIELD_GET(VSC73XX_MACLDATA_MAC3, val); 1969 + fdb[i].mac[4] = FIELD_GET(VSC73XX_MACLDATA_MAC4, val); 1970 + fdb[i].mac[5] = FIELD_GET(VSC73XX_MACLDATA_MAC5, val); 1971 + } 1972 + 1973 + return ret; 1974 + } 1975 + 1976 + static int 1977 + vsc73xx_fdb_operation(struct vsc73xx *vsc, const unsigned char *addr, u16 vid, 1978 + u16 hash, u16 cmd_mask, u16 cmd_val) 1979 + { 1980 + int ret; 1981 + u32 val; 1982 + 1983 + val = FIELD_PREP(VSC73XX_MACHDATA_VID, vid) | 1984 + FIELD_PREP(VSC73XX_MACHDATA_MAC0, addr[0]) | 1985 + FIELD_PREP(VSC73XX_MACHDATA_MAC1, addr[1]); 1986 + ret = vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_MACHDATA, 1987 + val); 1988 + if (ret) 1989 + return ret; 1990 + 1991 + val = FIELD_PREP(VSC73XX_MACLDATA_MAC2, addr[2]) | 1992 + FIELD_PREP(VSC73XX_MACLDATA_MAC3, addr[3]) | 1993 + FIELD_PREP(VSC73XX_MACLDATA_MAC4, addr[4]) | 1994 + FIELD_PREP(VSC73XX_MACLDATA_MAC5, addr[5]); 1995 + ret = vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_MACLDATA, 1996 + val); 1997 + if (ret) 1998 + return ret; 1999 + 2000 + ret = vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_MACTINDX, 2001 + hash); 2002 + if (ret) 2003 + return ret; 2004 + 2005 + ret = vsc73xx_port_wait_for_mac_table_cmd(vsc); 2006 + if (ret) 2007 + return ret; 2008 + 2009 + ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0, 2010 + VSC73XX_MACACCESS, cmd_mask, cmd_val); 2011 + if (ret) 2012 + return ret; 2013 + 2014 + return vsc73xx_port_wait_for_mac_table_cmd(vsc); 2015 + } 2016 + 2017 + static int vsc73xx_fdb_del_entry(struct vsc73xx *vsc, int port, 2018 + const unsigned char *addr, u16 vid) 2019 + { 2020 + struct vsc73xx_fdb fdb[VSC73XX_NUM_BUCKETS]; 2021 + u16 hash = vsc73xx_calc_hash(addr, vid); 2022 + int bucket, ret; 2023 + 2024 + mutex_lock(&vsc->fdb_lock); 2025 + 2026 + ret = vsc73xx_port_read_mac_table_row(vsc, hash, fdb); 2027 + if (ret) 2028 + goto err; 2029 + 2030 + for (bucket = 0; bucket < VSC73XX_NUM_BUCKETS; bucket++) { 2031 + if (fdb[bucket].valid && fdb[bucket].port == port && 2032 + ether_addr_equal(addr, fdb[bucket].mac)) 2033 + break; 2034 + } 2035 + 2036 + if (bucket == VSC73XX_NUM_BUCKETS) { 2037 + /* Can't find MAC in MAC table */ 2038 + ret = -ENODATA; 2039 + goto err; 2040 + } 2041 + 2042 + ret = vsc73xx_fdb_operation(vsc, addr, vid, hash, 2043 + VSC73XX_MACACCESS_CMD_MASK, 2044 + VSC73XX_MACACCESS_CMD_FORGET); 2045 + err: 2046 + mutex_unlock(&vsc->fdb_lock); 2047 + return ret; 2048 + } 2049 + 2050 + static int vsc73xx_fdb_add_entry(struct vsc73xx *vsc, int port, 2051 + const unsigned char *addr, u16 vid) 2052 + { 2053 + struct vsc73xx_fdb fdb[VSC73XX_NUM_BUCKETS]; 2054 + u16 hash = vsc73xx_calc_hash(addr, vid); 2055 + int bucket, ret; 2056 + u32 val; 2057 + 2058 + mutex_lock(&vsc->fdb_lock); 2059 + 2060 + ret = vsc73xx_port_read_mac_table_row(vsc, hash, fdb); 2061 + if (ret) 2062 + goto err; 2063 + 2064 + for (bucket = 0; bucket < VSC73XX_NUM_BUCKETS; bucket++) { 2065 + if (!fdb[bucket].valid) 2066 + break; 2067 + } 2068 + 2069 + if (bucket == VSC73XX_NUM_BUCKETS) { 2070 + /* Bucket is full */ 2071 + ret = -EOVERFLOW; 2072 + goto err; 2073 + } 2074 + 2075 + val = VSC73XX_MACACCESS_VALID | VSC73XX_MACACCESS_LOCKED | 2076 + FIELD_PREP(VSC73XX_MACACCESS_DEST_IDX_MASK, port) | 2077 + VSC73XX_MACACCESS_CMD_LEARN; 2078 + ret = vsc73xx_fdb_operation(vsc, addr, vid, hash, 2079 + VSC73XX_MACACCESS_VALID | 2080 + VSC73XX_MACACCESS_LOCKED | 2081 + VSC73XX_MACACCESS_DEST_IDX_MASK | 2082 + VSC73XX_MACACCESS_CMD_MASK, val); 2083 + err: 2084 + mutex_unlock(&vsc->fdb_lock); 2085 + return ret; 2086 + } 2087 + 2088 + static int vsc73xx_fdb_add(struct dsa_switch *ds, int port, 2089 + const unsigned char *addr, u16 vid, struct dsa_db db) 2090 + { 2091 + struct vsc73xx *vsc = ds->priv; 2092 + 2093 + if (!vid) { 2094 + switch (db.type) { 2095 + case DSA_DB_PORT: 2096 + vid = dsa_tag_8021q_standalone_vid(db.dp); 2097 + break; 2098 + case DSA_DB_BRIDGE: 2099 + vid = dsa_tag_8021q_bridge_vid(db.bridge.num); 2100 + break; 2101 + default: 2102 + return -EOPNOTSUPP; 2103 + } 2104 + } 2105 + 2106 + return vsc73xx_fdb_add_entry(vsc, port, addr, vid); 2107 + } 2108 + 2109 + static int vsc73xx_fdb_del(struct dsa_switch *ds, int port, 2110 + const unsigned char *addr, u16 vid, struct dsa_db db) 2111 + { 2112 + struct vsc73xx *vsc = ds->priv; 2113 + 2114 + if (!vid) { 2115 + switch (db.type) { 2116 + case DSA_DB_PORT: 2117 + vid = dsa_tag_8021q_standalone_vid(db.dp); 2118 + break; 2119 + case DSA_DB_BRIDGE: 2120 + vid = dsa_tag_8021q_bridge_vid(db.bridge.num); 2121 + break; 2122 + default: 2123 + return -EOPNOTSUPP; 2124 + } 2125 + } 2126 + 2127 + return vsc73xx_fdb_del_entry(vsc, port, addr, vid); 2128 + } 2129 + 2130 + static int vsc73xx_port_fdb_dump(struct dsa_switch *ds, 2131 + int port, dsa_fdb_dump_cb_t *cb, void *data) 2132 + { 2133 + struct vsc73xx_fdb fdb[VSC73XX_NUM_BUCKETS]; 2134 + struct vsc73xx *vsc = ds->priv; 2135 + u16 i, bucket; 2136 + int err = 0; 2137 + 2138 + mutex_lock(&vsc->fdb_lock); 2139 + 2140 + for (i = 0; i < VSC73XX_NUM_FDB_ROWS; i++) { 2141 + err = vsc73xx_port_read_mac_table_row(vsc, i, fdb); 2142 + if (err) 2143 + goto unlock; 2144 + 2145 + for (bucket = 0; bucket < VSC73XX_NUM_BUCKETS; bucket++) { 2146 + if (!fdb[bucket].valid || fdb[bucket].port != port) 2147 + continue; 2148 + 2149 + /* We need to hide dsa_8021q VLANs from the user */ 2150 + if (vid_is_dsa_8021q(fdb[bucket].vid)) 2151 + fdb[bucket].vid = 0; 2152 + 2153 + err = cb(fdb[bucket].mac, fdb[bucket].vid, false, data); 2154 + if (err) 2155 + goto unlock; 2156 + } 2157 + } 2158 + unlock: 2159 + mutex_unlock(&vsc->fdb_lock); 2160 + return err; 2161 + } 2162 + 1901 2163 static const struct phylink_mac_ops vsc73xx_phylink_mac_ops = { 1902 2164 .mac_config = vsc73xx_mac_config, 1903 2165 .mac_link_down = vsc73xx_mac_link_down, ··· 2226 1876 .port_bridge_join = dsa_tag_8021q_bridge_join, 2227 1877 .port_bridge_leave = dsa_tag_8021q_bridge_leave, 2228 1878 .port_change_mtu = vsc73xx_change_mtu, 1879 + .port_fdb_add = vsc73xx_fdb_add, 1880 + .port_fdb_del = vsc73xx_fdb_del, 1881 + .port_fdb_dump = vsc73xx_port_fdb_dump, 2229 1882 .port_max_mtu = vsc73xx_get_max_mtu, 2230 1883 .port_stp_state_set = vsc73xx_port_stp_state_set, 2231 1884 .port_vlan_filtering = vsc73xx_port_vlan_filtering, ··· 2358 2005 dev_err(dev, "no chip found (%d)\n", ret); 2359 2006 return -ENODEV; 2360 2007 } 2008 + 2009 + mutex_init(&vsc->fdb_lock); 2361 2010 2362 2011 eth_random_addr(vsc->addr); 2363 2012 dev_info(vsc->dev,
+2
drivers/net/dsa/vitesse-vsc73xx.h
··· 45 45 * @vlans: List of configured vlans. Contains port mask and untagged status of 46 46 * every vlan configured in port vlan operation. It doesn't cover tag_8021q 47 47 * vlans. 48 + * @fdb_lock: Mutex protects fdb access 48 49 */ 49 50 struct vsc73xx { 50 51 struct device *dev; ··· 58 57 void *priv; 59 58 struct vsc73xx_portinfo portinfo[VSC73XX_MAX_NUM_PORTS]; 60 59 struct list_head vlans; 60 + struct mutex fdb_lock; 61 61 }; 62 62 63 63 /**