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

 
 
 
Reply to this topicStart new topic
> Важно ! 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
defunct
сообщение Dec 27 2007, 23:40
Сообщение #2


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(_dem @ Dec 27 2007, 21:47) *
нужен код примерно такой :

идеология неправильная imho. чем обрабатывать пакет в прерывании, надо бы просто потушить флаг в RSR и взвести семафор чтобы RX таск начал вынимать и обрабатывать пакеты.
Go to the top of the page
 
+Quote Post
timofey_99
сообщение Dec 28 2007, 01:15
Сообщение #3


Участник
*

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



Цитата(defunct @ Dec 28 2007, 02:40) *
идеология неправильная imho. чем обрабатывать пакет в прерывании, надо бы просто потушить флаг в RSR и взвести семафор чтобы RX таск начал вынимать и обрабатывать пакеты.


Всё верно, но нужен комплекс мер. И совершенно необходимо знать сколько новых пакетов появилось по прерыванию. Например, в стеке lwIP, точнее в реализации с SAM7X EMAC, мне видится, что авторы не учли, что флаг прерывания взводится когда ПДП положил один или более фреймов в буфер, вот это "более" - ключевое слово. Семафор с блокировкой на 100 мс, первый пакет вычитывается по сигналу из прерывания, а остальные уже каждые 100 мс, за это время легко возникает ситуация BUFFER NOT AVAILABLE и неоднократно... Счётчик пакетов нужен таки при работе с семафором, если не все пакеты вычитаны из буферов, не блокироваться на семафоре
Go to the top of the page
 
+Quote Post
_dem
сообщение Dec 28 2007, 06:43
Сообщение #4


Местный
***

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



Цитата
идеология неправильная imho. чем обрабатывать пакет в прерывании, надо бы просто потушить флаг в RSR и взвести семафор чтобы RX таск начал вынимать и обрабатывать пакеты.


идеология - в общем - да, неправильная. Но учитывая то, что у ARMа прерывания - приоритезируемые и прерывание EMAC имеет низкий приоритет, вполне допустимая.
Понятно, что неплохо бы переделать код, но если в готовом девайсе вдруг возникает такой вот баг - sad.gif увы, этим никто не будет заниматся.

ps Тем более, что проблема возникает при малом расстоянии между пакетами - менее 1 msec ( 50-100 usec по данным ethereal). Вполне возможно, что и "короткий" обработчик за это время не успеет выполнится.

Сообщение отредактировал _dem - Dec 28 2007, 07:02
Go to the top of the page
 
+Quote Post
defunct
сообщение Dec 28 2007, 10:50
Сообщение #5


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(_dem @ Dec 28 2007, 09:43) *
Понятно, что неплохо бы переделать код, но если в готовом девайсе вдруг возникает такой вот баг - sad.gif увы, этим никто не будет заниматся.

Это да.. риск переделки высок. sad.gif

Цитата
ps Тем более, что проблема возникает при малом расстоянии между пакетами - менее 1 msec ( 50-100 usec по данным ethereal). Вполне возможно, что и "короткий" обработчик за это время не успеет выполнится.

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


Цитата
И совершенно необходимо знать сколько новых пакетов появилось по прерыванию.
...
Семафор с блокировкой на 100 мс, первый пакет вычитывается по сигналу из прерывания, а остальные уже каждые 100 мс, за это время легко возникает ситуация BUFFER NOT AVAILABLE и неоднократно...

Количество пакетов можно узнать при вычитке.
Думаю, что ничто не мешает после вычитки одного пакета проверить статус следующего фрейм дескриптора и т.д. и прочитать все имеющиеся на тек. момент пакеты.
Go to the top of the page
 
+Quote Post
_dem
сообщение Dec 28 2007, 14:18
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 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
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 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
_dem
сообщение Dec 31 2007, 10:46
Сообщение #8


Местный
***

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



В моем случае проблема возникает не из-за

41.3.1.1 EMAC: Possible Event Loss when Reading EMAC_ISR

А из-за того, что во время обработки прерывания успевает придти второй пакет, а количество пакетов проверятся не при каждой итерации цикла обработки, а перед его запуском.

При выходе же из прерывания флаги сбрасываются.
Go to the top of the page
 
+Quote Post
aste
сообщение Mar 12 2009, 09:50
Сообщение #9





