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

NeStor46

Участник
  • Постов

    8
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

Посетители профиля

567 просмотров профиля
  1. Txs в PCI-E от Altera

    Здравствуйте. В ядре PCI-E от Altera обмен данными с платой построен следующим образом. Запись данных в плату идет через Bar0 с которого идут на OnChip: http://itmages.ru/image/view/1894191/ab4f91a7 Чтение данных с платы в память ПК надо осуществлять с помощью DMA, который подцеплен на OnChip и на Txs: http://itmages.ru/image/view/1894192/b6a7b059 . DMA считывает данные из OnChip и отправляет их на Txs, откуда они уже и отправляются в память ПК. По крайней мере так мне объяснили. Никто не работал с ядром PCI-E от Altera? Можете объяснить процесс обмена данными между ПК и платой? Что, откуда и как идет? Столкнулся со следующей проблемой: в DMA записываю адрес откуда читать (OnChip платы) и адрес (32-битный) куда записать прочитанные данные (буфер в памяти ПК). Контроллер DMA считывает данные, а потом отправляет их на Txs, откуда они по ходу и должны попасть в память ПК, но txs_address имеет разрядность 25 бит, получается, что он отрезает старшие разряды начального 32-битного адреса и отправляет данные неизвестно куда. По моему я неправильно понимаю весь механизм передачи данных. Может кто-нибудь пояснить или рассказать как там на самом деле все происходит? Как и какие адреса писать в DMA, чтобы организовать обмен данными между платой и памятью ПК?
  2. отвечу сам себе) с 32-разрядными регистрами адреса работает неплохо, то пока только в пределах адресного пространства, выделенного под BAR0. Т.е. драйвер может, используя mSGDMA, писать и читать данные, но пока только по адресам, задаваемым смещением относительно начала BAR0. Приведу кусок кода драйвера, чтобы было понятней) BOOLEAN EvtProgramReadDma( IN WDFDMATRANSACTION Transaction, IN WDFDEVICE Device, IN WDFCONTEXT Context, IN WDF_DMA_DIRECTION Direction, IN PSCATTER_GATHER_LIST SgList ) { PDEVICE_EXTENSION devExt; size_t offset; ULONG i; UNREFERENCED_PARAMETER( Context ); UNREFERENCED_PARAMETER( Direction ); devExt = PLxGetDeviceContext(Device); offset = WdfDmaTransactionGetBytesTransferred(Transaction); WdfInterruptAcquireLock( devExt->Interrupt ); //временно останавляваю диспетчер { union { DISP_CONTROL bits; ULONG ulong; } DispCtrl; DispCtrl.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDisp ); DispCtrl.bits.DispStop = TRUE; WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDisp, DispCtrl.ulong ); } //заполняем таблицу дескпипторов for (i=0; i < SgList->NumberOfElements; i++) { WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->ReadAddr, offset); WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->WriteAddr, SgList->Elements[i].Address.LowPart); WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->Length, SgList->Elements[i].Length); { union { DESC_CONTROL bits; ULONG ulong; } DescCtrl; DescCtrl.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDesc ); //последний пакет if (i==SgList->NumberOfElements-1) { DescCtrl.bits.TransferCOMP_IRQ = TRUE; } else { DescCtrl.bits.DoneEarly = TRUE; } DescCtrl.bits.Go = TRUE; WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDesc, DescCtrl.ulong ); } } //запускаю диспетчер { union { DISP_CONTROL bits; ULONG ulong; } DispCtrl; DispCtrl.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDisp ); DispCtrl.bits.DispStop = FALSE; WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDisp, DispCtrl.ulong ); } WdfInterruptReleaseLock( devExt->Interrupt ); return TRUE; } Вот. Если задавать адреса записи и чтения только смещением (в принципе любое число от 0 до 0x8000000 в моем случае, на BAR0 выделено 128 МБ), то все работает и работает хорошо. Винда, похоже, отображает эти адреса в системную память и все довольны, все работают. Но проблема возникла при записи или чтения пользовательского буфера. В приведенном выше коде я хочу прочитать данные по смещению из BAR0 и занести их в пользовательский буфер, который по идее должен быть задан страницами, физические адреса которых передала мне Винда в виде Scatter/Gather списка, но ничего не выходит. ДМА пишет по адресу записи, но этот адрес, судя по всему, не тот, что мне нужен. В общем не знаю пока как подсунуть контроллеру нужный адрес пользовательского буфера (выделенного приложением, от которого шел запрос на чтение). Есть какие-нибудь предложения?
  3. по ходу они и вешали) сегодня запустил этот уже изрядно задолбавший mSGDMA. Транзакция запускается, что-то передается, в конце передачи генерируется прерывание, которое потом обрабатываю и ничего не виснет, но возникла новая проблема... адресация. ОС у меня х64, дискриптор в mSGDMA выбран расширенный, т.е. должен работать с 64 разрядными адресами (64-bit addressing requires the use of the extended descriptor format), но передает на read_master он всего одну часть адреса, младшую. Изначально в проекте был выбран стандартный дискриптор с 32 адресацией. Альтеровский софт для теста скорости передачи по PCI-E похоже и использовал стандартный дискриптор, так как при смене его на расширенный, софт перестал работать. Выходит, что и мне надо работать с 32-разрядными адресами??
  4. Никак не получается запустить mSGDMA (modular SGDMA (мануал прикреплен ниже)). Написал следующий код, который по идее должен стартовать DMA транзакцию, но ничего не выходит. BOOLEAN EvtProgramReadDma( IN WDFDMATRANSACTION Transaction, IN WDFDEVICE Device, IN WDFCONTEXT Context, IN WDF_DMA_DIRECTION Direction, IN PSCATTER_GATHER_LIST SgList ) { PDEVICE_EXTENSION devExt; size_t offset; ULONG i; UNREFERENCED_PARAMETER( Context ); UNREFERENCED_PARAMETER( Direction ); devExt = PLxGetDeviceContext(Device); offset = WdfDmaTransactionGetBytesTransferred(Transaction); WdfInterruptAcquireLock( devExt->Interrupt ); for (i=0; i < SgList->NumberOfElements; i++) { //физический адрес начала памяти BAR0, полученный при инициализации устройства. Отсюда надо читать WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->ReadAddrLow, &devExt->ReadAddr.LowPart); //Read Address[31..0] WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->ReadAddrHigh, &devExt->ReadAddr.HighPart); //Read Address[63..32] //физические адреса страниц, сооставляющих выделенный пользовательским приложением буффер. Сюда необходимо передать //сформированный виндой Scatter/Gather List, соответствующий запросу от приложения WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->WriteAddrLow, SgList->Elements[i].Address.LowPart); //Write Address[31..0] WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->WriteAddrHigh, gList->Elements[i].Address.HighPart); //Write Address[63..32] //длина каждой передаваемой страницы WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->Length, SgList->Elements[i].Length); //Length[31..0] WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->Burst_SeqNumber, 0); WRITE_REGISTER_ULONG ((PULONG) &devExt->Regs->Stride, 0x10001); //Write Stride[15..0], Read Stride[15..0] { union { DESC_CONTROL bits; ULONG ulong; } DescCtrl; DescCtrl.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDesc ); //первый пакет if (i==0) { DescCtrl.bits.SOP = TRUE; } //последний пакет else if (i==SgList->NumberOfElements-1) { DescCtrl.bits.EOP = TRUE; DescCtrl.bits.TransferCOMP_IRQ = TRUE; DescCtrl.bits.EARLY_IRQ = TRUE; } //одиночный пакет else { DescCtrl.bits.SOP = TRUE; DescCtrl.bits.EOP = TRUE; DescCtrl.bits.TransferCOMP_IRQ = TRUE; DescCtrl.bits.EARLY_IRQ = TRUE; } DescCtrl.bits.TransmitERR_IRQ = 0xFF; DescCtrl.bits.Go = TRUE; WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDesc, DescCtrl.ulong ); } } //настройка управляющего регистра диспетчера { union { DISP_CONTROL bits; ULONG ulong; } DispCtrl; DispCtrl.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDisp ); //за что отвечает этот бит не совсем понял. //разрешает прерывания или разрешает их если не заданы маски? DispCtrl.bits.IntMask = TRUE; WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->ControlDisp, DispCtrl.ulong ); } WdfInterruptReleaseLock( devExt->Interrupt ); return TRUE; } При этом, если пытаться отправить один пакет, то чтение статусного регистра диспетчера говорит, что дескрипторное фифо пусто, если отправлять 2 и более пакетов, то выставляется Busy статусного регистра диспетчера говорит, что в фифо что-то есть или идет передача, а Fill Level показывает количество занесеный в фифо дескрипторов. Но этот Busy стоит вечно, пока вручную не уберешь. Выходит, что дескрипторы записываются, отправляются в фифо, откуда их должен вызывать диспетчер, но сам диспетчер передачу не запускает? потому они и остаются там висеть. Или же я не совсем верно заполняю эти дескрипторы? В альтеровских дровах к модулю есть функции stop_dispatcher() и start_dispatcher(), смысл которых сводится к установке в 1 или 0 бита "Stop Dispatcher". Может быть стоит перед записью дескрипторов остановить диспетчер, а после записи запускать его? (почему-то не подумал об этом сразу). Или же необходимо настраивать что-то еще? Кстати, не совсем понял почему так происходит, но порой при установке бита "Global Interrupt Enable Mask" в диспетчере, компьютер намертво повисал. Может это было от того, что диспетчер засыпал его прерываниями, а я их толком не обработал? Прерывания либо вообще не приходят, либо система зависает намертво, но пока не выяснил чем именно это было вызвано. Есть какие-нибудь идеи у кого? Буду очень признателен за любую помощь! Заранее спасибо, если хотя бы дочитали) Modular_SGDMA_Dispatcher_Core.pdf
  5. Спасибо, т.е. записывать в дескрипторы элементы SGL, сформированные виндой, пока не заполнится дескрипторные фифо, потом заново заполнять дескрипторы и т.д. до тех пор, пока не будут переданы все данные. Спасибо за разъяснение. в dst addr я так понимаю необходимо записывать адрес выделенного пользовательским приложением буфера (приложение, от которого шел запрос на чтение).
  6. Доброго времени суток всем! Наверное, кто-то разбирался с альтровским mSGDMA и сможет помочь немного разобраться. При написании драйвера под Windows для платы PCI-E дошел до организации транзакций чтения и записи с использованием mSGDMA и сел. Немного не понятно, как работает этот самый mSGDMA с конфигурацией Memory-Mapped to Memory-Mapped. Допустим в драйвер поступил запрос на чтение. Выполнив необходимые программные действия дело доходит до программирования устройства и собственно нашего mSGDMA. Заносить в дескрипторы необходимо адреса и длину элементов SGL(scatter-gather list), сформированного ОС, т.е. большое число буферов малой длины (4кБ), или же просто записать в дескриптор mSGDMA адрес откуда читать и длину читаемых данных, а дальше он сам разберется что и как ему делать? Запуск dma передачи начинается автоматически, как только данные из дескриптора передаются в дескрипторное FIFO при установке контрольного бита Go? а как только передача выполняется выставляется прерывание, которое сообщает о выполнении операции? и нужно ли что-то настраивать, чтобы эти прерывания генерировались? Пока нашел только пример драйвера для Linux, описывающий работу с этим mSGDMA, но еще не совсем в нем разобрался. Здесь есть и описание управляющего регистра дескриптора для разных видов передачи http://lxr.free-electrons.com/source/drive...tera_msgdmahw.h , но не знаю применимы для они для dma в pci-e. Откликнитесь, кто-нибудь, пожалуйста. Вопросов, пока много, а понимания мало. Буду благодарен за любую консультацию.
  7. Доброго времени суток. Стоит задача написания драйвера под Windows для PCI-Е. В альтеровском мануале к PCI Express Hard IP на странице 15-14 (246 по счету) и далее (ссылка на сам мануал - http://www.altera.com/literature/ug/ug_pci_express.pdf ) приводится описание управляющего и статусного регистров (Chaining DMA Control and Status Registers). Для инициализации DMA транзакций в моем драйвере мне необходимо использовать именно эти регистры или же они задействованы только при создании тестового проекта с BFM модулем?
×
×
  • Создать...