Перейти к содержанию
    

Важно ! uC-TCPIP bug @ SAM7X port

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) {

 

Это позволяет отловить вышеописанную ситуацию и отреагировать на второй пакет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

нужен код примерно такой :

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Всё верно, но нужен комплекс мер. И совершенно необходимо знать сколько новых пакетов появилось по прерыванию. Например, в стеке lwIP, точнее в реализации с SAM7X EMAC, мне видится, что авторы не учли, что флаг прерывания взводится когда ПДП положил один или более фреймов в буфер, вот это "более" - ключевое слово. Семафор с блокировкой на 100 мс, первый пакет вычитывается по сигналу из прерывания, а остальные уже каждые 100 мс, за это время легко возникает ситуация BUFFER NOT AVAILABLE и неоднократно... Счётчик пакетов нужен таки при работе с семафором, если не все пакеты вычитаны из буферов, не блокироваться на семафоре

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Понятно, что неплохо бы переделать код, но если в готовом девайсе вдруг возникает такой вот баг - :( увы, этим никто не будет заниматся.

 

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

Изменено пользователем _dem

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Понятно, что неплохо бы переделать код, но если в готовом девайсе вдруг возникает такой вот баг - :( увы, этим никто не будет заниматся.

Это да.. риск переделки высок. :(

 

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

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

 

 

И совершенно необходимо знать сколько новых пакетов появилось по прерыванию.

...

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

Количество пакетов можно узнать при вычитке.

Думаю, что ничто не мешает после вычитки одного пакета проверить статус следующего фрейм дескриптора и т.д. и прочитать все имеющиеся на тек. момент пакеты.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Глубоко переделать драйвер - потерять совместивость со следующими версиями стека.

 

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

Пришёл к этому выводу, просматривая коды обработчиков 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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

41.3.1.1 EMAC: Possible Event Loss when Reading EMAC_ISR

 

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

 

При выходе же из прерывания флаги сбрасываются.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Недавно столкнулся с алогичной проблемой подвивания сетевой подсистемы в 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 (однако он справедлив и для предыдущих версий и видимо для нескольких следующих :) )

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, в связи с чем в логика перывания решала что новых пакетов нет, и не инкрементировла значение семафора приходящих пакетов. ВУАЛЯ мы замираем до прихода любого нового пакета.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...