@@ -321,6 +321,22 @@ static int mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp,
321321 return 0 ;
322322}
323323
324+ static int mlxsw_sp_port_module_map (struct mlxsw_sp * mlxsw_sp , u8 local_port ,
325+ u8 module , u8 width , u8 lane )
326+ {
327+ char pmlp_pl [MLXSW_REG_PMLP_LEN ];
328+ int i ;
329+
330+ mlxsw_reg_pmlp_pack (pmlp_pl , local_port );
331+ mlxsw_reg_pmlp_width_set (pmlp_pl , width );
332+ for (i = 0 ; i < width ; i ++ ) {
333+ mlxsw_reg_pmlp_module_set (pmlp_pl , i , module );
334+ mlxsw_reg_pmlp_tx_lane_set (pmlp_pl , i , lane + i ); /* Rx & Tx */
335+ }
336+
337+ return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (pmlp ), pmlp_pl );
338+ }
339+
324340static int mlxsw_sp_port_module_unmap (struct mlxsw_sp * mlxsw_sp , u8 local_port )
325341{
326342 char pmlp_pl [MLXSW_REG_PMLP_LEN ];
@@ -1284,6 +1300,18 @@ static u32 mlxsw_sp_to_ptys_speed(u32 speed)
12841300 return ptys_proto ;
12851301}
12861302
1303+ static u32 mlxsw_sp_to_ptys_upper_speed (u32 upper_speed )
1304+ {
1305+ u32 ptys_proto = 0 ;
1306+ int i ;
1307+
1308+ for (i = 0 ; i < MLXSW_SP_PORT_LINK_MODE_LEN ; i ++ ) {
1309+ if (mlxsw_sp_port_link_mode [i ].speed <= upper_speed )
1310+ ptys_proto |= mlxsw_sp_port_link_mode [i ].mask ;
1311+ }
1312+ return ptys_proto ;
1313+ }
1314+
12871315static int mlxsw_sp_port_set_settings (struct net_device * dev ,
12881316 struct ethtool_cmd * cmd )
12891317{
@@ -1360,7 +1388,22 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
13601388 .set_settings = mlxsw_sp_port_set_settings ,
13611389};
13621390
1363- static int mlxsw_sp_port_create (struct mlxsw_sp * mlxsw_sp , u8 local_port )
1391+ static int
1392+ mlxsw_sp_port_speed_by_width_set (struct mlxsw_sp_port * mlxsw_sp_port , u8 width )
1393+ {
1394+ struct mlxsw_sp * mlxsw_sp = mlxsw_sp_port -> mlxsw_sp ;
1395+ u32 upper_speed = MLXSW_SP_PORT_BASE_SPEED * width ;
1396+ char ptys_pl [MLXSW_REG_PTYS_LEN ];
1397+ u32 eth_proto_admin ;
1398+
1399+ eth_proto_admin = mlxsw_sp_to_ptys_upper_speed (upper_speed );
1400+ mlxsw_reg_ptys_pack (ptys_pl , mlxsw_sp_port -> local_port ,
1401+ eth_proto_admin );
1402+ return mlxsw_reg_write (mlxsw_sp -> core , MLXSW_REG (ptys ), ptys_pl );
1403+ }
1404+
1405+ static int __mlxsw_sp_port_create (struct mlxsw_sp * mlxsw_sp , u8 local_port ,
1406+ bool split , u8 module , u8 width )
13641407{
13651408 struct devlink * devlink = priv_to_devlink (mlxsw_sp -> core );
13661409 struct mlxsw_sp_port * mlxsw_sp_port ;
@@ -1376,6 +1419,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
13761419 mlxsw_sp_port -> dev = dev ;
13771420 mlxsw_sp_port -> mlxsw_sp = mlxsw_sp ;
13781421 mlxsw_sp_port -> local_port = local_port ;
1422+ mlxsw_sp_port -> split = split ;
13791423 bytes = DIV_ROUND_UP (VLAN_N_VID , BITS_PER_BYTE );
13801424 mlxsw_sp_port -> active_vlans = kzalloc (bytes , GFP_KERNEL );
13811425 if (!mlxsw_sp_port -> active_vlans ) {
@@ -1417,6 +1461,8 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
14171461 dev -> hard_header_len += MLXSW_TXHDR_LEN ;
14181462
14191463 devlink_port = & mlxsw_sp_port -> devlink_port ;
1464+ if (mlxsw_sp_port -> split )
1465+ devlink_port_split_set (devlink_port , module );
14201466 err = devlink_port_register (devlink , devlink_port , local_port );
14211467 if (err ) {
14221468 dev_err (mlxsw_sp -> bus_info -> dev , "Port %d: Failed to register devlink port\n" ,
@@ -1438,6 +1484,13 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
14381484 goto err_port_swid_set ;
14391485 }
14401486
1487+ err = mlxsw_sp_port_speed_by_width_set (mlxsw_sp_port , width );
1488+ if (err ) {
1489+ dev_err (mlxsw_sp -> bus_info -> dev , "Port %d: Failed to enable speeds\n" ,
1490+ mlxsw_sp_port -> local_port );
1491+ goto err_port_speed_by_width_set ;
1492+ }
1493+
14411494 err = mlxsw_sp_port_mtu_set (mlxsw_sp_port , ETH_DATA_LEN );
14421495 if (err ) {
14431496 dev_err (mlxsw_sp -> bus_info -> dev , "Port %d: Failed to set MTU\n" ,
@@ -1479,6 +1532,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
14791532err_port_buffers_init :
14801533err_port_admin_status_set :
14811534err_port_mtu_set :
1535+ err_port_speed_by_width_set :
14821536err_port_swid_set :
14831537err_port_system_port_mapping_set :
14841538 devlink_port_unregister (& mlxsw_sp_port -> devlink_port );
@@ -1494,6 +1548,28 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
14941548 return err ;
14951549}
14961550
1551+ static int mlxsw_sp_port_create (struct mlxsw_sp * mlxsw_sp , u8 local_port ,
1552+ bool split , u8 module , u8 width , u8 lane )
1553+ {
1554+ int err ;
1555+
1556+ err = mlxsw_sp_port_module_map (mlxsw_sp , local_port , module , width ,
1557+ lane );
1558+ if (err )
1559+ return err ;
1560+
1561+ err = __mlxsw_sp_port_create (mlxsw_sp , local_port , split , module ,
1562+ width );
1563+ if (err )
1564+ goto err_port_create ;
1565+
1566+ return 0 ;
1567+
1568+ err_port_create :
1569+ mlxsw_sp_port_module_unmap (mlxsw_sp , local_port );
1570+ return err ;
1571+ }
1572+
14971573static void mlxsw_sp_port_vports_fini (struct mlxsw_sp_port * mlxsw_sp_port )
14981574{
14991575 struct net_device * dev = mlxsw_sp_port -> dev ;
@@ -1562,7 +1638,7 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
15621638 if (!width )
15631639 continue ;
15641640 mlxsw_sp -> port_to_module [i ] = module ;
1565- err = mlxsw_sp_port_create (mlxsw_sp , i );
1641+ err = __mlxsw_sp_port_create (mlxsw_sp , i , false, module , width );
15661642 if (err )
15671643 goto err_port_create ;
15681644 }
@@ -1576,6 +1652,137 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
15761652 return err ;
15771653}
15781654
1655+ static u8 mlxsw_sp_cluster_base_port_get (u8 local_port )
1656+ {
1657+ u8 offset = (local_port - 1 ) % MLXSW_SP_PORTS_PER_CLUSTER_MAX ;
1658+
1659+ return local_port - offset ;
1660+ }
1661+
1662+ static int mlxsw_sp_port_split (void * priv , u8 local_port , unsigned int count )
1663+ {
1664+ struct mlxsw_sp * mlxsw_sp = priv ;
1665+ struct mlxsw_sp_port * mlxsw_sp_port ;
1666+ u8 width = MLXSW_PORT_MODULE_MAX_WIDTH / count ;
1667+ u8 module , cur_width , base_port ;
1668+ int i ;
1669+ int err ;
1670+
1671+ mlxsw_sp_port = mlxsw_sp -> ports [local_port ];
1672+ if (!mlxsw_sp_port ) {
1673+ dev_err (mlxsw_sp -> bus_info -> dev , "Port number \"%d\" does not exist\n" ,
1674+ local_port );
1675+ return - EINVAL ;
1676+ }
1677+
1678+ if (count != 2 && count != 4 ) {
1679+ netdev_err (mlxsw_sp_port -> dev , "Port can only be split into 2 or 4 ports\n" );
1680+ return - EINVAL ;
1681+ }
1682+
1683+ err = mlxsw_sp_port_module_info_get (mlxsw_sp , local_port , & module ,
1684+ & cur_width );
1685+ if (err ) {
1686+ netdev_err (mlxsw_sp_port -> dev , "Failed to get port's width\n" );
1687+ return err ;
1688+ }
1689+
1690+ if (cur_width != MLXSW_PORT_MODULE_MAX_WIDTH ) {
1691+ netdev_err (mlxsw_sp_port -> dev , "Port cannot be split further\n" );
1692+ return - EINVAL ;
1693+ }
1694+
1695+ /* Make sure we have enough slave (even) ports for the split. */
1696+ if (count == 2 ) {
1697+ base_port = local_port ;
1698+ if (mlxsw_sp -> ports [base_port + 1 ]) {
1699+ netdev_err (mlxsw_sp_port -> dev , "Invalid split configuration\n" );
1700+ return - EINVAL ;
1701+ }
1702+ } else {
1703+ base_port = mlxsw_sp_cluster_base_port_get (local_port );
1704+ if (mlxsw_sp -> ports [base_port + 1 ] ||
1705+ mlxsw_sp -> ports [base_port + 3 ]) {
1706+ netdev_err (mlxsw_sp_port -> dev , "Invalid split configuration\n" );
1707+ return - EINVAL ;
1708+ }
1709+ }
1710+
1711+ for (i = 0 ; i < count ; i ++ )
1712+ mlxsw_sp_port_remove (mlxsw_sp , base_port + i );
1713+
1714+ for (i = 0 ; i < count ; i ++ ) {
1715+ err = mlxsw_sp_port_create (mlxsw_sp , base_port + i , true,
1716+ module , width , i * width );
1717+ if (err ) {
1718+ dev_err (mlxsw_sp -> bus_info -> dev , "Failed to create split port\n" );
1719+ goto err_port_create ;
1720+ }
1721+ }
1722+
1723+ return 0 ;
1724+
1725+ err_port_create :
1726+ for (i -- ; i >= 0 ; i -- )
1727+ mlxsw_sp_port_remove (mlxsw_sp , base_port + i );
1728+ for (i = 0 ; i < count / 2 ; i ++ ) {
1729+ module = mlxsw_sp -> port_to_module [base_port + i * 2 ];
1730+ mlxsw_sp_port_create (mlxsw_sp , base_port + i * 2 , false,
1731+ module , MLXSW_PORT_MODULE_MAX_WIDTH , 0 );
1732+ }
1733+ return err ;
1734+ }
1735+
1736+ static int mlxsw_sp_port_unsplit (void * priv , u8 local_port )
1737+ {
1738+ struct mlxsw_sp * mlxsw_sp = priv ;
1739+ struct mlxsw_sp_port * mlxsw_sp_port ;
1740+ u8 module , cur_width , base_port ;
1741+ unsigned int count ;
1742+ int i ;
1743+ int err ;
1744+
1745+ mlxsw_sp_port = mlxsw_sp -> ports [local_port ];
1746+ if (!mlxsw_sp_port ) {
1747+ dev_err (mlxsw_sp -> bus_info -> dev , "Port number \"%d\" does not exist\n" ,
1748+ local_port );
1749+ return - EINVAL ;
1750+ }
1751+
1752+ if (!mlxsw_sp_port -> split ) {
1753+ netdev_err (mlxsw_sp_port -> dev , "Port wasn't split\n" );
1754+ return - EINVAL ;
1755+ }
1756+
1757+ err = mlxsw_sp_port_module_info_get (mlxsw_sp , local_port , & module ,
1758+ & cur_width );
1759+ if (err ) {
1760+ netdev_err (mlxsw_sp_port -> dev , "Failed to get port's width\n" );
1761+ return err ;
1762+ }
1763+ count = cur_width == 1 ? 4 : 2 ;
1764+
1765+ base_port = mlxsw_sp_cluster_base_port_get (local_port );
1766+
1767+ /* Determine which ports to remove. */
1768+ if (count == 2 && local_port >= base_port + 2 )
1769+ base_port = base_port + 2 ;
1770+
1771+ for (i = 0 ; i < count ; i ++ )
1772+ mlxsw_sp_port_remove (mlxsw_sp , base_port + i );
1773+
1774+ for (i = 0 ; i < count / 2 ; i ++ ) {
1775+ module = mlxsw_sp -> port_to_module [base_port + i * 2 ];
1776+ err = mlxsw_sp_port_create (mlxsw_sp , base_port + i * 2 , false,
1777+ module , MLXSW_PORT_MODULE_MAX_WIDTH ,
1778+ 0 );
1779+ if (err )
1780+ dev_err (mlxsw_sp -> bus_info -> dev , "Failed to reinstantiate port\n" );
1781+ }
1782+
1783+ return 0 ;
1784+ }
1785+
15791786static void mlxsw_sp_pude_event_func (const struct mlxsw_reg_info * reg ,
15801787 char * pude_pl , void * priv )
15811788{
@@ -1999,6 +2206,8 @@ static struct mlxsw_driver mlxsw_sp_driver = {
19992206 .priv_size = sizeof (struct mlxsw_sp ),
20002207 .init = mlxsw_sp_init ,
20012208 .fini = mlxsw_sp_fini ,
2209+ .port_split = mlxsw_sp_port_split ,
2210+ .port_unsplit = mlxsw_sp_port_unsplit ,
20022211 .txhdr_construct = mlxsw_sp_txhdr_construct ,
20032212 .txhdr_len = MLXSW_TXHDR_LEN ,
20042213 .profile = & mlxsw_sp_config_profile ,
0 commit comments