Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Не работает DMA. Устройство Stratix IV подключено к шине PCI. ОС Windows 7.  (Прочитано 7709 раз)
0 Пользователей и 1 Гость смотрят эту тему.
alexey29
Интересующийся

ru
Offline Offline

« : 05-02-2014 16:30 » 

Здравствуйте.
Режим DMA под XP работает, а вот под windows 7 (32 бит) не хочет.

У меня алгоритм работы следующий.
1) Создаю объект AdapterObject;
2) Выделяю непрерывную физическую память под таблицу дескрипторов( Scatter/Gatcher для движка DMA контроллера ) и под буфер для DMA данных.
3) Подготавливаю таблицу дескрипторов.

4) Записываю в регистр контроллера физический адрес на первый дескриптор.
5) Запускаю движок DMA. (А он отрабатывает так как будто по этому физическому адресу он ничего не смог прочитать или прочитал ерунду).

Создаём AdapterObject, выделяем память и подготавливаем таблицу дескрипторов.
Код:
//Создаём AdapterObject, выделяем память и подготавливаем таблицу дескрипторов.
DEVICE_DESCRIPTION dd;
RtlZeroMemory(&dd, sizeof(dd));
dd.Version = DEVICE_DESCRIPTION_VERSION;
dd.Master = TRUE;
dd.ScatterGather = FALSE;
dd.InterfaceType = InterfaceTypeUndefined; //PCIBus; //InterfaceTypeUndefined; 
dd.MaximumLength = PAGE_SIZE;
dd.Dma32BitAddresses = TRUE;

pdx->AdapterObject = IoGetDmaAdapter(pdx->Pdo, &dd, &pdx->nMapRegisters);
KdPrint(("pdx->nMapRegisters = %X\n", pdx->nMapRegisters));  //Возвращает цифру 8

...

//Выделим память для таблицы дескрипторов
rdDMA->VAdrDescTable[i] = (PDescriptorTable)(*pdx->AdapterObject->DmaOperations->AllocateCommonBuffer)
(pdx->AdapterObject, sizeTablDesc, &rdDMA->PhAdrDescTable[i], FALSE);
RtlZeroMemory( rdDMA->VAdrDescTable[i], sizeTablDesc );

//Выделим память для буффера
rdDMA->VAdrBufDma[i] = (PUCHAR)(*pdx->AdapterObject->DmaOperations->AllocateCommonBuffer)
(pdx->AdapterObject, sBufRd, &rdDMA->PhAdrBufDma[i], FALSE);
RtlZeroMemory(rdDMA->VAdrBufDma[i], sBufRd);

