Re: [lwip-users] TCP Retransmission when receiving consecutive packets
Hi Jens, hi Sergio, Yes that's exactly my problem. Here's the patch I've came up with on my driver : int packetCount = 0; static void eth_notify (ARM_ETH_MAC_EVENT event) { /* Send notification on RX event */ if (event == ARM_ETH_MAC_EVENT_RX_FRAME) { packetCount++; } } void ethernetif_poll (struct netif *netif) { struct ethernetif *eth = netif-state; if (!eth-phy_ok || eth-link == ARM_ETH_LINK_DOWN) { return; } while (packetCount) { ethernetif_input (netif); atomicDecrement(packetCount); } } It works perfectly ! Thanks a lot for your help ! Julien. 2014-03-20 19:46 GMT+01:00 Jens Nielsen d...@telia.com: Alright, I also use the ST drivers (the ones from STM32Cube 1.0.0) on an STM32F4 I haven't verified that my fix is 100% accurate but I think it looks safe so I'm sending it to ST anyway so they can figure it out if they want to. My fix goes something like this: At the bottom of HAL_ETH_GetReceivedFrame_IT() I return an error code if I don't find a complete packet: --- a/clients/embedded/source/STM32F4XX/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_eth.c +++ b/clients/embedded/source/STM32F4XX/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_eth.c @@ -868,7 +868,7 @@ HAL_StatusTypeDef HAL_ETH_GetReceivedFrame_IT(ETH_HandleTypeDef *heth) __HAL_UNLOCK(heth); /* Return function status */ - return HAL_OK; + return HAL_ERROR; } /** And then return NULL from low_level_input() in my ethernetif: --- a/clients/embedded/source/lwip-1.4.1/port/STM32F4x7/FreeRTOS/ethernetif.c +++ b/clients/embedded/source/lwip-1.4.1/port/STM32F4x7/FreeRTOS/ethernetif.c @@ -225,7 +224,10 @@ static struct pbuf * low_level_input(struct netif *netif) uint32_t i=0; /* get received frame */ - HAL_ETH_GetReceivedFrame_IT(EthHandle); + if ( HAL_ETH_GetReceivedFrame_IT(EthHandle) != HAL_OK ) + { + return NULL; + } /* Obtain the size of the packet and put it into the len variable. */ len = EthHandle.RxFrameInfos.length; And in my receive task I have this loop (ok yeah this could be prettier...) +do +{ +p = low_level_input(netif); +if (p != NULL) +{ +if (netif-input(p, netif) != ERR_OK) +{ +pbuf_free(p); +} +} +} while (p != NULL); Hope it helps! BR /Jens On 2014-03-20 19:13, Sergio R. Caprile wrote: Yes Jens, looks like you are absolutely right, missed that, there is no frame loss here, the receiving process must be getting only the first frame in the chip cue. Julien is using some ST microcontroller, I guess it has a built-in eth controller, probably with DMA. I've studied the Linux drivers for the DM9000 to write my driver, and I've seen they read all the packets out of the chip every time; then I setup a simple test to see if interrupts would trigger on every frame or only on empty buffer, and guess what... empty buffer only (there is no int ack here) Looks like we've got a different situation here, the chip seems to be issuing an interrupt after the first one is ACKed, as you Jens described for your case. Julien, can you confirm this from the chip docs ? Pitty one has to fix the drivers for a manufacturer, maybe someone in ST can lend a hand ? ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users
Re: [lwip-users] TCP Retransmission when receiving consecutive packets
Hi Julien. Yes, there is a TCP retransmission from your host. I bet that is because when the two packets come in such a close proximity your Ethernet driver is losing the second one. This, in fact, can be because there is a problem with the driver itself, or you have a really low-memory condition and the driver can't find enough memory to store the packet. If I would have to hunt this witch, I would start by setting a breakpoint on the Ethernet driver low_level_input() routine, somewhere around here: static struct pbuf * low_level_input(struct netif *netif) { [...] /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { [...] read data into(q-payload, q-len); } acknowledge that packet has been read(); [...] } else { drop packet(); - It actually depends on how the one who actually wrote the driver wanted to make it difficult for you. Let me know how it goes. Cheers -- ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users
Re: [lwip-users] TCP Retransmission when receiving consecutive packets
Hi Sergio, I've found this drop packet thing in my driver, however it doesn't seem to break there. I've had a look at the driver code but I can't find anything... I am a bit surprised that the ethernet interrupt just raises a flag : static void eth_notify (ARM_ETH_MAC_EVENT event) { /* Send notification on RX event */ if (event == ARM_ETH_MAC_EVENT_RX_FRAME) { rx_event = true; } } It seems to imply that calling ethernetif_poll in an IDLE thread will only process on packet even if multiple interrupts have been raised : void ethernetif_poll (struct netif *netif) { struct ethernetif *eth = netif-state; if (!eth-phy_ok || eth-link == ARM_ETH_LINK_DOWN) { return; } if (rx_event) { rx_event = false; /* process received ethernet packet */ ethernetif_input (netif); } } I think that an atomic counter and a while loop instead of a flag and a if would be more appropriate. Am I wrong ? Could that have anything to do with my problem ? Thanks for your help, Julien. 2014-03-20 15:10 GMT+01:00 Sergio R. Caprile scapr...@gmail.com: Hi Julien. Yes, there is a TCP retransmission from your host. I bet that is because when the two packets come in such a close proximity your Ethernet driver is losing the second one. This, in fact, can be because there is a problem with the driver itself, or you have a really low-memory condition and the driver can't find enough memory to store the packet. If I would have to hunt this witch, I would start by setting a breakpoint on the Ethernet driver low_level_input() routine, somewhere around here: static struct pbuf * low_level_input(struct netif *netif) { [...] /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { [...] read data into(q-payload, q-len); } acknowledge that packet has been read(); [...] } else { drop packet(); - It actually depends on how the one who actually wrote the driver wanted to make it difficult for you. Let me know how it goes. Cheers -- ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users
Re: [lwip-users] TCP Retransmission when receiving consecutive packets
I am a bit surprised that the ethernet interrupt just raises a flag : Don't be surprised, lwIP is single threaded, meaning you shouldn't call an lwIP memory allocation routine from inside an interrupt, since it might have interrupted another lwIP memory allocation routine... (I might be wrong since I didn't write the code, but that is what I understand by single-threaded and what I did on my driver) As you are using an RTOS, it surely dispatches a task to get the frame(s) later. The frames should happily rest inside the eth chip (or equivalent) until them, providing there is enough memory for them. The chip I use has 13K devoted to that. It seems to imply that calling ethernetif_poll in an IDLE thread will only process on packet even if multiple interrupts have been raised : Many eth chips issue only one interrupt for the first frame, the driver then checks for how many outstanding frames there are. check here -- ethernetif_input (netif); it should have some form of a do while loop Could that have anything to do with my problem ? IMHO, yes, quite probably, if that function does not perform a loop to get all the outstanding frames. Sorry but you'll have to learn your chip to check how it issues interrupts and buffers frames, and then check the driver. One quick try: send ping floods and see if you get the same behaviour. Pings are answered at the very first part of the IP processing, so if pings are OK, the issue is not probably inside the driver (do check inter-ping time with wireshark) Regards ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users
Re: [lwip-users] TCP Retransmission when receiving consecutive packets
Hi Yes you're probably right, that would be a better solution. What looks like happens next in the wireshark capture is that the interrupt triggered by the retransmission signals your code to read and ack the queued old packet. Then there's an ACK in packet 26 triggering another interrupt that signals your application to read the queued retransmission packet, hence the dup ack in packet 27. And so on, your application is constantly one packet behind the interrupt. One comment though: I don't know which MCU you're on but I wouldn't assume one interrupt equals one packet. I recently fixed a bug in my application that had a similar setup (interrupt signals with counting semaphore to receive thread, which processed a number of packets equal to the counting semaphore) which didn't cover the case where a second packet is received before the ethernet interrupt has serviced the first packet. My interrupt would only hit once so the second packet was left until the next interrupt. My solution was to simply try to fetch packets from DMA until it was empty each time my receive thread was woken. BR /Jens On 2014-03-20 16:21, Julien Jemine wrote: Hi Sergio, I've found this drop packet thing in my driver, however it doesn't seem to break there. I've had a look at the driver code but I can't find anything... I am a bit surprised that the ethernet interrupt just raises a flag : static void eth_notify (ARM_ETH_MAC_EVENT event) { /* Send notification on RX event */ if (event == ARM_ETH_MAC_EVENT_RX_FRAME) { rx_event = true; } } It seems to imply that calling ethernetif_poll in an IDLE thread will only process on packet even if multiple interrupts have been raised : void ethernetif_poll (struct netif *netif) { struct ethernetif *eth = netif-state; if (!eth-phy_ok || eth-link == ARM_ETH_LINK_DOWN) { return; } if (rx_event) { rx_event = false; /* process received ethernet packet */ ethernetif_input (netif); } } I think that an atomic counter and a while loop instead of a flag and a if would be more appropriate. Am I wrong ? Could that have anything to do with my problem ? Thanks for your help, Julien. 2014-03-20 15:10 GMT+01:00 Sergio R. Caprile scapr...@gmail.com mailto:scapr...@gmail.com: Hi Julien. Yes, there is a TCP retransmission from your host. I bet that is because when the two packets come in such a close proximity your Ethernet driver is losing the second one. This, in fact, can be because there is a problem with the driver itself, or you have a really low-memory condition and the driver can't find enough memory to store the packet. If I would have to hunt this witch, I would start by setting a breakpoint on the Ethernet driver low_level_input() routine, somewhere around here: static struct pbuf * low_level_input(struct netif *netif) { [...] /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { [...] read data into(q-payload, q-len); } acknowledge that packet has been read(); [...] } else { drop packet(); - It actually depends on how the one who actually wrote the driver wanted to make it difficult for you. Let me know how it goes. Cheers -- ___ lwip-users mailing list lwip-users@nongnu.org mailto:lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users
Re: [lwip-users] TCP Retransmission when receiving consecutive packets
Yes Jens, looks like you are absolutely right, missed that, there is no frame loss here, the receiving process must be getting only the first frame in the chip cue. Julien is using some ST microcontroller, I guess it has a built-in eth controller, probably with DMA. I've studied the Linux drivers for the DM9000 to write my driver, and I've seen they read all the packets out of the chip every time; then I setup a simple test to see if interrupts would trigger on every frame or only on empty buffer, and guess what... empty buffer only (there is no int ack here) Looks like we've got a different situation here, the chip seems to be issuing an interrupt after the first one is ACKed, as you Jens described for your case. Julien, can you confirm this from the chip docs ? Pitty one has to fix the drivers for a manufacturer, maybe someone in ST can lend a hand ? -- ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users
Re: [lwip-users] TCP Retransmission when receiving consecutive packets
Alright, I also use the ST drivers (the ones from STM32Cube 1.0.0) on an STM32F4 I haven't verified that my fix is 100% accurate but I think it looks safe so I'm sending it to ST anyway so they can figure it out if they want to. My fix goes something like this: At the bottom of HAL_ETH_GetReceivedFrame_IT() I return an error code if I don't find a complete packet: --- a/clients/embedded/source/STM32F4XX/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_eth.c +++ b/clients/embedded/source/STM32F4XX/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_eth.c @@ -868,7 +868,7 @@ HAL_StatusTypeDef HAL_ETH_GetReceivedFrame_IT(ETH_HandleTypeDef *heth) __HAL_UNLOCK(heth); /* Return function status */ - return HAL_OK; + return HAL_ERROR; } /** And then return NULL from low_level_input() in my ethernetif: --- a/clients/embedded/source/lwip-1.4.1/port/STM32F4x7/FreeRTOS/ethernetif.c +++ b/clients/embedded/source/lwip-1.4.1/port/STM32F4x7/FreeRTOS/ethernetif.c @@ -225,7 +224,10 @@ static struct pbuf * low_level_input(struct netif *netif) uint32_t i=0; /* get received frame */ - HAL_ETH_GetReceivedFrame_IT(EthHandle); + if ( HAL_ETH_GetReceivedFrame_IT(EthHandle) != HAL_OK ) + { + return NULL; + } /* Obtain the size of the packet and put it into the len variable. */ len = EthHandle.RxFrameInfos.length; And in my receive task I have this loop (ok yeah this could be prettier...) +do +{ +p = low_level_input(netif); +if (p != NULL) +{ +if (netif-input(p, netif) != ERR_OK) +{ +pbuf_free(p); +} +} +} while (p != NULL); Hope it helps! BR /Jens On 2014-03-20 19:13, Sergio R. Caprile wrote: Yes Jens, looks like you are absolutely right, missed that, there is no frame loss here, the receiving process must be getting only the first frame in the chip cue. Julien is using some ST microcontroller, I guess it has a built-in eth controller, probably with DMA. I've studied the Linux drivers for the DM9000 to write my driver, and I've seen they read all the packets out of the chip every time; then I setup a simple test to see if interrupts would trigger on every frame or only on empty buffer, and guess what... empty buffer only (there is no int ack here) Looks like we've got a different situation here, the chip seems to be issuing an interrupt after the first one is ACKed, as you Jens described for your case. Julien, can you confirm this from the chip docs ? Pitty one has to fix the drivers for a manufacturer, maybe someone in ST can lend a hand ? ___ lwip-users mailing list lwip-users@nongnu.org https://lists.nongnu.org/mailman/listinfo/lwip-users