* [PATCH] net: stmmac: Add NCSI support
@ 2025-07-14 5:35 Marvin Lin
2025-07-14 13:53 ` Andrew Lunn
0 siblings, 1 reply; 2+ messages in thread
From: Marvin Lin @ 2025-07-14 5:35 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, mcoquelin.stm32,
alexandre.torgue
Cc: netdev, linux-stm32, linux-arm-kernel, openbmc, KWLIU, tmaimon77,
kflin, Marvin Lin
The NCSI is defined as the interface between BMC and Network
Controller on Host side. The interface is responsible for providing
external network connectivity for BMC.
This patch adds support for NCSI that registers and starts NCSI
device, it also skips PHY-related operations if use-ncsi property is
defined in the DTS.
Signed-off-by: Marvin Lin <milkfafa@gmail.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 166 +++++++++++++-----
.../ethernet/stmicro/stmmac/stmmac_platform.c | 27 ++-
include/linux/stmmac.h | 1 +
4 files changed, 142 insertions(+), 54 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index cda09cf5dcca..9dc386e0bc6b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -365,6 +365,8 @@ struct stmmac_priv {
/* XDP BPF Program */
unsigned long *af_xdp_zc_qps;
struct bpf_prog *xdp_prog;
+
+ struct ncsi_dev *ncsidev;
};
enum stmmac_state {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index b948df1bff9a..dfe3e588ffb2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -51,6 +51,7 @@
#include "dwmac1000.h"
#include "dwxgmac2.h"
#include "hwif.h"
+#include <net/ncsi.h>
/* As long as the interface is active, we keep the timestamping counter enabled
* with fine resolution and binary rollover. This avoid non-monotonic behavior
@@ -3131,10 +3132,12 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE))
priv->plat->dma_cfg->atds = 1;
- ret = stmmac_reset(priv, priv->ioaddr);
- if (ret) {
- netdev_err(priv->dev, "Failed to reset the dma\n");
- return ret;
+ if (!priv->plat->use_ncsi) {
+ ret = stmmac_reset(priv, priv->ioaddr);
+ if (ret) {
+ netdev_err(priv->dev, "Failed to reset the dma\n");
+ return ret;
+ }
}
/* DMA Configuration */
@@ -3643,6 +3646,14 @@ static void stmmac_hw_teardown(struct net_device *dev)
clk_disable_unprepare(priv->plat->clk_ptp_ref);
}
+static void stmmac_ncsi_handler(struct ncsi_dev *nd)
+{
+ if (unlikely(nd->state != ncsi_dev_state_functional))
+ return;
+
+ netdev_info(nd->dev, "NCSI interface %s\n", nd->link_up ? "up" : "down");
+}
+
static void stmmac_free_irq(struct net_device *dev,
enum request_irq_err irq_err, int irq_idx)
{
@@ -4046,14 +4057,16 @@ static int __stmmac_open(struct net_device *dev,
if (ret < 0)
return ret;
- if ((!priv->hw->xpcs ||
- xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73)) {
- ret = stmmac_init_phy(dev);
- if (ret) {
- netdev_err(priv->dev,
- "%s: Cannot attach to PHY (error: %d)\n",
- __func__, ret);
- goto init_phy_error;
+ if (!priv->plat->use_ncsi) {
+ if ((!priv->hw->xpcs ||
+ xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73)) {
+ ret = stmmac_init_phy(dev);
+ if (ret) {
+ netdev_err(priv->dev,
+ "%s: Cannot attach to PHY (error: %d)\n",
+ __func__, ret);
+ goto init_phy_error;
+ }
}
}
@@ -4082,9 +4095,23 @@ static int __stmmac_open(struct net_device *dev,
stmmac_init_coalesce(priv);
- phylink_start(priv->phylink);
- /* We may have called phylink_speed_down before */
- phylink_speed_up(priv->phylink);
+ if (priv->plat->use_ncsi) {
+ u32 ctrl;
+
+ stmmac_mac_flow_ctrl(priv, DUPLEX_FULL, FLOW_AUTO);
+ ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
+ ctrl &= ~priv->hw->link.speed_mask;
+ ctrl |= priv->hw->link.speed100;
+ ctrl |= priv->hw->link.duplex;
+ writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
+
+ /* If using NC-SI subsystem, set our carrier on and start the stack */
+ netif_carrier_on(dev);
+ } else {
+ phylink_start(priv->phylink);
+ /* We may have called phylink_speed_down before */
+ phylink_speed_up(priv->phylink);
+ }
ret = stmmac_request_irq(dev);
if (ret)
@@ -4094,17 +4121,29 @@ static int __stmmac_open(struct net_device *dev,
netif_tx_start_all_queues(priv->dev);
stmmac_enable_all_dma_irq(priv);
- return 0;
+ /* Start the NCSI device */
+ if (priv->plat->use_ncsi) {
+ ret = ncsi_start_dev(priv->ncsidev);
+ if (ret) {
+ netdev_err(priv->dev, "ERROR: start the ncsi device(%d)\n", ret);
+ goto ncsi_error;
+ }
+ }
+ return 0;
+ncsi_error:
+ stmmac_disable_all_queues(priv);
irq_error:
- phylink_stop(priv->phylink);
+ if (!priv->plat->use_ncsi)
+ phylink_stop(priv->phylink);
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer);
stmmac_hw_teardown(dev);
init_error:
- phylink_disconnect_phy(priv->phylink);
+ if (!priv->plat->use_ncsi)
+ phylink_disconnect_phy(priv->phylink);
init_phy_error:
pm_runtime_put(priv->device);
return ret;
@@ -4139,11 +4178,15 @@ static int stmmac_release(struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
u32 chan;
- if (device_may_wakeup(priv->device))
- phylink_speed_down(priv->phylink, false);
- /* Stop and disconnect the PHY */
- phylink_stop(priv->phylink);
- phylink_disconnect_phy(priv->phylink);
+ if (priv->plat->use_ncsi) {
+ ncsi_stop_dev(priv->ncsidev);
+ } else {
+ if (device_may_wakeup(priv->device))
+ phylink_speed_down(priv->phylink, false);
+ /* Stop and disconnect the PHY */
+ phylink_stop(priv->phylink);
+ phylink_disconnect_phy(priv->phylink);
+ }
stmmac_disable_all_queues(priv);
@@ -6230,7 +6273,8 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCGMIIPHY:
case SIOCGMIIREG:
case SIOCSMIIREG:
- ret = phylink_mii_ioctl(priv->phylink, rq, cmd);
+ if (!priv->plat->use_ncsi)
+ ret = phylink_mii_ioctl(priv->phylink, rq, cmd);
break;
default:
break;
@@ -6691,6 +6735,9 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
bool is_double = false;
int ret;
+ if (priv->plat->use_ncsi)
+ return ncsi_vlan_rx_add_vid(ndev, proto, vid);
+
ret = pm_runtime_resume_and_get(priv->device);
if (ret < 0)
return ret;
@@ -6725,6 +6772,9 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
bool is_double = false;
int ret;
+ if (priv->plat->use_ncsi)
+ return ncsi_vlan_rx_kill_vid(ndev, proto, vid);
+
ret = pm_runtime_resume_and_get(priv->device);
if (ret < 0)
return ret;
@@ -7504,7 +7554,9 @@ int stmmac_dvr_probe(struct device *device,
if (!priv->xstats.pcpu_stats)
return -ENOMEM;
- stmmac_set_ethtool_ops(ndev);
+ if (!plat_dat->use_ncsi)
+ stmmac_set_ethtool_ops(ndev);
+
priv->pause_time = pause;
priv->plat = plat_dat;
priv->ioaddr = res->addr;
@@ -7619,6 +7671,9 @@ int stmmac_dvr_probe(struct device *device,
* host DMA width for allocation and the device DMA width for
* register handling.
*/
+ if (priv->plat->use_ncsi)
+ ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+
if (priv->plat->host_dma_width)
priv->dma_cap.host_dma_width = priv->plat->host_dma_width;
else
@@ -7728,22 +7783,35 @@ int stmmac_dvr_probe(struct device *device,
if (!pm_runtime_enabled(device))
pm_runtime_enable(device);
- ret = stmmac_mdio_register(ndev);
- if (ret < 0) {
- dev_err_probe(priv->device, ret,
- "MDIO bus (id: %d) registration failed\n",
- priv->plat->bus_id);
- goto error_mdio_register;
- }
+ if (!priv->plat->use_ncsi) {
+ ret = stmmac_mdio_register(ndev);
+ if (ret < 0) {
+ dev_err_probe(priv->device, ret,
+ "MDIO bus (id: %d) registration failed\n",
+ priv->plat->bus_id);
+ goto error_mdio_register;
+ }
- ret = stmmac_pcs_setup(ndev);
- if (ret)
- goto error_pcs_setup;
+ ret = stmmac_pcs_setup(ndev);
+ if (ret)
+ goto error_pcs_setup;
- ret = stmmac_phy_setup(priv);
- if (ret) {
- netdev_err(ndev, "failed to setup phy (%d)\n", ret);
- goto error_phy_setup;
+ ret = stmmac_phy_setup(priv);
+ if (ret) {
+ netdev_err(ndev, "failed to setup phy (%d)\n", ret);
+ goto error_phy_setup;
+ }
+ } else {
+ if (!IS_ENABLED(CONFIG_NET_NCSI)) {
+ netdev_err(priv->dev, "CONFIG_NET_NCSI not enabled\n");
+ goto error_phy_setup;
+ }
+ dev_info(priv->device, "register NCSI dev\n");
+ priv->ncsidev = ncsi_register_dev(priv->dev, stmmac_ncsi_handler);
+ if (!priv->ncsidev)
+ goto error_phy_setup;
+
+ dev_info(priv->device, "Using NCSI interface\n");
}
ret = register_netdev(ndev);
@@ -7768,9 +7836,11 @@ int stmmac_dvr_probe(struct device *device,
return ret;
error_netdev_register:
- phylink_destroy(priv->phylink);
+ if (!priv->plat->use_ncsi)
+ phylink_destroy(priv->phylink);
error_phy_setup:
- stmmac_pcs_clean(ndev);
+ if (!priv->plat->use_ncsi)
+ stmmac_pcs_clean(ndev);
error_pcs_setup:
stmmac_mdio_unregister(ndev);
error_mdio_register:
@@ -7868,13 +7938,15 @@ int stmmac_suspend(struct device *dev)
mutex_unlock(&priv->lock);
- rtnl_lock();
- if (device_may_wakeup(priv->device) && !priv->plat->pmt)
- phylink_speed_down(priv->phylink, false);
+ if (!priv->plat->use_ncsi) {
+ rtnl_lock();
+ if (device_may_wakeup(priv->device) && !priv->plat->pmt)
+ phylink_speed_down(priv->phylink, false);
- phylink_suspend(priv->phylink,
- device_may_wakeup(priv->device) && priv->plat->pmt);
- rtnl_unlock();
+ phylink_suspend(priv->phylink,
+ device_may_wakeup(priv->device) && priv->plat->pmt);
+ rtnl_unlock();
+ }
if (stmmac_fpe_supported(priv))
ethtool_mmsv_stop(&priv->fpe_cfg.mmsv);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index b80c1efdb323..de500e59461f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -447,17 +447,30 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
eth_zero_addr(mac);
}
- phy_mode = device_get_phy_mode(&pdev->dev);
- if (phy_mode < 0)
- return ERR_PTR(phy_mode);
+ if (of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) {
+ plat->use_ncsi = true;
+ plat->has_xgmac = 0;
+ plat->has_gmac4 = 0;
+ plat->has_gmac = 0;
+ } else {
+ plat->use_ncsi = false;
+ }
- plat->phy_interface = phy_mode;
+ if (!plat->use_ncsi) {
+ phy_mode = device_get_phy_mode(&pdev->dev);
+ if (phy_mode < 0)
+ return ERR_PTR(phy_mode);
+
+ plat->phy_interface = phy_mode;
+ }
rc = stmmac_of_get_mac_mode(np);
plat->mac_interface = rc < 0 ? plat->phy_interface : rc;
- /* Some wrapper drivers still rely on phy_node. Let's save it while
- * they are not converted to phylink. */
- plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
+ if (!plat->use_ncsi) {
+ /* Some wrapper drivers still rely on phy_node. Let's save it while
+ * they are not converted to phylink. */
+ plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
+ }
/* PHYLINK automatically parses the phy-handle property */
plat->port_node = of_fwnode_handle(np);
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 26ddf95d23f9..668768043f7e 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -288,5 +288,6 @@ struct plat_stmmacenet_data {
int msi_tx_base_vec;
const struct dwmac4_addrs *dwmac4_addrs;
unsigned int flags;
+ int use_ncsi;
};
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] net: stmmac: Add NCSI support
2025-07-14 5:35 [PATCH] net: stmmac: Add NCSI support Marvin Lin
@ 2025-07-14 13:53 ` Andrew Lunn
0 siblings, 0 replies; 2+ messages in thread
From: Andrew Lunn @ 2025-07-14 13:53 UTC (permalink / raw)
To: Marvin Lin
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, mcoquelin.stm32,
alexandre.torgue, netdev, linux-stm32, linux-arm-kernel, openbmc,
KWLIU, tmaimon77, kflin
> - ret = stmmac_reset(priv, priv->ioaddr);
> - if (ret) {
> - netdev_err(priv->dev, "Failed to reset the dma\n");
> - return ret;
> + if (!priv->plat->use_ncsi) {
> + ret = stmmac_reset(priv, priv->ioaddr);
> + if (ret) {
> + netdev_err(priv->dev, "Failed to reset the dma\n");
> + return ret;
> + }
> }
Please break this patch up into a series and include good commit
messages. You can then explain why this change is safe.
> /* DMA Configuration */
> @@ -3643,6 +3646,14 @@ static void stmmac_hw_teardown(struct net_device *dev)
> clk_disable_unprepare(priv->plat->clk_ptp_ref);
> }
>
> +static void stmmac_ncsi_handler(struct ncsi_dev *nd)
> +{
> + if (unlikely(nd->state != ncsi_dev_state_functional))
> + return;
> +
> + netdev_info(nd->dev, "NCSI interface %s\n", nd->link_up ? "up" : "down");
Please don't spam the kernel log. Only do prints if something goes
wrong.
> +}
> +
> static void stmmac_free_irq(struct net_device *dev,
> enum request_irq_err irq_err, int irq_idx)
> {
> @@ -4046,14 +4057,16 @@ static int __stmmac_open(struct net_device *dev,
> if (ret < 0)
> return ret;
>
> - if ((!priv->hw->xpcs ||
> - xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73)) {
> - ret = stmmac_init_phy(dev);
> - if (ret) {
> - netdev_err(priv->dev,
> - "%s: Cannot attach to PHY (error: %d)\n",
> - __func__, ret);
> - goto init_phy_error;
> + if (!priv->plat->use_ncsi) {
> + if ((!priv->hw->xpcs ||
My understanding of NCSI is that you have an additional RGMII like
port feeding into the MAC. The MAC still has all its media machinery,
a PCS, PHY etc. Something needs to drive that PCS and PHY. So it would
be good to explain in the commit message why you are removing all
this.
Andrew
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-07-14 13:53 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-14 5:35 [PATCH] net: stmmac: Add NCSI support Marvin Lin
2025-07-14 13:53 ` Andrew Lunn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).