@@ -780,6 +780,8 @@ static const struct ethtool_ops ocelot_ethtool_ops = {
780780 .get_strings = ocelot_get_strings ,
781781 .get_ethtool_stats = ocelot_get_ethtool_stats ,
782782 .get_sset_count = ocelot_get_sset_count ,
783+ .get_link_ksettings = phy_ethtool_get_link_ksettings ,
784+ .set_link_ksettings = phy_ethtool_set_link_ksettings ,
783785};
784786
785787static int ocelot_port_attr_get (struct net_device * dev ,
@@ -1088,6 +1090,137 @@ static void ocelot_port_bridge_leave(struct ocelot_port *ocelot_port,
10881090 ocelot -> hw_bridge_dev = NULL ;
10891091}
10901092
1093+ static void ocelot_set_aggr_pgids (struct ocelot * ocelot )
1094+ {
1095+ int i , port , lag ;
1096+
1097+ /* Reset destination and aggregation PGIDS */
1098+ for (port = 0 ; port < ocelot -> num_phys_ports ; port ++ )
1099+ ocelot_write_rix (ocelot , BIT (port ), ANA_PGID_PGID , port );
1100+
1101+ for (i = PGID_AGGR ; i < PGID_SRC ; i ++ )
1102+ ocelot_write_rix (ocelot , GENMASK (ocelot -> num_phys_ports - 1 , 0 ),
1103+ ANA_PGID_PGID , i );
1104+
1105+ /* Now, set PGIDs for each LAG */
1106+ for (lag = 0 ; lag < ocelot -> num_phys_ports ; lag ++ ) {
1107+ unsigned long bond_mask ;
1108+ int aggr_count = 0 ;
1109+ u8 aggr_idx [16 ];
1110+
1111+ bond_mask = ocelot -> lags [lag ];
1112+ if (!bond_mask )
1113+ continue ;
1114+
1115+ for_each_set_bit (port , & bond_mask , ocelot -> num_phys_ports ) {
1116+ // Destination mask
1117+ ocelot_write_rix (ocelot , bond_mask ,
1118+ ANA_PGID_PGID , port );
1119+ aggr_idx [aggr_count ] = port ;
1120+ aggr_count ++ ;
1121+ }
1122+
1123+ for (i = PGID_AGGR ; i < PGID_SRC ; i ++ ) {
1124+ u32 ac ;
1125+
1126+ ac = ocelot_read_rix (ocelot , ANA_PGID_PGID , i );
1127+ ac &= ~bond_mask ;
1128+ ac |= BIT (aggr_idx [i % aggr_count ]);
1129+ ocelot_write_rix (ocelot , ac , ANA_PGID_PGID , i );
1130+ }
1131+ }
1132+ }
1133+
1134+ static void ocelot_setup_lag (struct ocelot * ocelot , int lag )
1135+ {
1136+ unsigned long bond_mask = ocelot -> lags [lag ];
1137+ unsigned int p ;
1138+
1139+ for_each_set_bit (p , & bond_mask , ocelot -> num_phys_ports ) {
1140+ u32 port_cfg = ocelot_read_gix (ocelot , ANA_PORT_PORT_CFG , p );
1141+
1142+ port_cfg &= ~ANA_PORT_PORT_CFG_PORTID_VAL_M ;
1143+
1144+ /* Use lag port as logical port for port i */
1145+ ocelot_write_gix (ocelot , port_cfg |
1146+ ANA_PORT_PORT_CFG_PORTID_VAL (lag ),
1147+ ANA_PORT_PORT_CFG , p );
1148+ }
1149+ }
1150+
1151+ static int ocelot_port_lag_join (struct ocelot_port * ocelot_port ,
1152+ struct net_device * bond )
1153+ {
1154+ struct ocelot * ocelot = ocelot_port -> ocelot ;
1155+ int p = ocelot_port -> chip_port ;
1156+ int lag , lp ;
1157+ struct net_device * ndev ;
1158+ u32 bond_mask = 0 ;
1159+
1160+ rcu_read_lock ();
1161+ for_each_netdev_in_bond_rcu (bond , ndev ) {
1162+ struct ocelot_port * port = netdev_priv (ndev );
1163+
1164+ bond_mask |= BIT (port -> chip_port );
1165+ }
1166+ rcu_read_unlock ();
1167+
1168+ lp = __ffs (bond_mask );
1169+
1170+ /* If the new port is the lowest one, use it as the logical port from
1171+ * now on
1172+ */
1173+ if (p == lp ) {
1174+ lag = p ;
1175+ ocelot -> lags [p ] = bond_mask ;
1176+ bond_mask &= ~BIT (p );
1177+ if (bond_mask ) {
1178+ lp = __ffs (bond_mask );
1179+ ocelot -> lags [lp ] = 0 ;
1180+ }
1181+ } else {
1182+ lag = lp ;
1183+ ocelot -> lags [lp ] |= BIT (p );
1184+ }
1185+
1186+ ocelot_setup_lag (ocelot , lag );
1187+ ocelot_set_aggr_pgids (ocelot );
1188+
1189+ return 0 ;
1190+ }
1191+
1192+ static void ocelot_port_lag_leave (struct ocelot_port * ocelot_port ,
1193+ struct net_device * bond )
1194+ {
1195+ struct ocelot * ocelot = ocelot_port -> ocelot ;
1196+ int p = ocelot_port -> chip_port ;
1197+ u32 port_cfg ;
1198+ int i ;
1199+
1200+ /* Remove port from any lag */
1201+ for (i = 0 ; i < ocelot -> num_phys_ports ; i ++ )
1202+ ocelot -> lags [i ] &= ~BIT (ocelot_port -> chip_port );
1203+
1204+ /* if it was the logical port of the lag, move the lag config to the
1205+ * next port
1206+ */
1207+ if (ocelot -> lags [p ]) {
1208+ int n = __ffs (ocelot -> lags [p ]);
1209+
1210+ ocelot -> lags [n ] = ocelot -> lags [p ];
1211+ ocelot -> lags [p ] = 0 ;
1212+
1213+ ocelot_setup_lag (ocelot , n );
1214+ }
1215+
1216+ port_cfg = ocelot_read_gix (ocelot , ANA_PORT_PORT_CFG , p );
1217+ port_cfg &= ~ANA_PORT_PORT_CFG_PORTID_VAL_M ;
1218+ ocelot_write_gix (ocelot , port_cfg | ANA_PORT_PORT_CFG_PORTID_VAL (p ),
1219+ ANA_PORT_PORT_CFG , p );
1220+
1221+ ocelot_set_aggr_pgids (ocelot );
1222+ }
1223+
10911224/* Checks if the net_device instance given to us originate from our driver. */
10921225static bool ocelot_netdevice_dev_check (const struct net_device * dev )
10931226{
@@ -1114,6 +1247,14 @@ static int ocelot_netdevice_port_event(struct net_device *dev,
11141247 ocelot_port_bridge_leave (ocelot_port ,
11151248 info -> upper_dev );
11161249 }
1250+ if (netif_is_lag_master (info -> upper_dev )) {
1251+ if (info -> linking )
1252+ err = ocelot_port_lag_join (ocelot_port ,
1253+ info -> upper_dev );
1254+ else
1255+ ocelot_port_lag_leave (ocelot_port ,
1256+ info -> upper_dev );
1257+ }
11171258 break ;
11181259 default :
11191260 break ;
@@ -1129,6 +1270,20 @@ static int ocelot_netdevice_event(struct notifier_block *unused,
11291270 struct net_device * dev = netdev_notifier_info_to_dev (ptr );
11301271 int ret = 0 ;
11311272
1273+ if (event == NETDEV_PRECHANGEUPPER &&
1274+ netif_is_lag_master (info -> upper_dev )) {
1275+ struct netdev_lag_upper_info * lag_upper_info = info -> upper_info ;
1276+ struct netlink_ext_ack * extack ;
1277+
1278+ if (lag_upper_info -> tx_type != NETDEV_LAG_TX_TYPE_HASH ) {
1279+ extack = netdev_notifier_info_to_extack (& info -> info );
1280+ NL_SET_ERR_MSG_MOD (extack , "LAG device using unsupported Tx type" );
1281+
1282+ ret = - EINVAL ;
1283+ goto notify ;
1284+ }
1285+ }
1286+
11321287 if (netif_is_lag_master (dev )) {
11331288 struct net_device * slave ;
11341289 struct list_head * iter ;
@@ -1201,6 +1356,11 @@ int ocelot_init(struct ocelot *ocelot)
12011356 int i , cpu = ocelot -> num_phys_ports ;
12021357 char queue_name [32 ];
12031358
1359+ ocelot -> lags = devm_kcalloc (ocelot -> dev , ocelot -> num_phys_ports ,
1360+ sizeof (u32 ), GFP_KERNEL );
1361+ if (!ocelot -> lags )
1362+ return - ENOMEM ;
1363+
12041364 ocelot -> stats = devm_kcalloc (ocelot -> dev ,
12051365 ocelot -> num_phys_ports * ocelot -> num_stats ,
12061366 sizeof (u64 ), GFP_KERNEL );
0 commit comments