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

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

не должно такого быть, один дескриптор - один пакет. read until EOP=0 говорит о том, что читать, пока EOP не встретится (длина пакета ведь заранее неизвестна). ненулевое значение в этом поле означает сколько байт читать. надо ловить первое прерывание и разбираться, как дескриптор передали SGDMA, не обработав первый пакет.

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


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

не должно такого быть, один дескриптор - один пакет. read until EOP=0 говорит о том, что читать, пока EOP не встретится (длина пакета ведь заранее неизвестна). ненулевое значение в этом поле означает сколько байт читать. надо ловить первое прерывание и разбираться, как дескриптор передали SGDMA, не обработав первый пакет.

 

понятно.

 

тогда есть такой вопрос

при вот таком описании

alt_sgdma_descriptor *desc = (alt_sgdma_descriptor *) ONCHIP_MEMORY2_1_BASE;
alt_sgdma_descriptor *currdescriptor_ptr;

идет обращение

currdescriptor_ptr =  &desc[ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST];

тут не косяк??? мне что-то подсказывае что должно быть так

currdescriptor_ptr =  desc+ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST;

я прав?

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


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

тут не косяк??? мне что-то подсказывае что должно быть так

currdescriptor_ptr =  desc+ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST;

я прав?

нет, тогда уж

currdescriptor_ptr =  desc+sizeof(alt_sgdma_descriptor)*ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST;

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

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


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

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

 

пока не очень просек как это нужно сделать...

но количество заходов в прерывание правильное... отправил 2 пакета, 2 раза и зашел... но принял одинаковый пакет (последний)

 

реально получается что при первом заходе в прерывание в currdescriptor_ptr уже есть первый пакет и вызов функции TseMacReceive(); его затирает...

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

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


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

Переместил функцию TseMacReceive(); из начала обработки прерывания в конец => просерать пакеты перестало, но выяснился новый баг - последний пакет принимается дважды

 

void TseMacSgDmaReadInit()
{
    alt_u32 *uncached_packet_payload;
    uncached_packet_payload = (void *)alt_remap_cached ((volatile void*) rx_pkt, 4);
    
    currdescriptor_ptr =  &desc[ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST];
    nextdescriptor_ptr = (alt_sgdma_descriptor *) IORD_ALTERA_TSE_SGDMA_DESC_NEXT(currdescriptor_ptr);
    blockdescriptor_ptr = currdescriptor_ptr;
    alt_avalon_sgdma_construct_stream_to_mem_desc(
            (alt_sgdma_descriptor *) &desc[ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST],  // descriptor I want to work with
            (alt_sgdma_descriptor *) &desc[ALTERA_TSE_SECOND_RX_SGDMA_DESC_OFST],  // pointer to "next"
            uncached_packet_payload,            // pkt_array[chain_loop]->nb_buff,                     // starting write_address
            0,                                  // read until EOP
            0);
   
    currdescriptor_ptr =  &desc[ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST];
    nextdescriptor_ptr = (alt_sgdma_descriptor *) IORD_ALTERA_TSE_SGDMA_DESC_NEXT(currdescriptor_ptr);
    
    int desc_status = 1;
    desc_status = alt_avalon_sgdma_check_descriptor_status(currdescriptor_ptr);
    desc_status = alt_avalon_sgdma_check_descriptor_status(nextdescriptor_ptr);  
    desc_pointer = currdescriptor_ptr;
    
    TseMacRxRead(currdescriptor_ptr);
    
    alt_u32 sgdma_control_rx = 0;
    sgdma_control_rx = IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_1_BASE);
    alt_u32 sgdma_status_rx = 0;
    sgdma_status_rx = IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_1_BASE);
}

int TseMacReceive(){
    alt_u32 *uncached_packet_payload;
    alt_u8 tempVar;
    desc_pointer = currdescriptor_ptr;
    alt_u32 desc_stat=0;
    desc_stat = IORD_ALTERA_TSE_SGDMA_DESC_STATUS(desc_pointer);
    
    if ((desc_stat & ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) )
    {
        desc_pointer->status&=~ALTERA_AVALON_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK;
        nextdescriptor_ptr = (alt_sgdma_descriptor *)IORD_ALTERA_TSE_SGDMA_DESC_NEXT(desc_pointer);
    
        uncached_packet_payload = (void *)alt_remap_cached ((volatile void*) rx_pkt, 4);
       tempVar = IORD_8DIRECT(&nextdescriptor_ptr->control, 0 );
    
        alt_avalon_sgdma_construct_stream_to_mem_desc(
            (alt_sgdma_descriptor *) &desc[ALTERA_TSE_FIRST_RX_SGDMA_DESC_OFST],  // descriptor I want to work with
            (alt_sgdma_descriptor *) &desc[ALTERA_TSE_SECOND_RX_SGDMA_DESC_OFST],  // pointer to "next"
            uncached_packet_payload,            // starting write_address
            0,                                  // read until EOP
            0);                                 // don't write to constant address
        
        IOWR_8DIRECT(&nextdescriptor_ptr->control, 0, tempVar);
        
      //  desc_pointer = nextdescriptor_ptr;
            }
    return 1;
}

alt_u32  TseMacRxRead(alt_sgdma_descriptor *rxDesc)
{
    
    alt_u32 sgdma_status_rx = 0;
    sgdma_status_rx = IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_1_BASE);
    alt_u32 sgdma_control_rx = 0;
    sgdma_control_rx = IORD_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_1_BASE);
    
    alt_u8 result = 0;
    while ( (IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_1_BASE) & ALTERA_AVALON_SGDMA_STATUS_BUSY_MSK) ){
    }
    result = alt_avalon_sgdma_do_async_transfer(sgdma_rx_dev, (alt_sgdma_descriptor *) rxDesc /*&rxDesc[0]*/);
    

        
return 0;
}


int TseMacSgDmaRxIsr(void * context, alt_u32 id)
{
    alt_u32 rx_section = 0;
    rx_section = IORD_ALTERA_TSEMAC_RX_SECTION_EMPTY(sgdma_rx_dev);
    rx_section = IORD_ALTERA_TSEMAC_CMD_CONFIG(TRIPLE_SPEED_ETHERNET_0_BASE);
    
          //TseMacReceive();    
    IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_1_BASE, 0x00);
    IOWR_ALTERA_AVALON_SGDMA_CONTROL(SGDMA_1_BASE, ALTERA_TSE_SGDMA_INTR_MASK);

         
    if((IORD_ALTERA_AVALON_SGDMA_STATUS(SGDMA_1_BASE) & ALTERA_AVALON_SGDMA_STATUS_CHAIN_COMPLETED_MSK )){
       TseMacRxRead(currdescriptor_ptr/*desc*/);
    }    
     
    IOWR_ALTERA_AVALON_SGDMA_STATUS(SGDMA_1_BASE,0xFF);
     
       // тут у меня обработка принятого пакета  &rx_pkt[0]

     TseMacReceive();                
return 0;
}

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

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


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

это неправильно, порядок должен быть такой:

*проверка на ошибки при приеме

*обработка пакета (напр., помещение в очередь)

*вызов alt_remap_cached и alt_avalon_sgdma_construct_stream_to_mem_desc (подготовка дескрипторов к проведению очередной транзакции)

*вызов alt_avalon_sgdma_do_async_transfer (начало асинхронной транзакции)

 

это, что касается обработчика прерывания. в начале работы вызывается read_init, которая делает последние 2 действия. посмотрите код в оригинальном драйвере.

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


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

это неправильно, порядок должен быть такой:

*проверка на ошибки при приеме

*обработка пакета (напр., помещение в очередь)

*вызов alt_remap_cached и alt_avalon_sgdma_construct_stream_to_mem_desc (подготовка дескрипторов к проведению очередной транзакции)

*вызов alt_avalon_sgdma_do_async_transfer (начало асинхронной транзакции)

 

это, что касается обработчика прерывания. в начале работы вызывается read_init, которая делает последние 2 действия. посмотрите код в оригинальном драйвере.

 

Т.е. получается в процедуре read_init

функция alt_remap_cached задает формат работы с памятью (32 разрядные данные),

alt_avalon_sgdma_construct_stream_to_mem_desc указывает SGDMA через какую память и куда копировать,

alt_avalon_sgdma_do_async_transfer взводит SGDMA в ожидание приема.

 

когда прием закончился, то попадаем в наше прерывание где решаем что делать с принятым пакетом, после чего снова готовим дискриптор (alt_avalon_sgdma_construct_stream_to_mem_desc) и взводим SGDMA на ожидание приема следующего пакета (alt_avalon_sgdma_do_async_transfer).

 

по факту получается как-то так.

 

но есть косяк... если отправить фрвгментированный пакет (ping -l 9000 -n 1 192.168.0.5) следующую картину: пакеты приходят кучно принимаем 6 пакетов и после заходим еще раз в прерывание и принимаем повторно 6-ой пакет. на меньшем количестве тоже самое, последнее прерывание - двойное...

 

ладно, отправляем больше пакет (ping -l 20000 -n 1 192.168.0.5)

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

 

Если слать пинги не фрагментированные любой цикличности (ping -n 50 192.168.0.5) то они будут приниматься нормально без сбоев, но каждый дважды (т.к. он последний в "кучной" транзакции)...

 

где-то лажа... но пока не понятно, где именно...

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


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

ладно, отправляем больше пакет (ping -l 20000 -n 1 192.168.0.5)

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

 

Проблема 7-и пакетов решилась очень просто - исправлением ошибки в размере FIFO... он у меня был 2048*32 при необходимых 16384*32

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


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

что-то непонятно все это. насколько я понимаю, бороться с фрагментацией пакетов дело не драйвера, а IP. для любого драйвера можно подобрать условия, при которых он начнет терять пакеты, это нормальная ситуация, IP учитывает такую возможность. фокусы с "ping -l 20000" на мой взгляд можно рассматривать лишь в роли некоторого стресс-теста, а не как абсолютный показатель (кстати, попробуйте "ping -i 0" + длину побольше). бороться с потерей пакетов путем увеличения буферов, мне кажется, бесперспективно: любой буфер можно зафлудить и переполнить, если обработчик прерывания еле ворочается. так что если хотите расшить узкое место, то начинать надо с прерываний, это известная проблема ниоса. больше интересен факт размножения пакетов. как вы его фиксируете?

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


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

что-то непонятно все это. насколько я понимаю, бороться с фрагментацией пакетов дело не драйвера, а IP. для любого драйвера можно подобрать условия, при которых он начнет терять пакеты, это нормальная ситуация, IP учитывает такую возможность. фокусы с "ping -l 20000" на мой взгляд можно рассматривать лишь в роли некоторого стресс-теста, а не как абсолютный показатель (кстати, попробуйте "ping -i 0" + длину побольше). бороться с потерей пакетов путем увеличения буферов, мне кажется, бесперспективно: любой буфер можно зафлудить и переполнить, если обработчик прерывания еле ворочается. так что если хотите расшить узкое место, то начинать надо с прерываний, это известная проблема ниоса. больше интересен факт размножения пакетов. как вы его фиксируете?

 

Да согласен, обработка прерывания сделана не лучшим образом, медленно ворочается... но пока так... когда более менее отлажусь попробую выйти из положения задав частоту процу 100-150 МГц (сейчас 50)

 

интересный момент, мои BBlaster-ы не хотят заходить в дебаг если я строю ниос систему на частоте более 50.

пробовал как LPT blaster, так и USB... итог один не может остановить процессор по ресету... на 50 работают оба программатора нормально...

 

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

 

так же отмечу, что я вызываю функцию TseMacReceive(); в конце обработки прерывания, а не в начале как вы... таким образом, я не теряю первого пакета из пачки... я думаю тут тесная взаимосвязь. Вы принимали один пакет т.к. ловили всегда второй. попробуйте свой драйвер на прием фрагментированного пинга и вы пропустите пакет со смещением 0....

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


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

Доброе время суток)

с TSE начал работать недавно, очень помогла эта тема. Возникло пару вопросов:

1) массив данных находится в памяти(100-500кб), и его надо передат по udp с максимальной скорость, как с минимальной задержкой формировать udp сообщение, имеется ввиду алгоритм, типа сначала десккриптор на заголовок потом на данные и потом уже трансляция в сеть, я правильно мыслю?

2) Как максимально быстро считать контрольную сумму? пробовал через С2H, хороший выйгрыш только на длинных пакетах, также видел в примера встраивание этой функции в sgdma.

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


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

и его надо передат по udp с максимальной скорость

именно по UDP? на raw ethernet сокетах скорость выше, да и с заголовками возни меньше.

по 1) пакет надо передавать TSE целиком, переключать дескриптор с заголовка на данные не получится. напрашивается такой вариант: подготовить буфер, вбить туда заголовок, потом дать смещение и при помощи DMA скопировать данные из массива. после этого пакет можно отдавать в сеть. есть другой вариант: данные в массиве располагать не подряд, а фрагментами, чтобы в свободное место потом вписывать заголовки. тут скорость повыше будет.

по 2) максимально быстро сумма считается компонентом с DMA (не sgdma, а именно компонент с Avalon-MM мастером). по идее, туда же можно прикрутить логику для работы с заголовками

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


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

... при помощи DMA скопировать данные из массива в буфер.

 

А у вас случайно нет рабочего примерчика данной операции?

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


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

А у вас случайно нет рабочего примерчика данной операции?

а чем из примеров в Software Developer`s Handbok не устраивает?

#include <stdio.h>
#include <stdlib.h>
#include "sys/alt_dma.h"
#include "system.h"
static volatile int rx_done = 0;
/*
* Callback function that obtains notification that the data
* is received.
*/
static void done (void* handle, void* data)
{
    rx_done++;
}
/*
*
*/
int main (int argc, char* argv[], char* envp[])
{
    int rc;
    alt_dma_txchan txchan;
    alt_dma_rxchan rxchan;
    void* tx_data = (void*) 0x901000; /* pointer to data to send */
    void* rx_buffer = (void*) 0x902000; /* pointer to rx buffer */
    /* Create the transmit channel */
    if ((txchan = alt_dma_txchan_open("/dev/dma_0")) == NULL)
    {
        printf ("Failed to open transmit channel\n");
        exit (1);
    }
    /* Create the receive channel */
    if ((rxchan = alt_dma_rxchan_open("/dev/dma_0")) == NULL)
    {
        printf ("Failed to open receive channel\n");
        exit (1);
    }
    /* Post the transmit request */
    if ((rc = alt_dma_txchan_send (txchan,
        tx_data,
        128,
        NULL,
        NULL)) < 0)
    {
        printf ("Failed to post transmit request, reason = %i\n", rc);
        exit (1);
    }
...

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


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

а чем из примеров в Software Developer`s Handbok не устраивает?

 

Да, я тоже думал, что вот оно счастье... но...

к инициализации обоих каналов DMA притензий нет - всё чисто... а вот с приемом и передачей не получается

 

    int psize = 528; // размер передаваемого массива
    alt_u8 *rx_buf;
    alt_u8 *tx_buf;
   int rc;
    
    

tx_buf = packet+34;  // указатель на место откуда
rx_buf = 34+pkt_pointer+offset; // указатель куда

     if ((rc = alt_dma_txchan_send ( txchan,
                                    tx_buf,
                                    psize,
                                        NULL,
                                        NULL)) < 0)
        {
        printf ("Failed to post transmit request, reason = %i\n", rc);
        exit (1);
        }
       
    if ((rc = alt_dma_rxchan_prepare (  rxchan,
                                       rx_buf,
                                       psize, 
                                        done,
                                        NULL)) < 0)
        {
        printf ("Failed to post read request, reason = %i\n", rc); // вот тут вылетаем с кодом -22
        exit (1);
        }
        /* wait for transfer to complete */
        while (!rx_done);
                      #ifdef DEBUG_IP
                      printf ("DMA transfer successful!\n");
                      #endif

Вылетаем на приеме с rc = -22

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


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

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

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

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

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

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

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

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

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

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