Ethernet cannot work after resuming from suspending (S2RAM) - ethernet

I am working on EthernetAVB module. My board can be suspended by the command
echo mem > /sys/power/state
But when resuming from suspending, the eth0 doesn't work. The phenomenon are:
Able ping loopback: $ ping 127.0.0.1 --> Ok
Power of PHY is off (power down)
Unable ping to neighbors: $ ping 192.168.1.1 --> Failed
I assumed that the network layer (comply with OSI model) is ok, because I can ping loopback. I thought the problem happened in physical layers, related to:
PHY ic (my board using Micrel Phys ksz9031)
MDIO bus
And the last is phy_dev
Maybe the issue able to happen on Ethernet Controller (my case is Ethernet AVB)
I tried to disable "suspend" the PHY ic (power of ksz9031) - keep the PHY waken. After resuming, the power indicating led is ON, but still cannot ping the other neighbors.
By the way, I saw that my system (ethernet) cannot jump to RUNNING state after resuming.
The above is the way PM platform work.
And Block Diagram of EthernetAVB in my board.
I drew a part of PHY state machine for purpose of detecting the issue (not completely)
More details:
PHY state machine states:
DOWN: PHY device and driver are not ready for anything. probe() should be called if and only if the PHY is in this state, given that the PHY device exists.
- PHY driver probe function will, depending on the PHY, set the state to STARTING or READY
STARTING: PHY device is coming up, and the ethernet driver is not ready. PHY drivers may set this in the probe function. If they do, they are responsible for making sure the state is eventually set to indicate whether the PHY is UP or READY, depending on the state when the PHY is done starting up.
- PHY driver will set the state to READY
- start will set the state to PENDING
READY: PHY is ready to send and receive packets, but the controller is not. By default, PHYs which do not implement probe will be set to this state by phy_probe(). If the PHY driver knows the PHY is ready, and the PHY state is STARTING, then it sets this STATE.
- start will set the state to UP
PENDING: PHY device is coming up, but the ethernet driver is ready. phy_start will set this state if the PHY state is STARTING.
- PHY driver will set the state to UP when the PHY is ready
UP: The PHY and attached device are ready to do work. Interrupts should be started here.
- timer moves to AN
AN: The PHY is currently negotiating the link state. Link is therefore down for now. phy_timer will set this state when it detects the state is UP. config_aneg will set this state whenever called with phydev->autoneg set to AUTONEG_ENABLE.
- If autonegotiation finishes, but there's no link, it sets the state to NOLINK.
- If aneg finishes with link, it sets the state to RUNNING, and calls adjust_link
- If autonegotiation did not finish after an arbitrary amount of time, autonegotiation should be tried again if the PHY supports "magic" autonegotiation (back to AN)
- If it didn't finish, and no magic_aneg, move to FORCING.
NOLINK: PHY is up, but not currently plugged in.
- If the timer notes that the link comes back, we move to RUNNING
- config_aneg moves to AN
- phy_stop moves to HALTED
FORCING: PHY is being configured with forced settings
- if link is up, move to RUNNING
- If link is down, we drop to the next highest setting, and retry (FORCING) after a timeout
- phy_stop moves to HALTED
RUNNING: PHY is currently up, running, and possibly sending and/or receiving packets
- timer will set CHANGELINK if we're polling (this ensures the link state is polled every other cycle of this state machine, which makes it every other second)
- irq will set CHANGELINK
- config_aneg will set AN
- phy_stop moves to HALTED
CHANGELINK: PHY experienced a change in link state
- timer moves to RUNNING if link
- timer moves to NOLINK if the link is down
- phy_stop moves to HALTED
HALTED: PHY is up, but no polling or interrupts are done. Or PHY is in an error state.
- phy_start moves to RESUMING
RESUMING: PHY was halted, but now wants to run again.
- If we are forcing, or aneg is done, timer moves to RUNNING
- If aneg is not done, timer moves to AN
- phy_stop moves to HALTED
I raise some assumptions/hypothesis:
After suspended, the system goes to HALTED state, but cannot change to RUNNING state.
Because of a certain reason, the system goes to DOWN state, and cannot move to READY state and UP again.
Thanks for any help.

