Skip to content

drivers: ethernet: nxp: use net_if_carrier correct#100809

Merged
MaureenHelm merged 1 commit intozephyrproject-rtos:mainfrom
maass-hamburg:drivers_ethernet_net_if_carrier_fix
Mar 30, 2026
Merged

drivers: ethernet: nxp: use net_if_carrier correct#100809
MaureenHelm merged 1 commit intozephyrproject-rtos:mainfrom
maass-hamburg:drivers_ethernet_net_if_carrier_fix

Conversation

@maass-hamburg
Copy link
Copy Markdown
Member

net_if_carrier is to be used independently of the
administrative state (start and stop of the ethernet_api).

LOG_DBG("Start interface %d", net_if_get_by_iface(data->iface));

atomic_set_bit(&data->state, CDC_NCM_IFACE_UP);
net_if_carrier_on(data->iface);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way it is no longer wrong. To really make use of it, net_if_carrier should be changed at the points where a connection is established or disconnected. But that is for later.

Aren't these points simply usbd_cdc_ncm_enable() and usbd_cdc_ncm_disable()? If yes, why not just put the calls there instead of commenting "that is for later".

Copy link
Copy Markdown
Contributor

@tmon-nordic tmon-nordic Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is it more like usbd_cdc_ncm_shutdown and .update callback in struct usbd_class_api which are bound to functional state (device configured)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I now changed it, so that it works with plugging the usb cable out and in. (tested on a renesas ek_ra8d1 with the zperf sample and the provided confs and overlays)

@maass-hamburg maass-hamburg force-pushed the drivers_ethernet_net_if_carrier_fix branch from 80e8362 to 6bc7751 Compare December 11, 2025 13:04

atomic_set_bit(&data->state, CDC_NCM_CLASS_SUSPENDED);

net_if_carrier_off(data->iface);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that suspend is not removing carrier. When suspended the device is still connected to host. It may even be possible for the device to issue Remote Wakeup if device reported that it supports Remote Wakeup and host did allow it (enabled the feature before suspending device).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But where are we getting the info, that for example the cable is no longer connected?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What cable do you mean? If "USB cable" then suspend is low power state when the cable is physically connected.

When USB cable is disconnected, all USB classes disable callbacks are called - here it is usbd_cdc_ncm_disable(). When the cable is connected, and device gets configured (so USB functions can operate) then all USB classes enable callbacks are called - here it is usbd_cdc_ncm_enable().

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When USB cable is disconnected, all USB classes disable callbacks are called - here it is usbd_cdc_ncm_disable(). When the cable is connected, and device gets configured (so USB functions can operate) then all USB classes enable callbacks are called - here it is usbd_cdc_ncm_enable().

No it isn't, at least for the device_next subsys. The disable callbacks (usbd_class_disable) are only called on UDC_EVT_RESET by event_handler_bus_reset.
UDC_EVT_VBUS_REMOVED is not used for that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the the net_if_carrier_off() in the suspend therefore.

@manuargue
Copy link
Copy Markdown
Member

ping @sumitbatra-nxp for the GMAC changes for S32

@maass-hamburg maass-hamburg force-pushed the drivers_ethernet_net_if_carrier_fix branch from 6bc7751 to f2aac10 Compare December 11, 2025 16:30
@sonarqubecloud
Copy link
Copy Markdown

@manuargue
Copy link
Copy Markdown
Member

ping @sumitbatra-nxp for the GMAC changes for S32

@maass-hamburg the changes for the NXP S32 GMAC drivers look reasonable to me, but I currently don’t have hardware to test them. Tagging @bperseghetti @PetervdPerk-NXP @sumitbatra-nxp in case you can help with a quick smoke test. Thanks!

@sumitbatra-nxp
Copy link
Copy Markdown
Contributor

@maass-hamburg thanks for the fix aligning carrier with link state.

Could you confirm you tested (or can reason about) these scenarios for eth_nxp_s32_gmac:

TX while link is down: if an application calls .send() while carrier/link is down, do we recover cleanly once link comes back?
Specifically: does Gmac_Ip_SendFrame() ever complete / do TX interrupts fire when link is down, or can TX descriptors/buffers get stuck consumed (leading to timeouts / permanent -ENOBUFS until reboot)?
If this is possible, we may want a small guard in send() to fail fast when carrier is off (e.g. return -ENETDOWN / -EHOSTDOWN) rather than queueing into HW.

Initial carrier state with PHY: the PR sets net_eth_carrier_off(iface) in eth_nxp_s32_iface_init() for PHY-present cases, which makes sense so iface doesn’t look “link up” until PHY reports it.

Please double-check the no-PHY / fixed-link case still sets carrier ON (e.g. if (cfg->phy_dev == NULL) net_if_carrier_on(iface);).

Also, does phy_link_callback_set() guarantee an immediate callback for the PHYs used on S32? If not, carrier could remain OFF until the first link transition/poll. If that’s a concern, we might need a one-time phy_get_link_state() after registering the callback to seed initial carrier state.

