@@ -594,12 +594,18 @@ static int dpaa2_switch_port_change_mtu(struct net_device *netdev, int mtu)
594594 return 0 ;
595595}
596596
597- static int dpaa2_switch_port_carrier_state_sync (struct net_device * netdev )
597+ static int dpaa2_switch_port_link_state_update (struct net_device * netdev )
598598{
599599 struct ethsw_port_priv * port_priv = netdev_priv (netdev );
600600 struct dpsw_link_state state ;
601601 int err ;
602602
603+ /* When we manage the MAC/PHY using phylink there is no need
604+ * to manually update the netif_carrier.
605+ */
606+ if (dpaa2_switch_port_is_type_phy (port_priv ))
607+ return 0 ;
608+
603609 /* Interrupts are received even though no one issued an 'ifconfig up'
604610 * on the switch interface. Ignore these link state update interrupts
605611 */
@@ -677,12 +683,14 @@ static int dpaa2_switch_port_open(struct net_device *netdev)
677683 struct ethsw_core * ethsw = port_priv -> ethsw_data ;
678684 int err ;
679685
680- /* Explicitly set carrier off, otherwise
681- * netif_carrier_ok() will return true and cause 'ip link show'
682- * to report the LOWER_UP flag, even though the link
683- * notification wasn't even received.
684- */
685- netif_carrier_off (netdev );
686+ if (!dpaa2_switch_port_is_type_phy (port_priv )) {
687+ /* Explicitly set carrier off, otherwise
688+ * netif_carrier_ok() will return true and cause 'ip link show'
689+ * to report the LOWER_UP flag, even though the link
690+ * notification wasn't even received.
691+ */
692+ netif_carrier_off (netdev );
693+ }
686694
687695 err = dpsw_if_enable (port_priv -> ethsw_data -> mc_io , 0 ,
688696 port_priv -> ethsw_data -> dpsw_handle ,
@@ -692,23 +700,12 @@ static int dpaa2_switch_port_open(struct net_device *netdev)
692700 return err ;
693701 }
694702
695- /* sync carrier state */
696- err = dpaa2_switch_port_carrier_state_sync (netdev );
697- if (err ) {
698- netdev_err (netdev ,
699- "dpaa2_switch_port_carrier_state_sync err %d\n" , err );
700- goto err_carrier_sync ;
701- }
702-
703703 dpaa2_switch_enable_ctrl_if_napi (ethsw );
704704
705- return 0 ;
705+ if (dpaa2_switch_port_is_type_phy (port_priv ))
706+ phylink_start (port_priv -> mac -> phylink );
706707
707- err_carrier_sync :
708- dpsw_if_disable (port_priv -> ethsw_data -> mc_io , 0 ,
709- port_priv -> ethsw_data -> dpsw_handle ,
710- port_priv -> idx );
711- return err ;
708+ return 0 ;
712709}
713710
714711static int dpaa2_switch_port_stop (struct net_device * netdev )
@@ -717,6 +714,13 @@ static int dpaa2_switch_port_stop(struct net_device *netdev)
717714 struct ethsw_core * ethsw = port_priv -> ethsw_data ;
718715 int err ;
719716
717+ if (dpaa2_switch_port_is_type_phy (port_priv )) {
718+ phylink_stop (port_priv -> mac -> phylink );
719+ } else {
720+ netif_tx_stop_all_queues (netdev );
721+ netif_carrier_off (netdev );
722+ }
723+
720724 err = dpsw_if_disable (port_priv -> ethsw_data -> mc_io , 0 ,
721725 port_priv -> ethsw_data -> dpsw_handle ,
722726 port_priv -> idx );
@@ -1419,41 +1423,103 @@ bool dpaa2_switch_port_dev_check(const struct net_device *netdev)
14191423 return netdev -> netdev_ops == & dpaa2_switch_port_ops ;
14201424}
14211425
1422- static void dpaa2_switch_links_state_update (struct ethsw_core * ethsw )
1426+ static int dpaa2_switch_port_connect_mac (struct ethsw_port_priv * port_priv )
14231427{
1424- int i ;
1428+ struct fsl_mc_device * dpsw_port_dev , * dpmac_dev ;
1429+ struct dpaa2_mac * mac ;
1430+ int err ;
14251431
1426- for (i = 0 ; i < ethsw -> sw_attr .num_ifs ; i ++ ) {
1427- dpaa2_switch_port_carrier_state_sync (ethsw -> ports [i ]-> netdev );
1428- dpaa2_switch_port_set_mac_addr (ethsw -> ports [i ]);
1432+ dpsw_port_dev = to_fsl_mc_device (port_priv -> netdev -> dev .parent );
1433+ dpmac_dev = fsl_mc_get_endpoint (dpsw_port_dev , port_priv -> idx );
1434+
1435+ if (PTR_ERR (dpmac_dev ) == - EPROBE_DEFER )
1436+ return PTR_ERR (dpmac_dev );
1437+
1438+ if (IS_ERR (dpmac_dev ) || dpmac_dev -> dev .type != & fsl_mc_bus_dpmac_type )
1439+ return 0 ;
1440+
1441+ mac = kzalloc (sizeof (* mac ), GFP_KERNEL );
1442+ if (!mac )
1443+ return - ENOMEM ;
1444+
1445+ mac -> mc_dev = dpmac_dev ;
1446+ mac -> mc_io = port_priv -> ethsw_data -> mc_io ;
1447+ mac -> net_dev = port_priv -> netdev ;
1448+
1449+ err = dpaa2_mac_open (mac );
1450+ if (err )
1451+ goto err_free_mac ;
1452+ port_priv -> mac = mac ;
1453+
1454+ if (dpaa2_switch_port_is_type_phy (port_priv )) {
1455+ err = dpaa2_mac_connect (mac );
1456+ if (err ) {
1457+ netdev_err (port_priv -> netdev ,
1458+ "Error connecting to the MAC endpoint %pe\n" ,
1459+ ERR_PTR (err ));
1460+ goto err_close_mac ;
1461+ }
14291462 }
1463+
1464+ return 0 ;
1465+
1466+ err_close_mac :
1467+ dpaa2_mac_close (mac );
1468+ port_priv -> mac = NULL ;
1469+ err_free_mac :
1470+ kfree (mac );
1471+ return err ;
1472+ }
1473+
1474+ static void dpaa2_switch_port_disconnect_mac (struct ethsw_port_priv * port_priv )
1475+ {
1476+ if (dpaa2_switch_port_is_type_phy (port_priv ))
1477+ dpaa2_mac_disconnect (port_priv -> mac );
1478+
1479+ if (!dpaa2_switch_port_has_mac (port_priv ))
1480+ return ;
1481+
1482+ dpaa2_mac_close (port_priv -> mac );
1483+ kfree (port_priv -> mac );
1484+ port_priv -> mac = NULL ;
14301485}
14311486
14321487static irqreturn_t dpaa2_switch_irq0_handler_thread (int irq_num , void * arg )
14331488{
14341489 struct device * dev = (struct device * )arg ;
14351490 struct ethsw_core * ethsw = dev_get_drvdata (dev );
1436-
1437- /* Mask the events and the if_id reserved bits to be cleared on read */
1438- u32 status = DPSW_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000 ;
1439- int err ;
1491+ struct ethsw_port_priv * port_priv ;
1492+ u32 status = ~0 ;
1493+ int err , if_id ;
14401494
14411495 err = dpsw_get_irq_status (ethsw -> mc_io , 0 , ethsw -> dpsw_handle ,
14421496 DPSW_IRQ_INDEX_IF , & status );
14431497 if (err ) {
14441498 dev_err (dev , "Can't get irq status (err %d)\n" , err );
1445-
1446- err = dpsw_clear_irq_status (ethsw -> mc_io , 0 , ethsw -> dpsw_handle ,
1447- DPSW_IRQ_INDEX_IF , 0xFFFFFFFF );
1448- if (err )
1449- dev_err (dev , "Can't clear irq status (err %d)\n" , err );
14501499 goto out ;
14511500 }
14521501
1453- if (status & DPSW_IRQ_EVENT_LINK_CHANGED )
1454- dpaa2_switch_links_state_update (ethsw );
1502+ if_id = (status & 0xFFFF0000 ) >> 16 ;
1503+ port_priv = ethsw -> ports [if_id ];
1504+
1505+ if (status & DPSW_IRQ_EVENT_LINK_CHANGED ) {
1506+ dpaa2_switch_port_link_state_update (port_priv -> netdev );
1507+ dpaa2_switch_port_set_mac_addr (port_priv );
1508+ }
1509+
1510+ if (status & DPSW_IRQ_EVENT_ENDPOINT_CHANGED ) {
1511+ if (dpaa2_switch_port_has_mac (port_priv ))
1512+ dpaa2_switch_port_disconnect_mac (port_priv );
1513+ else
1514+ dpaa2_switch_port_connect_mac (port_priv );
1515+ }
14551516
14561517out :
1518+ err = dpsw_clear_irq_status (ethsw -> mc_io , 0 , ethsw -> dpsw_handle ,
1519+ DPSW_IRQ_INDEX_IF , status );
1520+ if (err )
1521+ dev_err (dev , "Can't clear irq status (err %d)\n" , err );
1522+
14571523 return IRQ_HANDLED ;
14581524}
14591525
@@ -3133,6 +3199,7 @@ static int dpaa2_switch_remove(struct fsl_mc_device *sw_dev)
31333199 for (i = 0 ; i < ethsw -> sw_attr .num_ifs ; i ++ ) {
31343200 port_priv = ethsw -> ports [i ];
31353201 unregister_netdev (port_priv -> netdev );
3202+ dpaa2_switch_port_disconnect_mac (port_priv );
31363203 free_netdev (port_priv -> netdev );
31373204 }
31383205
@@ -3212,6 +3279,10 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
32123279 goto err_port_probe ;
32133280 port_priv -> learn_ena = false;
32143281
3282+ err = dpaa2_switch_port_connect_mac (port_priv );
3283+ if (err )
3284+ goto err_port_probe ;
3285+
32153286 return 0 ;
32163287
32173288err_port_probe :
@@ -3288,12 +3359,6 @@ static int dpaa2_switch_probe(struct fsl_mc_device *sw_dev)
32883359 & ethsw -> fq [i ].napi , dpaa2_switch_poll ,
32893360 NAPI_POLL_WEIGHT );
32903361
3291- err = dpsw_enable (ethsw -> mc_io , 0 , ethsw -> dpsw_handle );
3292- if (err ) {
3293- dev_err (ethsw -> dev , "dpsw_enable err %d\n" , err );
3294- goto err_free_netdev ;
3295- }
3296-
32973362 /* Setup IRQs */
32983363 err = dpaa2_switch_setup_irqs (sw_dev );
32993364 if (err )
0 commit comments