Keep below things at least during resuming from suspended state to resolve the issue.
o Enable AVB-DMAC Mode Register working with high-speed peripheral bus clock (the AVB-DMAC module currently uses gPTP clock to read/write data from Queues (Best effort and Network control).
o Restore descriptor base address table (DBAT register) in the URAM.
o Enable interrupts for Best Effort Queue và Network Control Queue
o Re-init DMAC và E-MAC devices
o Initialize PTP Clock driver to provide clock for DMAC
o Enable transmits for all queues to allow the upper layer to transmit frames but it does not restart transmission.
o Re-start PHY device
o Mark device as attached from system and restart if needed.

Related

Hardware interrupt when Power Button pressed?

When we first press the power-on button, on the laptop, does a hardware interrupt occur?
I have read at multiple places that:
"Once the system receives a "Power Good" signal from the power supply, the CPU will seek instructions from the BIOS about initializing the system"
But even before the BIOS instructions getting loaded into the CPU, we have the Bootstrap instructions loaded into the Program counter. So for the memory address to be loaded onto the program counter, there has to be a hardware interrupt at the very start?
When we first press the power-on button, on the laptop, does a hardware interrupt occur?
No.
The CPU has to do various things ("built in self-test", determine if it's the "boot CPU" or not, etc), then the firmware has to configure various things (interrupt controller, etc), then something (firmware) has to create a table of interrupt vectors. All of that has to happen before any interrupt is possible.
So for the memory address to be loaded onto the program counter, there has to be a hardware interrupt at the very start?
For the main "boot CPU"; after its power-on sequence (self test, etc) the CPU ends up in a well defined default state that was built into the CPU by the manufacturer; which includes a default/initial value for each register (including the instruction pointer). This also means that something (firmware) must exist at the address that was built into the CPU by its manufacturer.
For other CPUs ("application processors"); after their power-on sequence they just wait until software wakes them up somehow. For 80x86, waking an AP up is done by software sending a sequence of interrupts from another CPU; where (for modern 80x86 CPUs only - Pentium and newer) part of the address to put into the instruction pointer is included in the message sent to the CPU as part of a "startup interrupt" (SIPI); and the rest of the instruction pointer (and all other registers) is still "well defined default state that was built into the CPU by the manufacturer".

STM32H7 SPI frozen during break?

In order to freeze a timer during a break in debug mode on a STM32H7, one has to set a bit in the DBGMCU. But I didn't find such a bit for SPI. Does it mean that the SPI is always frozen ? Or on the contrary never frozen ?
Short answer:
There is no such option for the SPI. SPI is always enabled, if used and proper configured.
Long answer:
There is no such option for SPI because this interface must be either actively served by the microcontroller. In this case the SPI transaction is automaticly stoped if your device is halted e.g in break mode. Any ongoing transaction of a word/fifo will be executed anyway.
Or the dma controler is configured to server the SPI. In this case data transmission is controlled by the dma controller. The dma controller itself has different trigger sources. As long this trigger source is not a timer depended one there is no way to implicitly halt the transfer.
See also: https://stackoverflow.com/a/43225545/5388805

lwip stm32 - http requests failing

I running freeRTOS and lwip 1.4.1 with the socket api in use on an stm32 processor (stm32f407).
Overall it works pretty fine.
I can send and receive data with udp and tcp.
But in a timewindow of 3 to 7 days I see a strange behavior.
My Problem
Every 3 to 7 days my client (Windows 10, which sends 1-2 HTTP-Requests per second) fails to send those requests. When this happens, there are ~10 Requests successively, which are failing. In very few moments, the stack won't regenerate at all.
My Guess
I think I have possibly missconfigured something in my LWIP config.
Because the stack is well used and shouldn't have any bugs in this direction
My Ethernet settings
server and client are directly connected, no switch,hub or router in between.
server (stm32/lwip):
static, 192.168.168.2
netmask, 255.255.255.0
client (win10) eth0:
static, 192.168.168.1
netmask, 255.255.255.0
client (win10) eth1:
dhcp, to normal working network
My Tries
At the moment I have tests running which are sending ~7-8 Requests per second, but the error doesn't apply more often.
I played around with the lwip config:
more memory for the stack
more pbufs
bigger pbufs
with/without backlog
But everything without improving of this connection problem.
Could it be because of the often reused port numbers from the client, which could make this problem?
Here I have the relevant part of the lwip debuging output:
tcp debugging output
https://pastebin.com/a9JabhET
Here the Wireshark log:
orig screenshot
hole wireshark log:
https://www.file-upload.net/download-12682664/debug_tcp_00001_20170828172950.html
And here my lwipopts.h:
lwip configuration:
https://pastebin.com/cW0v4hF6
It seems a memory problem, but as it is temporary, it could be a timeout on something.
I suggest to use the memory stats functions of LwIP, and also to enable the ARP debug messages.
I have a new Job and am no longer working on this issue.
Befor I stated my new job I could show that it was not a memory Problem on LwIP (I defined unreasonable large pbufs and memorypools) they never reached their limits.
The problem was in the DMA driver for the ETH. When once reached the memory chain end of the DMA driver the chain elements never got freed, so I run into RBU (Receive Buffer Underrun) problems and the RBU Flag never got reseted again and the DMA ETH driver was hanging in this RBU interrupt (even if there where enough LwIP buffs to write to from DMA chain). So I added a sledgehammer fix to the DMA driver and disabled the RBU interrupt (I am polling the RBU flag in multiple situations and clear it if needed, and start to read again from ETH).
I think since then the problem is more or less "solved". Not nice, but it worked.
I've got some information of my coworker at my old working place:
The RBU Interrupt and the clear did not work, because our used CAN stack did not work very well with FreeRTOS, the CAN stack used on busy systems much over 90% of CPU time, which let to the strange behaviour in ETH driver and LWIP.

Do we have to enable or disable PCI interrupts on every layer, or only at the closest to hardware?

I'm implementing a PCIe driver, and I'd like to understand at what level the interrupts can be or should be enabled/disabled. I intentionally do not specify OS, as I'm assuming it should be relevant for any platform. By levels I mean the following:
OS specific interrupts handling framework
Interrupts can be disabled or enabled in the PCI/PCIe configuration space registers, e.g. COMMAND register
Interrupts also can be masked at device level, for instance we can
configure device not trigger certain interrupts to the host
I understand that whatever interrupt type is being used on PCIe (INTx emulation, MSI or MSI-X), it has to be delivered to the host OS.
So my question is really -- do we actually have to enable or disable interrupts on every layer, or it's sufficient only at the closest to hardware, e.g. in relevant PCI registers?
Disabling interrupts at the various levels usually has completely different purposes.
Disabling interrupts:
In the OS (really, this means in the CPU) - This is generally about avoiding race conditions. In particular, if state/memory corruption could occur during a particular section of code if the CPU happened to be interrupted, then that section of code will need to disable interrupt handling. Interrupt handlers must not acquire normal locks (by definition they can't be suspended), and they must not attempt to acquire a spin-lock that is held by the thread currently scheduled on the same CPU (because that thread is blocked from progressing by the very same interrupt handler!) so ensuring data safety with interrupt handlers can be tricky. Handling interrupts promptly is generally a good thing, so you want to absolutely minimise such sections in any code you write. Do as much of your interrupt handling in secondary interrupt handlers as possible to avoid such situations. Secondary interrupt handlers are really just callbacks on a regular OS thread which doesn't have any of the restrictions of a primary interrupt handler.
PCI/PCIe configuration - It's my understanding this is mainly about routing interrupts, and is something you normally do once when your driver loads (or is activated by a client) and again when your driver unloads (or is deactivated). This may also be affected by power management events. In some OSes, the PCI(e) level is actually handled for you when you activate PCI device interrupts via higher-level APIs.
On-device - This is usually an optimisation to avoid interrupting the CPU when it doesn't need to be interrupted. The most common scenario is that an event happens on the device, so an interrupt is generated. The driver's primary interrupt handler checks the device registers if the driver needs to do any processing. If so, it disables interrupts on the device, and schedules the driver's secondary interrupt handler to run. The OS eventually runs the secondary handler, which processes whatever information the device has provided, until it runs out of things to do. Then it enables interrupts again, checks once more if there's any work pending from the device and if there are none, it terminates. (If there are items to process in this last check, it re-disables interrupts and starts over from the beginning.) The idea is that until the secondary interrupt handler has finished processing, there really is no point triggering the primary interrupt handler, and a waste of resources, if additional events arrive, because the driver is already busy processing the event queue. The final check after re-enabling interrupts is to avoid a race condition between an event arriving and re-enabling interrupts.
I hope that answers your question.

Reseting a PHY from U-boot

I am building a custom board that is based off of an existing evaluation module for a processor. On the evaluation module there is a MCU that handles most of the boot time configuration. Along with this, the MCU forces a reset on the PHY chips so that the PHY chips can begin communication. On my custom board there will not be an MCU to perform the reset and this the processor must perform the reset.
How would I go about performing the reset from u-boot?
My processor is connected to an SPI -> GPIO expander and this must reset the Phy through the use of SPI. I will not be performing an NFS boot so I do not need the Phys to be accessable from u-boot, but they do need to be reset before the Linux Kernel is booted in order for the kernel drivers to set it up correctly. Any ideas?
As per MII standards, your PHY chip will have basic mode control register at address 0x00. Look in PHY chip datasheet under 'PHY MDIO register Description'.
In U-Boot either phy-chip driver ( example marvell, vitesse etc.) if found, otherwise generic phy-driver will perform the phy reset.