@sumitbatra-nxp
Copy link
Copy Markdown
Contributor

Optional validation matrix (what I had in mind while reviewing):

For PHY-based Ethernet (S32 GMAC):

Boot with cable unplugged → carrier stays OFF

Plug cable → carrier ON, traffic works

Unplug cable → carrier OFF, traffic stops cleanly

Admin down/up with cable plugged → traffic stops/resumes without needing cable replug

TX attempted while link down → no TX deadlock or permanent ENOBUFS after link comes back

Rapid link flap → no stuck semaphores / TX mutex / IRQ storm

For USB CDC-NCM:

USB plug/unplug while running iperf → carrier tracks connection, no stale carrier ON after unplug

@mmahadevan108
Copy link
Copy Markdown
Contributor

@manuargue , assigned this PR to you as you added this driver and are more familiar.

if (data->if_state == IF_STATE_CONNECTION_STATUS_SUBMITTED) {
data->if_state = IF_STATE_CONNECTION_STATUS_SENT;
LOG_INF("Connection status sent");
net_if_carrier_on(data->iface);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handling notifications (interrupt endpoint transfer is completed) is the consequence of cdc_ncm_iface_start() scheduling notification work. Removing it from cdc_ncm_iface_start() and calling it here does not really change what happened from network interfaces view. What is the point of this commit?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cdc_ncm_iface_start() will be called by the networking subsystem only once. Meaning, if i disconnect the cable between the board and the host and connect it again, the networking subsystem won't be informed about the disconnection in between and won't f.e. restart the dhcp client. Doing it this way it will be notified. Also this will only be called when there is a connection, if the board is started without the usb cable plugged in, the iface will only go up when it is plugged in.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iface_start and iface_stop should never directly contain net_if_carrier_on and net_if_carrier_off. The carrier is independent of it.


if (data_iface == iface && alternate == 0) {
atomic_clear_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED);
net_if_carrier_off(data->iface);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the current implementation, the network interface on the Zephyr side determines whether the carrier is switched on or off for both sides. Mixing it like that is not correct.

net_if_carrier is to be used independently of the
administrative state (start and stop of the ethernet_api).

This seem to work.

Also it does belong in this commit and looks like a stray change.
Please work on your commit messages.

atomic_clear_bit(&data->state, CDC_NCM_DATA_IFACE_ENABLED);
atomic_clear_bit(&data->state, CDC_NCM_CLASS_SUSPENDED);

net_if_carrier_off(data->iface);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as for changes in usbd_cdc_ncm_update().

manuargue
manuargue previously approved these changes Jan 28, 2026
Copy link
Copy Markdown
Member

@manuargue manuargue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sumitbatra-nxp for your feedback on the NXP GMAC driver. Judging by the discussion, the changes LGTM for NXP GMAC driver.

@maass-hamburg maass-hamburg force-pushed the drivers_ethernet_net_if_carrier_fix branch from 651e07d to e29d230 Compare February 23, 2026 08:19
@maass-hamburg maass-hamburg dismissed jfischer-no’s stale review February 23, 2026 08:21

Objected part no longer part of this PR, now in #104379

Only the nxp driver part remains

@maass-hamburg
Copy link
Copy Markdown
Member Author

To continue I removed the usb part of this PR and split it into #104379

@maass-hamburg
Copy link
Copy Markdown
Member Author

ping @manuargue

manuargue
manuargue previously approved these changes Mar 9, 2026
Copy link
Copy Markdown
Member

@manuargue manuargue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved based on the comments above, I don't have hw to test this.

net_if_carrier is to be used independently of the
administrative state (start and stop of the ethernet_api).

Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
@maass-hamburg
Copy link
Copy Markdown
Member Author

replaced the net_eth_carrier_off in the iface init with net_if_carrier_off, so it matches the iface init of the other ethernet drivers.

@maass-hamburg maass-hamburg requested a review from manuargue March 10, 2026 14:57
@sonarqubecloud
Copy link
Copy Markdown

@maass-hamburg maass-hamburg added this to the v4.4.0 milestone Mar 16, 2026
@maass-hamburg
Copy link
Copy Markdown
Member Author

please take a look @zejiang0jason @mmahadevan108

@maass-hamburg maass-hamburg changed the title drivers: ethernet: use net_if_carrier correct drivers: ethernet: nxp: use net_if_carrier correct Mar 20, 2026
@maass-hamburg
Copy link
Copy Markdown
Member Author

please take a look @yangbolu1991

Copy link
Copy Markdown
Member

@yangbolu1991 yangbolu1991 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't work on s32 platform.
But reviewed the changes, It looks good to me.
Thanks.

@MaureenHelm MaureenHelm merged commit 511a50d into zephyrproject-rtos:main Mar 30, 2026
29 checks passed
@maass-hamburg maass-hamburg deleted the drivers_ethernet_net_if_carrier_fix branch March 30, 2026 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants