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

 
 
> DMA. Потери данных внутри пакета, Проблемы с инициализацией транзакции?
Nedd
сообщение Aug 10 2015, 11:31
Сообщение #1





Группа: Участник
Сообщений: 9
Регистрация: 5-08-15
Пользователь №: 87 854



Здравствуйте, прочитал на хабре статью про DMA контроллер, было решено повторить.
До момента написания драйвера все работает должным образом. Драйвер скомпилировать не удалось, поэтому было принято решение переписать утилиту phys_addr для автономной работы (инициализация интерфейсов, выделение памяти, запись стартового адреса в регистры, запуск транзакции). И здесь возникла проблема:

Были обнаружены потери данных внутри одной транзакции (данные передаются, но теряются некоторые посылки, зависимости установить не удалось).
Причем, потери возникают в том месте, где устанавливается стартовый бит (младший бит в регистре 0хс0000000) в единицу внутри программы. Если же программу поставить на паузу и вручную установить младший бит в регистре 0хс0000000 в единицу, потерь нет (так как описано в статье, утилиты mem и phys_addr).

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


P.S. Cyclone V, de1-soc. Был бы рад руководству (документации), по написанию программ для sgdma ядра.
Слева изображение с потеряными посылками (№1,8,9), справа без потерь. Во вложении программный код.

Сообщение отредактировал Nedd - Aug 10 2015, 11:34
Эскизы прикрепленных изображений
Прикрепленное изображение
Прикрепленное изображение
 

Прикрепленные файлы
Прикрепленный файл  dma_test.rar ( 23.99 килобайт ) Кол-во скачиваний: 14
 
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
johan
сообщение Dec 23 2015, 09:27
Сообщение #2


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

Группа: Свой
Сообщений: 78
Регистрация: 3-09-12
Пользователь №: 73 371



Так получилось, что коллеги топикстартера вышли на меня и попросили глянуть этот кейс на тех платах, на которых я работаю.

Я посмотрел - действительно, воспроизводится - результат аналогичный (видны пропуски).
Для исключения ошибки в FPGA коде я написал свой, который делает аналогичные действия, но пишет шириной данных по 32 бита (вместо 128, как было у автора). Результат тоже аналогичный - видны пропуски, хотя я писал и через интерфейсы fpga2hps и через fpga2sdram.

Если открыть Cyclone V Hard Processor System Technical Reference Manual Figure 1-2: HPS Block Diagram, то видно, что при использовании этих интерфейсов поток данных идет в обход процессора ARM (MPU Subsystem), в том числе его кэша L2 (64 КБ). Следовательно, когда программа в юзерспейсе просит процессор прочитать данные из DDR-памяти, то если данные остались в кэше, то он вычитает из кэша.

Эта идея подтвердилась тем, что в той же самой утилите перед запуском DMA-транзакции сделали фейковую обработку данных вида:
Код
#define BIG_ARR_SIZE 1000000
uint32_t* big_arr;

big_arr = malloc( BIG_ARR_SIZE * sizeof( uint32_t ) );

if( big_arr == NULL ) {
  printf("big_arr: can't alloc\n");
  exit( -1 );
}

int i;

uint32_t sum = 0;
for( i = 0; i < BIG_ARR_SIZE; i++ ) {
  big_arr[i] = rand();
}

for( i = 0; i < BIG_ARR_SIZE; i++ ) {
  sum += big_arr[i];
}


А после DMA-транзакции делали печать sum (для того, чтобы ничего не соптимизировалось).
Идея этой фейковой обработки в том, что данные из кэша которые принадлежали той области памяти, куда будет писать FPGA, сбросятся в DDR.
А когда процессор попросит даные из этой памяти, то он будет обязан взять их из DDR-памяти - т.е. самые новые.

На железе было попробовано - действительно пропуски пропали.

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

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

Например, в драйвере aclsoc (Altera OpenCL) для этого делают так:
Код
kalloc_memory = dma_alloc_coherent(NULL, allocated_size, &dma_handle, GFP_KERNEL);
if (kalloc_memory == NULL) {
  return -ENOMEM;
}

// kmalloc returns "kernel logical addresses".
// __pa()          maps "kernel logical addresses" to "physical addresses".
// remap_pfn_range maps "physical addresses" to "user virtual addresses".
// kernel logical addresses are usually just physical addresses with an offset.
// Make the pages uncache-able. Otherwise, will run into consistency issues.
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
if (remap_pfn_range(vma, vma->vm_start,
      dma_handle >> PAGE_SHIFT,
      size,
      vma->vm_page_prot) < 0) {
  return -EAGAIN;
}


В конце статьи про DMA (http://habrahabr.ru/company/metrotek/blog/248145/) Денис (des333) привел пример драйвера, который делает подобное. Можно воспользоваться им, либо написать какой-то свой.

Сообщение отредактировал johan - Dec 23 2015, 09:33


--------------------
Go to the top of the page
 
+Quote Post



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

 


RSS Текстовая версия Сейчас: 26th August 2025 - 09:36
Рейтинг@Mail.ru


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