Группа: Новичок
Сообщений: 1
Регистрация: 8-10-05
Пользователь №: 9 398



Недавно столкнулся с алогичной проблемой подвивания сетевой подсистемы в uC/TCP-IP для at91sam7x256 (описание полностью соответствует тому которое привёл _dem в первом посте топика), предложенные здесь решения проблему не решили. Однако после некоторого анализа и отладки реальная проблема данной ситуации была обнаружена и исправлена.

Перед описание решения проблемы несколько комментариев:

2_dem: видимо у вас был какой-то частный случай что вам помог ваш фикс, в моём случае не было замечено практически никакого увеличения стабильности (кроме возможно увеличения на несколько тысяч удачно прошедших пакетов до первого замирания).

2defunct: насчёт идеологии, то как раз в uC реализации стека и пользуется описанная вами идеология -- в прерывании только читаются и обновляются статусные регистры и взводятся необходимые семафоры, а сама обработка пакетов производиться в отдельном таске.

2timofey_99: уж кто кто а разработчики uC/TCP-IP и NIС драйверов еррату читали и не раз, поэтому и решили вообще не использовать в обработчике прерывания от EMAC значения регистра EMAC_ISR, а сразу (как и рекомендуется в еррате) использовать значение конкретных статусных регистров.

Проблема как и было предположено находиться именно в NIC драйвере для at91sam7x256, patch для net_nic.c V1.92 (однако он справедлив и для предыдущих версий и видимо для нескольких следующих smile.gif )
CODE
Index: net_nic.c
===================================================================
--- net_nic.c (revision 114)
+++ net_nic.c (working copy)
@@ -1543,9 +1543,9 @@
}
}

+ CPU_CRITICAL_ENTER();
search_ptr->addr &= ~EMAC_RXBUF_SW_OWNED; /* Free the EOF desc. */

- CPU_CRITICAL_ENTER();
if (NIC_RxNRdyCtr > 0) { /* One fewer packet to process. */
NIC_RxNRdyCtr--;
}
@@ -1596,9 +1596,9 @@
}
}

+ CPU_CRITICAL_ENTER();
search_ptr->addr &= ~EMAC_RXBUF_SW_OWNED; /* Free the last descriptor. */

- CPU_CRITICAL_ENTER();
if (NIC_RxNRdyCtr > 0) { /* One fewer packet to process. */
NIC_RxNRdyCtr--;
}


Итак причина проблемы: потеря увеличения семафора приходящих пакетов (вызова метода NetOS_IF_RxTaskSignal) в прерывании от EMAC (а именно NetNIC_RxISR_Handler) из-за ошибки в подсчёте новых пришедших пакетов (выражение n_new = NIC_GetNRdy() - NIC_RxNRdyCtr). Ошибка происходила из-за разсинхронизации значения переменной NIC_RxNRdyCtr и реального состояния буферов приёма периферии EMAC. Это происходило когда мы снимали флаг SW на буфере (search_ptr->addr &= ~EMAC_RXBUF_SW_OWNED) и сразу после этого происходило прерывание по приходу нового пакета, при это мы ещё не декрементировали значение переменной NIC_RxNRdyCtr, в связи с чем в логика перывания решала что новых пакетов нет, и не инкрементировла значение семафора приходящих пакетов. ВУАЛЯ мы замираем до прихода любого нового пакета.
Go to the top of the page
 
+Quote Post
kons
сообщение Mar 12 2009, 14:32
Сообщение #10


Частый гость
**

Группа: Свой
Сообщений: 106
Регистрация: 28-09-05
Пользователь №: 9 035



Интересная тема. Я тут тоже на днях написал драйвер EMAC (еще не проверял). Вначале тоже думал над прерываниями, а потом обошелся без них - все сделал, вообще не дотрагиваясь до регистров EMAC после инициализации. Проверяю только состояния дескрипторов в памяти. Причем опрос может быть не слишком частым (при достойной длине буфера) - раз в 5-10 мс вполне нормально. Почитал и засомневался - может, так не пойдет? И еще вопрос: автонегоциацией кто-нибудь заморачивался? Если правильно понял, это надо время от времени опрашивать PHY и приводить скорость и дуплекс в EMAC в соответствие со считанными из PHY значениями?
Go to the top of the page
 
+Quote Post

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

 


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


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