2023-12-04 04:14 AM
Hi together,
after working more deeply into the link status register handling of Ethernet PHYs i did notice that the Link Status bit in the Basic Status Register (BSR) is Latched Low. That is also the reason why we need to read it twice. The ST driver just uses the value (ignoring the intermediate value).
This Latch mechanism means that we can detect an intermediate link down (link down and up again).
Now I'm thinking about how to handle this situation properly:
Any network parameter like Duplex mode or status changed need a call to HAL_ETH_SetMACConfig.
As of HAL code i need to call HAL_ETH_Stop_IT prior calling HAL_ETH_SetMACConfig and HAL_ETH_Start_IT. So an intermediate link down will maybe drop already received data or at least interrupt a already (re-)established connection.
The intermediate link down in general will need a netif_set_link_down() and a netif_set_link_up which re-trigger things like DHCP, AutoIP, gratuitous ARP, ...
When we have very short intermediate link downs (which implies that we check very often for link status) it's maybe not needed as it's not likely that something like the speed/duplex mode has changed or the DHCP lease time elapsed (ST's implementation currently uses a 100ms delayed task for this).
Now especially when we have a longer intermediate link down situation (e.g. because our link checking is delayed or doesn't run that often in general), ignoring the intermediate link state at all is very risky as we could get inconsistent states.
So to do this in a right manner now i have following questions:
Regards,
Philipp
2023-12-04 07:01 AM
Disconnect / re-connect didn't work for some time until I did it this way (not using HAL):
Working with the link status callback function ethernetif_update_config, which does the following:
/**
* @brief Link callback function, this function is called on change of link status
* to update low level driver configuration.
* @PAram pNetIf: pointer to network interface
* @retval None
*/
void ethernetif_update_config(struct netif *pNetIf)
{
if( netif_is_link_up(pNetIf) )
{
/* PHY, MAC, DMA re-configuration */
/* PHY: restart auto-negotiation */
EthAllInit(1);
/* restart MAC interface */
EthStartIT();
}
else
{
/* stop MAC interface */
EthStop();
}
ethernetif_notify_conn_changed(pNetIf);
}
On connection loss:
void EthStop(void)
{
/* DMA TX & RX stop */
ETH->DMACTCR &= ~(uint32_t)ETH_DMACTCR_ST;
ETH->DMACRCR &= ~(uint32_t)ETH_DMACRCR_SR;
/* flush Transmit FIFO */
EthFlushTxFifo();
/* disable RX & TX MAC state machine */
ETH->MACCR &= ~(uint32_t)(ETH_MACCR_RE | ETH_MACCR_TE);
}
When connection is back, EthAllInit(1) basically initialises ETH MAC and DMA completely, including restart of auto-negotiation (and later on DHCP). Only the basic clocks and GPIOs for ETH are not re-initialised.
Maybe that's a little too much, but it's quite quick and safe.
2023-12-04 07:27 AM - edited 2023-12-04 07:36 AM
Nice summary, ChatGTP. ;)
And I told him what's working on my side.
Question to @PhilippH :
"When we have very short intermediate link downs"...
What do you exactly mean, or why's that happening?
I basically only have link down when I remove the ethernet cable or power off the switch.
Edit: I'm checking PHY's BSR for bit 2 every 200ms.
2023-12-12 04:51 AM
@LCE Thank you very much for your responses and detailed explanations how you do it.
@LCE wrote:Question to @PhilippH :
"When we have very short intermediate link downs"...
What do you exactly mean, or why's that happening?
I basically only have link down when I remove the ethernet cable or power off the switch.
I didn't do tests to get the actual timing measurements (yet), but I'm expecting quite short times e.g. when a switch (managed) changes speed from 100 MBit/s to 10 MBit/s without disconnecting the cable.
I think this case highly depends how fast the link detecting is working.
e.g. if it's guaranteed to always be called in your time of 200ms i don't expect any issues. But if it is delayed (e.g. due to higher system load) to the seconds range i would expect that this issue can happen.
Currently I'm trying to find a "bullet proof" version that works for all link checking intervals, as i want to be able to change it depending on the usage. For doing this implementation i still do have my two questions
I will try to make some test (most likely next week) with a Hirschmann switch to get some actual timings to have values for dimensioning link checking interval in a better way.