реклама на сайте
подробности

 
 
> Важно ! uC-TCPIP bug @ SAM7X port, Некорректная обработка пакетов
_dem
сообщение Dec 27 2007, 18:47
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



uCOS/II v 2.85
ucTCPIP v 1.86
MCU - AT91SAM7X256 @ 43Mhz + RTL8201BL, порт ucTCPIP от micrium.com - свежий по состоянию на 27.12.2007

Долго отлавливал следующий баг в порте uTCP-IP на SAM7X -
в случае, если на плату приходит пара пакетов из Ethernet с малым расстоянием между ними (менее 1 мс), возможно "зависание" стека до получения следующего пакета из сети.

Картина выглядит так - приходит подряд два пакета, на каждый из которых плата должна ответить.
Плата отвечает на первый пакет, потом сетевая подсистема "зависает" (API работает, но обмена нет) до прихода еще одного пакета (неважно какого, например ARP).

Вместо
Код
---------- time ------------------------------->
[ request1 ][ request2 ] [ reply1][ reply2 ] --<time>------[ request3 ][ reply3 ]
имеем
Код
---------- time ------------------------------->
[ request1 ][ request2 ] [ reply1] ----<time>------[ any ethernet packet ][ reply2 ]


Если подряд принимаются три или более пакетов, проблема не возникает, т.к. прерывание по третьему пакету обрабатывает второй и третий.

Проблема связана с тем, что за время обработки пакета в прерывании успевает придти еще один пакет, повторно же обработка не запускается (прерывание срабатывает, но флаги EMAC_RSR корректно не установлены, т.к. были сброшены при выходе из прерывания на прошлом пакете) - код не в определяет причину прерывания.
Код
---------- time ------------------------------->
[ packet1 ][ packet 2]
[irq1]-----[irq2]-------
[-----irq1_processing:packet ready-----][----irq2_processing:reason unknown----]


Проблема решается следующим образом :
В файле net_nic.c вместо кода
Код
    n_new = NIC_GetNRdy() - NIC_RxNRdyCtr;                              /* Determine how many NEW packets have been received    */
    
    while (n_new > 0) {


нужен код примерно такой :
Код
    
while ((n_new = NIC_GetNRdy() - NIC_RxNRdyCtr) > 0) {


Это позволяет отловить вышеописанную ситуацию и отреагировать на второй пакет.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
_dem
сообщение Dec 28 2007, 14:18
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



Цитата
Время прихода пакета и скорость обработчика прерывания не важны, т.к. RX таск запустится с некоторым отставанием и может вынимать не один пакет, а столько сколько можно вытащить, т.е. не ссылаться на некую абстрактную величину количества принятых пакетов посчитанную "когда-то", а непосредственно проверять статусы дескрипторов в момент вычитки.


Это понятно smile.gif целиком и полностью согласен.

Просто в данном случае речь идет о готовой чужой реализации стека, который используется "как есть", и будет апдейтится с выходом новых версий. Глубоко переделать драйвер - потерять совместивость со следующими версиями стека.
Go to the top of the page
 
+Quote Post
timofey_99
сообщение Dec 29 2007, 04:36
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 28-10-06
Пользователь №: 21 741



Цитата(_dem @ Dec 28 2007, 17:18) *
Глубоко переделать драйвер - потерять совместивость со следующими версиями стека.


А не нужно глубоко, мне видится, что ваша проблема зарыта довольно мелко.
Пришёл к этому выводу, просматривая коды обработчиков EMAC прерывания uC-TCPIP и lwIP/FreeRTOS.

Эти фрагменты относительно приёма. Что внутри if, сейчас не так интересно
В первом примере статус прерывания просто вычитывается и далее не используется,
потом идёт разбор событий по значениям в специализированных регистрах. Авторы еррату не читали, а может этой проблемы не существует в некоторых чипах из ряда AT91SAM7X256, AT91SAM9260, AT91SAM9263, & AVR32, для коих этот драйвер написан

uC-TCPIP
Код
    isr_status      =  MACB_ISR;  
    rsr_status      = MACB_RSR;              
    if ((rsr_status & MACB_RSR_REC) == MACB_RSR_REC) {  
        NetNIC_RxISR_Handler();                        
        MACB_RSR    = MACB_RSR_REC;                        
    }


А это код из примера с FreeRTOS (стек lwIP). Здесь видно, что проверяются флаги и в общем
регистре, и в специализированном
Код
    /* Find the cause of the interrupt. */
    ulIntStatus = AT91C_BASE_EMAC->EMAC_ISR;
    ulEventStatus = AT91C_BASE_EMAC->EMAC_RSR;

    if( ( ulIntStatus & AT91C_EMAC_RCOMP ) || ( ulEventStatus & AT91C_EMAC_REC ) )
    {
        /* A frame has been received, signal the lwIP task so it can process
        the Rx descriptors. */
        xSwitchRequired = xSemaphoreGiveFromISR( xSemaphore, pdFALSE );
        AT91C_BASE_EMAC->EMAC_RSR = AT91C_EMAC_REC;
    }


Во втором случае, описанная вами проблема, не возникает, а код хорошо согласуется с fix/workaround
from errata

41.3.1.1 EMAC: Possible Event Loss when Reading EMAC_ISR

If an event occurs within the same clock cycle in which the EMAC_ISR is read, the corresponding
bit might be cleared even though it has not been read at 1. This might lead to the loss of this
event.

Problem Fix/Workaround

Each time the software reads EMAC_ISR, it has to check the contents of the Transmit Status
Register (EMAC_TSR), the Receive Status Register (EMAC_RSR) and the Network Status
Register (EMAC_NSR), as the possible lost event is still notified in one of these registers.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 13:42
Рейтинг@Mail.ru


Страница сгенерированна за 0.01409 секунд с 7
ELECTRONIX ©2004-2016