//Создадим mdl для буфера чтения DMA (для того чтобы можно было получить указатель USER_MODE)
rdDMA->MdlList[i] = IoAllocateMdl(rdDMA->VAdrBufDma[i], sBufRd, FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(rdDMA->MdlList[i]);

//Подготовка таблиц чтения
PDescriptorTable rdt = rdDMA->VAdrDescTable[i];
ULONG sDescTabl = sizeof(DescriptorTable);
for (ULONG j = 0; j < cDescRead; j++)
    {
rdt[j].source = 0;
rdt[j].destination = rdDMA->PhAdrBufDma[i].LowPart+(j*sDesc); //Физический адресс куда контроллер будет передовать данные
rdt[j].next_desc_ptr = (j==cDescRead-1) ? 0 : rdDMA->PhAdrDescTable[i].LowPart+(sDescTabl*(j+1)); //Физический адресс следующей таблицы дескрипторов
rdt[j].bytes_to_transfer = sDesc;
rdt[j].desc_control = OWNED_BY_HW;
rdt[j].desc_status = 0;
    }
   

Выполняем чтение из DMA
Код:
WRITE_REGISTER_ULONG( NextDeskReg, pdx->workReadDMA->PhAdrDescTable[bufInReadDma->buf_id].LowPart ); //Записывается физический адрес первой таблицы дескрипторов
WRITE_REGISTER_ULONG( StatusReg, 0x1f);
WRITE_REGISTER_ULONG( ControlReg, 0);

//Запуск движка DMA
WRITE_REGISTER_ULONG( ControlReg, RUN | IE_ERROR | IE_EOP_ENCOUNTERED | IE_DESCRIPTOR_COMPLETED | IE_CHAIN_COMPLETED | IE_GLOBAL | PARK | CLEAR_INTERRUPT);

//

//Ожидание данных
//Дождемся окончания работы движка
while(TRUE)
{
st = READ_REGISTER_ULONG( StatusReg );
if (st & CHAIN_COMPLETED) // CHAIN_COMPLETED = 0x8
break;
KeQuerySystemTime(&curr);
if ((curr.QuadPart - start.QuadPart) > tout_interval.QuadPart)
{
*retErrCode = 0xFFFFFFFF;
pdx->lastCodeError = 7;
WRITE_REGISTER_ULONG( ControlReg, SW_RESET);
break;
}
}

//READ_REGISTER_ULONG( StatusReg ) под Windows 7 этот регистр равен 0x8 (Движок закончил работу но ни один из дескрипторов не был выполение)

if (READ_REGISTER_ULONG( StatusReg ) == 0xC)   //0xС  1100  (2 бит - хотя бы один дескриптор был выполнен, 3 бит - движок ДМА закончил работу)
{
//Данные успешно сняты
}
else
{
//Ошибка
}


Я не могу понять почему под XP работает а под windows 7 не хочет.
Подскажите где надо искать проблему???
Спасибо.



Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 06-02-2014 07:30 » 

Доброго времени!
честно говоря со ScatterGather никогда не работал, поэтому знания только теоретические.
кстати почему dd.ScatterGather = FALSE? (я так и не разобрался  в свое время с этим флагом)

dd.InterfaceType = InterfaceTypeUndefined; //PCIBus; - я так понимаю пробовали разные значения?
что за движок DMA? может быть у него есть ограничения на используемый диапазон физических адресов? попробуйте сравнить физ адреса выдеяемые в XP и Win7. где то тут мелькала тема с проблемой в том что плата не работала с адресами выше какого то, может быть похожий случай?
либо может быть они как-то выровнены должны быть на границу чего нибудь.
проверьте на всякий случай что HighPart=0 для физ адресов, хотя не должно быть...
« Последнее редактирование: 06-02-2014 07:38 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
alexey29
Интересующийся

ru
Offline Offline

« Ответ #2 : 06-02-2014 08:41 » 



AdapterObject я использую только для выделения непрерывной памяти. поэтому мне всё равно чему равен параметр dd.ScatterGather. Если бы в моё устройство надо было записывать список ScatterGather, тогда я бы уставил его в true. В моём случае устройство это делает самостоятельно.

Цитата
dd.InterfaceType = InterfaceTypeUndefined; //PCIBus; - я так понимаю пробовали разные значения?

Да пытался записать PCIBus. Но результата нету.

HighPart = 0

Возможно у движка устройства есть ограничение на диапазон использования физических адресов.
В windows 7    выделяются адреса  ( 0xB8AF9000;  0xDB0E7000)
В windows XP  выделяются адреса  (   0x4648000;    0x8797000)


Пойду искать как с помощью AdapterObject сделать ограничение на диапазон физических адресов. Если я правильно понял то , WDM.h не имеет функции MmAllocateContiguousMemory.
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 06-02-2014 09:23 » 

я только непрерывный DMA делал и тоже через AllocateCommonBuffer.
похоже в Win8 есть AllocateCommonBufferEx с параметром ограничения.

есть и MmAllocateContiguousMemory и   MmAllocateContiguousMemorySpecifyCache начиная с Win2000. ( они в ntddk.h)
но я уже не помню почему я его не использовал.. а использовал выделение через адаптер.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
alexey29
Интересующийся

ru
Offline Offline

« Ответ #4 : 06-02-2014 10:31 » 

перешёл на ntddk.h. От WDM пришлось отказаться из за отсутствия MmAllocateContiguousMemory.

Поставил ограничение на максимальный адрес 0x80000000.

И всё стало работать.

Я даже подумать не мог что моё устройство имеет ограничения на доступ к физической памяти.
Спасибо огромное!


Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 06-02-2014 13:24 » new

всегда пожалуйста)
удачи!
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines