Dimonira 0 20 августа, 2022 Опубликовано 20 августа, 2022 · Жалоба Доброго дня плисоводам. При разработке системы, указанной в сабже, возникли проблемы при запуске стандартного примера SSS (интерфейс с PHY - GMII). Некоторые подробности описывал тут, поэтому повторять не буду (отладка заработала). По началу не было ни приёма, ни передачи. Но, переделал схему (оказалось, расширенный режим MSGDMA вкдючать нельзя) системы и вроде начало как-то работать - приём вроде появился: ethernet-фреймы принимаются, смотрю в обработчике прерываний приёма, вижу mac-адреса реальных девайсов в домашней сети. А вот передача не идёт. Первый посылаемый пакет - дискавери от dhcp клиента, посылаемый dhc_request. В пошаговом режиме дохожу до выделения буфера с помощью udp_alloc, а оно завершается неудачей. В результате стек вырубает сетевой интерфейс и делает exit. Пытаюсь по шагам пройти до критического места, но не выходит. Функция udp_alloc вызывает pk_alloc, которая принимает требуемый размер буфера len=592 байта, но как только делается проверка размера, то len уже становится равным 1528. Подозреваю, что отладчик ловит вызов от приёмной ветки, там, как я понимаю, выделяется на приём пакета память исходя из размера MTU. После проверки размера вызывается getq, которая непосредственно пытается выделить память из каких-то свободных цепочек, но почему-то сразу нарывается на то, что свободных буферов уже нет, возвращает 0, ну а дальше я уже написал - в итоге exit. В чём может быть проблема? И вообще, какие настройки должны быть у MSGDMA? Может с ними что-то не так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Dimonira 0 20 августа, 2022 Опубликовано 20 августа, 2022 · Жалоба Во время танцев с бубном вокруг TSE и гуляниям по исходникам выяснилось что: 1. Под пакеты (как я понял, и принимаемые, и передаваемые, что странно - передача может заткнуть приём и наоборот, как в моём случае) выделяются буферы двух размеров: 128 байт под маленькие пакеты и 1536 байт под большие в количестве по 30 штук каждых. Дескрипторы буферов объединяются в связанные списки. Всё это делается в pktalloc.c: queue bigfreeq; /* big free buffers */ queue lilfreeq; /* small free buffers */ unsigned lilbufs = NUMLILBUFS; /* number of small bufs to init */ unsigned lilbufsiz = LILBUFSIZE; /* big enough for most non-full size packets */ unsigned bigbufs = NUMBIGBUFS; /* number of big bufs to init */ unsigned bigbufsiz = BIGBUFSIZE; /* big enough for max. ethernet packet */ #ifdef NPDEBUG PACKET pktlog[MAXPACKETS]; /* record where the packets are */ #endif Все эти константы задаются в ipport.h. В отладочном коде есть глобальный массив pktlog, где можно все буфера посмотреть в одном массиве. 2. Оказывается, что когда в корке TSE включена возможность loopback, в исходниках одновременно включается опция promiscuous (файл ins_tse_mac.c): /* enable MAC */ dat = ALTERA_TSEMAC_CMD_TX_ENA_MSK | ALTERA_TSEMAC_CMD_RX_ENA_MSK | mmac_cc_RX_ERR_DISCARD_mask | #if ENABLE_PHY_LOOPBACK ALTERA_TSEMAC_CMD_PROMIS_EN_MSK | // promiscuous mode ALTERA_TSEMAC_CMD_LOOPBACK_MSK | // promiscuous mode #endif ALTERA_TSEMAC_CMD_TX_ADDR_INS_MSK | ALTERA_TSEMAC_CMD_RX_ERR_DISC_MSK; /* automatically discard frames with CRC errors */ А это означает, что TSE будет принимать всё что оказывается на входе. У меня loopback был по недоразумению включен. 3. Исходя из 1 и 2 у меня получалось, что все буферы большого размера сразу расходовались на принимаемые пакеты, ибо плата включена в сеть, где куча компов, умных розеток (их MAC-адреса я и видел в принятых фреймах) и т.д. Тем более, что буферов всего по 30 шт. Тем более в пошаговом режиме отладчика! Когда я вставал на первой же точке останова, хоть и сразу в нужном месте, но уже список bigfreeq был наполовину израсходован. Надо отключать loopback! 4. Попутно заметил фичу выделения буферов в куче, если размер пакета превышает максимальный для списка bigfreeq (1536): PACKET pk_alloc(unsigned len) { PACKET p; if (len > bigbufsiz) /* caller wants oversize buffer? */ { #ifdef HEAPBUFS if ((p = pk_alloc_heapbuf (len)) == NULL) return NULL; #else return(NULL); #endif } else { if ((len > lilbufsiz) || (lilfreeq.q_len == 0)) /* must use a big buffer */ p = (PACKET)getq(&bigfreeq); else p = (PACKET)getq(&lilfreeq); if (!p) return NULL; } //... Но, как я понял, HEAPBUFS не определена (задаётся в ipport.h). Так что при больших размерах пакетов будет пшик. Дефайн HEAPBUFS убран условной компиляцией через определение NOT_USED (задаётся в редакторе BSP для "новых версий" Iniche стека). Там вообще много чего выкидывается интересного. И как можно вносить в ipport.h свои правки, если при перегенерации BSP всё пропадёт (как пропадают, например, мои добавки для PHY RTL8211E в файлы altera_avalon_tse.h/c, приходится их возвращать). Жаль не сделали "окна" для пользовательских правок как в студии для STM32. Пошёл убирать loopback. Продолжение следует... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Dimonira 0 21 августа, 2022 Опубликовано 21 августа, 2022 · Жалоба ...продолжение опупеи. Убрал loopback, но радости это не принесло - передачи так и нет, хотя интерфейс уже вырубаться перестал, ведь буферов хватает (если в отладке не вставать). Далее в дело вступил осциллограф и помог: оказалось, что на PHY подавался GTX_CLK (такт передачи) частотой 100 МГц вместо 125. Тут я и вспомнил, что когда понижал частоту ядра NIOS и SDRAM до 100 (было 125), то забыл, что эта же частота идёт на PHY (её же, кстати, ещё надо переключать 125/25/2.5 в зависимости от скорости). В итоге пришлось ещё один выход в PLL организовать для 125 МГц. Далее пересобрал проект fpga и начал шить его в epcq (без прицепленного приложения). Когда прошивка завершилась и я нажал кнопку сброса, антивирус бодро сообщил мне, что в локальной сети появился новый клиент и показал mac-адрес моего девайса! Я понял, всё поехало! Я удивился, что приложение пошло, хотя я его не прошивал. Но потом понял, что оно же осталось в epcq с прошлого раза, я же полное стирание флеша не делал, а адреса в нём не поменялись, так что старое приложение вступилось (странно только, что SystemID то изменился, должно ли было запускаться?). На пинги плата отзывается. В итоге SSS работает, проверил, запустив в WSL Ubuntu (чтобы в Windows telnet не добавлять) команду telnet 192.168.81.99 30 Где 30 - номер порта, который обязательно указывать. SSS показал меню команд, далее попробовал вводить команды, мигать светодиодами и выкл/вкл "шоу" показа случайных чисел на семисегментном индикаторе (шоу - вывод случайных значений с периодичностью 50мс). Шоу, кстати включено по умолчанию, что помогает понять успешный запуск приложения. Всё работает, ура. Подсистему TSE (что я приводил выше) доработал - выкинул лишний pipeline. В результате это избавило от красноты таймингов после компиляции. В плане таймингов помог сам PHY RTL8211E - у него была включена задержка 1.5-2 нс по передаче и приёму. Так что с этим вообще не заморачивался. Констрейны задавал так (если кому интересно): create_clock -name CLK -period 50MHz [get_ports {CLK}] create_clock -name RXCLK -period 125MHz [get_ports {GMII_RXCLK}] derive_pll_clocks derive_clock_uncertainty set_clock_groups -asynchronous -group {CLK} -group {RXCLK} set_input_delay -clock RXCLK -max 2 [get_ports {GMII_RXD[*] GMII_RXDV GMII_RXER}] set_input_delay -clock RXCLK -min 1.2 [get_ports {GMII_RXD[*] GMII_RXDV GMII_RXER}] set_false_path -from [get_ports KEY[*]] set_false_path -from [get_ports SW[*]] set_false_path -to [get_ports LED[*]] set_false_path -to [get_ports ELED[*]] set_false_path -to [get_ports SEG[*]] set_false_path -to [get_ports DIG[*]] Последние шесть строчек для игнора кнопок/светодиодов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться