@@ -1051,6 +1051,14 @@ static struct ptp_clock_info ocelot_ptp_clock_info = {
10511051 .enable = ocelot_ptp_enable ,
10521052};
10531053
1054+ static void mscc_ocelot_teardown_devlink_ports (struct ocelot * ocelot )
1055+ {
1056+ int port ;
1057+
1058+ for (port = 0 ; port < ocelot -> num_phys_ports ; port ++ )
1059+ ocelot_port_devlink_teardown (ocelot , port );
1060+ }
1061+
10541062static void mscc_ocelot_release_ports (struct ocelot * ocelot )
10551063{
10561064 int port ;
@@ -1078,28 +1086,44 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
10781086{
10791087 struct ocelot * ocelot = platform_get_drvdata (pdev );
10801088 struct device_node * portnp ;
1081- int err ;
1089+ bool * registered_ports ;
1090+ int port , err ;
1091+ u32 reg ;
10821092
10831093 ocelot -> ports = devm_kcalloc (ocelot -> dev , ocelot -> num_phys_ports ,
10841094 sizeof (struct ocelot_port * ), GFP_KERNEL );
10851095 if (!ocelot -> ports )
10861096 return - ENOMEM ;
10871097
1098+ ocelot -> devlink_ports = devm_kcalloc (ocelot -> dev ,
1099+ ocelot -> num_phys_ports ,
1100+ sizeof (* ocelot -> devlink_ports ),
1101+ GFP_KERNEL );
1102+ if (!ocelot -> devlink_ports )
1103+ return - ENOMEM ;
1104+
1105+ registered_ports = kcalloc (ocelot -> num_phys_ports , sizeof (bool ),
1106+ GFP_KERNEL );
1107+ if (!registered_ports )
1108+ return - ENOMEM ;
1109+
10881110 for_each_available_child_of_node (ports , portnp ) {
10891111 struct ocelot_port_private * priv ;
10901112 struct ocelot_port * ocelot_port ;
10911113 struct device_node * phy_node ;
1114+ struct devlink_port * dlp ;
10921115 phy_interface_t phy_mode ;
10931116 struct phy_device * phy ;
10941117 struct regmap * target ;
10951118 struct resource * res ;
10961119 struct phy * serdes ;
10971120 char res_name [8 ];
1098- u32 port ;
10991121
1100- if (of_property_read_u32 (portnp , "reg" , & port ))
1122+ if (of_property_read_u32 (portnp , "reg" , & reg ))
11011123 continue ;
11021124
1125+ port = reg ;
1126+
11031127 snprintf (res_name , sizeof (res_name ), "port%d" , port );
11041128
11051129 res = platform_get_resource_byname (pdev , IORESOURCE_MEM ,
@@ -1117,15 +1141,26 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
11171141 if (!phy )
11181142 continue ;
11191143
1144+ err = ocelot_port_devlink_init (ocelot , port ,
1145+ DEVLINK_PORT_FLAVOUR_PHYSICAL );
1146+ if (err ) {
1147+ of_node_put (portnp );
1148+ goto out_teardown ;
1149+ }
1150+
11201151 err = ocelot_probe_port (ocelot , port , target , phy );
11211152 if (err ) {
11221153 of_node_put (portnp );
1123- return err ;
1154+ goto out_teardown ;
11241155 }
11251156
1157+ registered_ports [port ] = true;
1158+
11261159 ocelot_port = ocelot -> ports [port ];
11271160 priv = container_of (ocelot_port , struct ocelot_port_private ,
11281161 port );
1162+ dlp = & ocelot -> devlink_ports [port ];
1163+ devlink_port_type_eth_set (dlp , priv -> dev );
11291164
11301165 of_get_phy_mode (portnp , & phy_mode );
11311166
@@ -1150,7 +1185,8 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
11501185 "invalid phy mode for port%d, (Q)SGMII only\n" ,
11511186 port );
11521187 of_node_put (portnp );
1153- return - EINVAL ;
1188+ err = - EINVAL ;
1189+ goto out_teardown ;
11541190 }
11551191
11561192 serdes = devm_of_phy_get (ocelot -> dev , portnp , NULL );
@@ -1164,20 +1200,54 @@ static int mscc_ocelot_init_ports(struct platform_device *pdev,
11641200 port );
11651201
11661202 of_node_put (portnp );
1167- return err ;
1203+ goto out_teardown ;
11681204 }
11691205
11701206 priv -> serdes = serdes ;
11711207 }
11721208
1209+ /* Initialize unused devlink ports at the end */
1210+ for (port = 0 ; port < ocelot -> num_phys_ports ; port ++ ) {
1211+ if (registered_ports [port ])
1212+ continue ;
1213+
1214+ err = ocelot_port_devlink_init (ocelot , port ,
1215+ DEVLINK_PORT_FLAVOUR_UNUSED );
1216+ if (err ) {
1217+ while (port -- >= 0 ) {
1218+ if (!registered_ports [port ])
1219+ continue ;
1220+ ocelot_port_devlink_teardown (ocelot , port );
1221+ }
1222+
1223+ goto out_teardown ;
1224+ }
1225+ }
1226+
1227+ kfree (registered_ports );
1228+
11731229 return 0 ;
1230+
1231+ out_teardown :
1232+ /* Unregister the network interfaces */
1233+ mscc_ocelot_release_ports (ocelot );
1234+ /* Tear down devlink ports for the registered network interfaces */
1235+ for (port = 0 ; port < ocelot -> num_phys_ports ; port ++ ) {
1236+ if (!registered_ports [port ])
1237+ continue ;
1238+
1239+ ocelot_port_devlink_teardown (ocelot , port );
1240+ }
1241+ kfree (registered_ports );
1242+ return err ;
11741243}
11751244
11761245static int mscc_ocelot_probe (struct platform_device * pdev )
11771246{
11781247 struct device_node * np = pdev -> dev .of_node ;
11791248 int err , irq_xtr , irq_ptp_rdy ;
11801249 struct device_node * ports ;
1250+ struct devlink * devlink ;
11811251 struct ocelot * ocelot ;
11821252 struct regmap * hsio ;
11831253 unsigned int i ;
@@ -1201,10 +1271,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12011271 if (!np && !pdev -> dev .platform_data )
12021272 return - ENODEV ;
12031273
1204- ocelot = devm_kzalloc ( & pdev -> dev , sizeof (* ocelot ), GFP_KERNEL );
1205- if (!ocelot )
1274+ devlink = devlink_alloc ( & ocelot_devlink_ops , sizeof (* ocelot ));
1275+ if (!devlink )
12061276 return - ENOMEM ;
12071277
1278+ ocelot = devlink_priv (devlink );
1279+ ocelot -> devlink = priv_to_devlink (ocelot );
12081280 platform_set_drvdata (pdev , ocelot );
12091281 ocelot -> dev = & pdev -> dev ;
12101282
@@ -1221,7 +1293,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12211293 ocelot -> targets [io_target [i ].id ] = NULL ;
12221294 continue ;
12231295 }
1224- return PTR_ERR (target );
1296+ err = PTR_ERR (target );
1297+ goto out_free_devlink ;
12251298 }
12261299
12271300 ocelot -> targets [io_target [i ].id ] = target ;
@@ -1230,24 +1303,25 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12301303 hsio = syscon_regmap_lookup_by_compatible ("mscc,ocelot-hsio" );
12311304 if (IS_ERR (hsio )) {
12321305 dev_err (& pdev -> dev , "missing hsio syscon\n" );
1233- return PTR_ERR (hsio );
1306+ err = PTR_ERR (hsio );
1307+ goto out_free_devlink ;
12341308 }
12351309
12361310 ocelot -> targets [HSIO ] = hsio ;
12371311
12381312 err = ocelot_chip_init (ocelot , & ocelot_ops );
12391313 if (err )
1240- return err ;
1314+ goto out_free_devlink ;
12411315
12421316 irq_xtr = platform_get_irq_byname (pdev , "xtr" );
12431317 if (irq_xtr < 0 )
1244- return - ENODEV ;
1318+ goto out_free_devlink ;
12451319
12461320 err = devm_request_threaded_irq (& pdev -> dev , irq_xtr , NULL ,
12471321 ocelot_xtr_irq_handler , IRQF_ONESHOT ,
12481322 "frame extraction" , ocelot );
12491323 if (err )
1250- return err ;
1324+ goto out_free_devlink ;
12511325
12521326 irq_ptp_rdy = platform_get_irq_byname (pdev , "ptp_rdy" );
12531327 if (irq_ptp_rdy > 0 && ocelot -> targets [PTP ]) {
@@ -1256,7 +1330,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12561330 IRQF_ONESHOT , "ptp ready" ,
12571331 ocelot );
12581332 if (err )
1259- return err ;
1333+ goto out_free_devlink ;
12601334
12611335 /* Both the PTP interrupt and the PTP bank are available */
12621336 ocelot -> ptp = 1 ;
@@ -1265,7 +1339,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12651339 ports = of_get_child_by_name (np , "ethernet-ports" );
12661340 if (!ports ) {
12671341 dev_err (ocelot -> dev , "no ethernet-ports child node found\n" );
1268- return - ENODEV ;
1342+ err = - ENODEV ;
1343+ goto out_free_devlink ;
12691344 }
12701345
12711346 ocelot -> num_phys_ports = of_get_child_count (ports );
@@ -1280,10 +1355,14 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
12801355 if (err )
12811356 goto out_put_ports ;
12821357
1283- err = mscc_ocelot_init_ports ( pdev , ports );
1358+ err = devlink_register ( devlink , ocelot -> dev );
12841359 if (err )
12851360 goto out_ocelot_deinit ;
12861361
1362+ err = mscc_ocelot_init_ports (pdev , ports );
1363+ if (err )
1364+ goto out_ocelot_devlink_unregister ;
1365+
12871366 if (ocelot -> ptp ) {
12881367 err = ocelot_init_timestamp (ocelot , & ocelot_ptp_clock_info );
12891368 if (err ) {
@@ -1303,10 +1382,14 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
13031382
13041383 return 0 ;
13051384
1385+ out_ocelot_devlink_unregister :
1386+ devlink_unregister (devlink );
13061387out_ocelot_deinit :
13071388 ocelot_deinit (ocelot );
13081389out_put_ports :
13091390 of_node_put (ports );
1391+ out_free_devlink :
1392+ devlink_free (devlink );
13101393 return err ;
13111394}
13121395
@@ -1316,10 +1399,13 @@ static int mscc_ocelot_remove(struct platform_device *pdev)
13161399
13171400 ocelot_deinit_timestamp (ocelot );
13181401 mscc_ocelot_release_ports (ocelot );
1402+ mscc_ocelot_teardown_devlink_ports (ocelot );
1403+ devlink_unregister (ocelot -> devlink );
13191404 ocelot_deinit (ocelot );
13201405 unregister_switchdev_blocking_notifier (& ocelot_switchdev_blocking_nb );
13211406 unregister_switchdev_notifier (& ocelot_switchdev_nb );
13221407 unregister_netdevice_notifier (& ocelot_netdevice_nb );
1408+ devlink_free (ocelot -> devlink );
13231409
13241410 return 0 ;
13251411}
0 commit comments