[Bug 264006] dwc: dwc interface is not able to send packets when changing the dwc interface's media from the auto-negotiation mode to the forced mode
Date: Sun, 15 May 2022 21:36:28 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=264006 Bug ID: 264006 Summary: dwc: dwc interface is not able to send packets when changing the dwc interface's media from the auto-negotiation mode to the forced mode Product: Base System Version: CURRENT Hardware: arm64 OS: Any Status: New Severity: Affects Some People Priority: --- Component: bin Assignee: bugs@FreeBSD.org Reporter: jiahali@blackberry.com Created attachment 233945 --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=233945&action=edit Preliminary fix patch Test Procedure The dwc interface is directly connected to a host interface, "enp0s31f6" in my test. The auto-negotiation is always enabled in the host interface. The dwc interface will be initialized as autoselect mode by default. The "flag0" option is used in the test to disable auto-negotiation and set the forced mode The test is running on the following release root@generic:~ # uname -a FreeBSD generic 14.0-CURRENT FreeBSD 14.0-CURRENT #0 main-n254961-b91a48693a5: Thu Apr 21 09:35:51 UTC 2022 root@releng1.nyi.freebsd.org:/usr/obj/usr/src/arm64.aarch64/sys/GENERIC arm64 1. Check the config of dwc interface and the interface is able to ping the host interface root@generic:~ # ifconfig -m dwc0 dwc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=8000b<RXCSUM,TXCSUM,VLAN_MTU,LINKSTATE> capabilities=8000b<RXCSUM,TXCSUM,VLAN_MTU,LINKSTATE> ether fa:97:92:f6:f1:09 inet 192.168.3.129 netmask 0xffffff00 broadcast 192.168.3.255 media: Ethernet autoselect (1000baseT <full-duplex>) status: active supported media: media autoselect instance 1 media 1000baseT mediaopt full-duplex,master instance 1 media 1000baseT mediaopt full-duplex instance 1 media 100baseTX mediaopt full-duplex instance 1 media 100baseTX instance 1 media 10baseT/UTP mediaopt full-duplex instance 1 media 10baseT/UTP instance 1 media none instance 1 media autoselect media 1000baseT mediaopt full-duplex,master media 1000baseT mediaopt full-duplex media 100baseTX mediaopt full-duplex media 100baseTX media 10baseT/UTP mediaopt full-duplex media 10baseT/UTP media none nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> root@generic:~ # ping -c 1 192.168.3.2 PING 192.168.3.2 (192.168.3.2): 56 data bytes 64 bytes from 192.168.3.2: icmp_seq=0 ttl=64 time=0.534 ms --- 192.168.3.2 ping statistics --- 1 packets transmitted, 1 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.534/0.534/0.534/0.000 ms 2. Check the config and media status of the host interface, "enp0s31f6". The auto-negotiation process is correct and completed. $ ifconfig enp0s31f6 enp0s31f6: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.3.2 netmask 255.255.255.0 broadcast 192.168.3.255 ether 8c:8c:aa:c1:2b:c3 txqueuelen 1000 (Ethernet) RX packets 4078 bytes 1205102 (1.2 MB) RX errors 0 dropped 52 overruns 0 frame 0 TX packets 24612 bytes 3572527 (3.5 MB) TX errors 0 dropped 0 overruns 0 carrier 526 collisions 0 device interrupt 16 memory 0xae380000-ae3a0000 $ sudo ethtool enp0s31f6 Settings for enp0s31f6: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Supported pause frame use: No Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Advertised pause frame use: No Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: 1000Mb/s Duplex: Full Port: Twisted Pair PHYAD: 1 Transceiver: internal Auto-negotiation: on MDI-X: off (auto) Supports Wake-on: pumbg Wake-on: d Current message level: 0x00000007 (7) drv probe link Link detected: yes 3. Change the dwc interface from auto-negotiation mode to forced mode, 100baseTX mediaopt full-duplex,flag0. root@generic:~ # ifconfig -m dwc0 media 100baseTX mediaopt full-duplex,flag0 root@generic:~ # ifconfig -m dwc0 dwc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=8000b<RXCSUM,TXCSUM,VLAN_MTU,LINKSTATE> capabilities=8000b<RXCSUM,TXCSUM,VLAN_MTU,LINKSTATE> ether fa:97:92:f6:f1:09 inet 192.168.3.129 netmask 0xffffff00 broadcast 192.168.3.255 media: Ethernet 100baseTX <full-duplex> status: active supported media: media autoselect instance 1 media 1000baseT mediaopt full-duplex,master instance 1 media 1000baseT mediaopt full-duplex instance 1 media 100baseTX mediaopt full-duplex instance 1 media 100baseTX instance 1 media 10baseT/UTP mediaopt full-duplex instance 1 media 10baseT/UTP instance 1 media none instance 1 media autoselect media 1000baseT mediaopt full-duplex,master media 1000baseT mediaopt full-duplex media 100baseTX mediaopt full-duplex media 100baseTX media 10baseT/UTP mediaopt full-duplex media 10baseT/UTP media none nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> 4. Check the media status of the host interface. The media set up between the device with auto-negotiation enabled and the device with the forced mode is correct and completed. The host interface is set at the same speed as the dwc interface but its duplex mode is half. $ sudo ethtool enp0s31f6 Settings for enp0s31f6: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Supported pause frame use: No Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Advertised pause frame use: No Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: 100Mb/s Duplex: Half Port: Twisted Pair PHYAD: 1 Transceiver: internal Auto-negotiation: on MDI-X: off (auto) Supports Wake-on: pumbg Wake-on: d Current message level: 0x00000007 (7) drv probe link Link detected: yes 5. The dwc interface is not able to ping the host interface anymore. Based on the result of "netstat", the packet is sent from the network layer but not recorded at the link-layer level root@generic:~ # netstat -nI dwc0 Name Mtu Network Address Ipkts Ierrs Idrop Opkts Oerrs Coll dwc0 1500 <Link#1> fa:97:92:f6:f1:09 130 0 0 132 0 0 dwc0 - 192.168.3.0/2 192.168.3.129 54 - - 6 - - root@generic:~ # ping -c 1 192.168.3.2 PING 192.168.3.2 (192.168.3.2): 56 data bytes --- 192.168.3.2 ping statistics --- 1 packets transmitted, 0 packets received, 100.0% packet loss root@generic:~ # netstat -nI dwc0 Name Mtu Network Address Ipkts Ierrs Idrop Opkts Oerrs Coll dwc0 1500 <Link#1> fa:97:92:f6:f1:09 130 0 0 132 0 0 dwc0 - 192.168.3.0/2 192.168.3.129 54 - - 7 - - 6. Set the dwc interface into another forced mode. "PING" is also failed. root@generic:~ # ifconfig -m dwc0 media 10baseT/UTP mediaopt flag0 root@generic:~ # ifconfig -m dwc0 dwc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=8000b<RXCSUM,TXCSUM,VLAN_MTU,LINKSTATE> capabilities=8000b<RXCSUM,TXCSUM,VLAN_MTU,LINKSTATE> ether fa:97:92:f6:f1:09 inet 192.168.3.129 netmask 0xffffff00 broadcast 192.168.3.255 media: Ethernet 10baseT/UTP (10baseT/UTP <half-duplex>) status: active supported media: media autoselect instance 1 media 1000baseT mediaopt full-duplex,master instance 1 media 1000baseT mediaopt full-duplex instance 1 media 100baseTX mediaopt full-duplex instance 1 media 100baseTX instance 1 media 10baseT/UTP mediaopt full-duplex instance 1 media 10baseT/UTP instance 1 media none instance 1 media autoselect media 1000baseT mediaopt full-duplex,master media 1000baseT mediaopt full-duplex media 100baseTX mediaopt full-duplex media 100baseTX media 10baseT/UTP mediaopt full-duplex media 10baseT/UTP media none nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> root@generic:~ # netstat -nI dwc0 Name Mtu Network Address Ipkts Ierrs Idrop Opkts Oerrs Coll dwc0 1500 <Link#1> fa:97:92:f6:f1:09 134 0 0 132 0 0 dwc0 - 192.168.3.0/2 192.168.3.129 56 - - 7 - - root@generic:~ # ping -c 1 192.168.3.2 PING 192.168.3.2 (192.168.3.2): 56 data bytes --- 192.168.3.2 ping statistics --- 1 packets transmitted, 0 packets received, 100.0% packet loss root@generic:~ # netstat -nI dwc0 Name Mtu Network Address Ipkts Ierrs Idrop Opkts Oerrs Coll dwc0 1500 <Link#1> fa:97:92:f6:f1:09 134 0 0 132 0 0 dwc0 - 192.168.3.0/2 192.168.3.129 56 - - 8 - - 7. Check the media status of the host interface. The media set up between the device with auto-negotiation enabled and the device with the forced mode is correct and completed. $ sudo ethtool enp0s31f6 Settings for enp0s31f6: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Supported pause frame use: No Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Advertised pause frame use: No Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: 10Mb/s Duplex: Half Port: Twisted Pair PHYAD: 1 Transceiver: internal Auto-negotiation: on MDI-X: on (auto) Supports Wake-on: pumbg Wake-on: d Current message level: 0x00000007 (7) drv probe link Link detected: yes 8. Change the dwc interface from forced to auto-select mode. "PING" is successful. root@generic:~ # ifconfig -m dwc0 media autoselect root@generic:~ # ifconfig -m dwc0 dwc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=8000b<RXCSUM,TXCSUM,VLAN_MTU,LINKSTATE> capabilities=8000b<RXCSUM,TXCSUM,VLAN_MTU,LINKSTATE> ether fa:97:92:f6:f1:09 inet 192.168.3.129 netmask 0xffffff00 broadcast 192.168.3.255 media: Ethernet autoselect (1000baseT <full-duplex,master>) status: active supported media: media autoselect instance 1 media 1000baseT mediaopt full-duplex,master instance 1 media 1000baseT mediaopt full-duplex instance 1 media 100baseTX mediaopt full-duplex instance 1 media 100baseTX instance 1 media 10baseT/UTP mediaopt full-duplex instance 1 media 10baseT/UTP instance 1 media none instance 1 media autoselect media 1000baseT mediaopt full-duplex,master media 1000baseT mediaopt full-duplex media 100baseTX mediaopt full-duplex media 100baseTX media 10baseT/UTP mediaopt full-duplex media 10baseT/UTP media none nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> root@generic:~ # ping -c 1 192.168.3.2 PING 192.168.3.2 (192.168.3.2): 56 data bytes 64 bytes from 192.168.3.2: icmp_seq=0 ttl=64 time=0.302 ms --- 192.168.3.2 ping statistics --- 1 packets transmitted, 1 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.302/0.302/0.302/0.000 ms 9. Check the media status of the host interface, "enp0s31f6". The auto-negotiation process is correct and completed. $ sudo ethtool enp0s31f6 Settings for enp0s31f6: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Supported pause frame use: No Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Advertised pause frame use: No Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: 1000Mb/s Duplex: Full Port: Twisted Pair PHYAD: 1 Transceiver: internal Auto-negotiation: on MDI-X: off (auto) Supports Wake-on: pumbg Wake-on: d Current message level: 0x00000007 (7) drv probe link Link detected: yes Analysis I tried to step through the code about setting the media type into a forced mode and attach a patch for a quick fix to the problem in my personal development environment. My development environment is based on FreeBSD 13.0-RELEASE-p11. And I do not have a development environment based on the current release of Freebsd image. When setting the interface into a forced mode, the "mii_media_status" will be set to "DOWN" firstly and the "mii_media_active" will be set as the corresponding forced mode. The mii_physubr.c/mii_phy_update() function will invoke the if_dwc.c/dwc_miibus_statchg() function to set up the "link_is_up" field in "dwc_softc" struct as the "mii_media_status". If the "link_is_up" is not set as "UP", the interface is not able to send any packets. However, the dwc_miibus_statchg() will only be invoked when the "mii_media_active" is changed or mii.c/mii_mediachg() function is invoked. The change of "mii_media_status" will invoke the if.c/if_link_state_change() function to change the state in the dwc's "ifnet" struct. The "mii_media_status" has to wait for a while to let the PHY hardware setting be completed. Then, the "mii_media_status" will be set as "UP" in the dwc interface's callout function, dwc_tick() when the hardware setting is completed. But the "mii_media_active" is not changed and the if_dwc.c/dwc_miibus_statchg() function won't be invoked anymore. The "dwc_softc" struct's "link_is_up" field is still "down". Therefore, the packets sending is failed. -- You are receiving this mail because: You are the assignee for the bug.