Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Драйвер для Xilinx Virtex-6 X8 PCI Express
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Linux
art-folko
я пишу драйвер для Xilinx Virtex-6 X8 PCI Express Gen 2 Evaluation/Development Kit SX315T FPGA под линукс. У меня стоит openSUSE 11.3 64 bit. В документации к плате (Virtex-6 FPGA Integrated Block form PCI Express User Guide UG517 (v5.0) April 19, 2010, стр 219) сказано:

The PIO design is a simple target-only application that interfaces with the Endpoint for PCIe core’s Transaction (TRN) interface and is provided as a starting point for customers to build their own designs. The following features are included:

• Four transaction-specific 2 KB target regions using the internal Xilinx FPGA block RAMs, providing a total target space of 8192 bytes

• Supports single DWORD payload Read and Write PCI Express transactions to 32-/64-bit address memory spaces and I/O space with support for completion TLPs

• Utilizes the core’s trn_rbar_hit_n[6:0] signals to differentiate between TLP destination Base Address Registers

• Provides separate implementations optimized for 32-bit, 64-bit, and 128-bit TRN interfaces

В устройстве определены BAR0 и BAR2 длинной 128 байт каждый. Я пытаюсь получить доступ к этой встроенной памяти, для этого я делаю отображение BAR0 в виртуальное пространство ядра.

CODE
struct pcie_dev {
struct pci_dev* dev;
struct cdev chr_dev;
atomic_t dev_available;
u32 IOBaseAddress;
u32 IOLastAddress;
void* __iomem bar;
void *virt_addr;
u32 length;
unsigned long sirqNum;
void *private_data; };

struct pcie_dev cur_pcie_dev;

cur_pcie_dev.IOBaseAddress = pci_resource_start(dev, 0);
cur_pcie_dev.IOLastAddress = pci_resource_end(dev, 0);
cur_pcie_dev.length=pci_resource_len(dev,0);
cur_pcie_dev.bar=pci_iomap(dev, 0,cur_pcie_dev.length);


Получаем
IOBaseAddress = 0xfbbfe000 IOLastAddress = 0xfbbfe07f length=128;

Используя IOCTL я пытаюсь записать,прочитать данные.

CODE
case IOCTL_INFO_DEVICE:
{
u32 *rcslave_mem = (u32 *)pCur_dev->bar;
u32 result = 0;

u32 value = 0;
int i;
for (i = 0; i <2048 ; i++) {
printk(KERN_DEBUG "Writing 0x%08x to 0x%p.\n",
(u32)value, (void *)rcslave_mem + i);
iowrite32(value, rcslave_mem + i);
value++;
}
/* read-back loop */
value = 0;
for (i = 0; i < 2048; i++) {
result = ioread32(rcslave_mem + i);
printk(KERN_DEBUG "Wrote 0x%08x to 0x%p, but read back 0x%08x.\n",
(u32)value, (void *)rcslave_mem + i, (u32)result);

value++;
}


Но получается записать и прочитать только 32 значения. Как я понимаю запись произвелась только в BAR0 (4 byte * 32 values = 128 bytes), а не в встроенную память.Пытался пойти другим путём:

CODE
cur_pcie_dev.IOBaseAddress = pci_resource_start(dev, 0);
cur_pcie_dev.IOLastAddress = pci_resource_end(dev, 0);
cur_pcie_dev.length=pci_resource_len(dev,0);
flags = pci_resource_flags(dev,0);

if (flags & IORESOURCE_MEM) {
if (request_mem_region(cur_pcie_dev.IOBaseAddress,cur_pcie_dev.length, DEVICE_NAME)== NULL) {
return -EBUSY;}

cur_pcie_dev.virt_addr=ioremap_nocache(cur_pcie_dev.IOBaseAddress,cur_pcie_dev.l
ength);
if (cur_pcie_dev.virt_addr == NULL) {
printk(KERN_ERR "ERROR: BAR%u remapping FAILED\n",0);
return -ENOMEM;
}
printk(KERN_INFO " Allocated I/O memory range %#lx-%#lx\n", cur_pcie_dev.IOBaseAddress,(cur_pcie_dev.IOBaseAddress+cur_pcie_dev.length-1));
} else {
printk(KERN_ERR "ERROR: Invalid PCI region flags\n");
return -EIO;
}


Затем

CODE
address = (pCur_dev->virt_addr+pd.Address);
iowrite32(pd.Value,(unsigned int*) address);

address = ((unsigned int)pCur_dev->virt_addr+pd.Address);
pd.Value = ioread32((unsigned int *)address);


Адрес я получаю складывая виртуальный адрес и адрес,который задаёт пользователь (например адрес от пользователя = 0х1, 0х2). Но в результате получаются неверные значения.Подскажите что я делаю не так.
jojo
>получается записать и прочитать только 32 значения. Как я понимаю запись произвелась только в BAR0 (4 byte * 32 values = 128 bytes), а не в встроенную память.

Вроде у вас в первом варианте всё работало. Вы прочитали из BAR0 32 четырёхбайтовых числа.
Только я не понял противопоставления BAR0 и встроенной памяти. В примере PIO только встроенная память и выступает в качестве хранилища данных.

Да, и адрес должен быть кратным 4 для int32..
sasamy
Цитата(art-folko @ May 21 2011, 21:43) *
struct pcie_dev {
....
void *virt_addr;
.....

Но в результате получаются неверные значения.Подскажите что я делаю не так.


Не знаете что такое указатель в С

Код
sasa@sasa-laptop:~/test$ cat void_vs_int.c
#include <stdio.h>

int main(void)
{
    int *pInt = 0;
    void *pVoid = 0;

    pInt += 1;
    pVoid += 1;
    
    printf("pInt + 1 = %u\n", (int)pInt);
    printf("pVoid + 1 = %u\n", (int)pVoid);
    
    return 0;
}    
sasa@sasa-laptop:~/test$ gcc void_vs_int.c && ./a.out
pInt + 1 = 4
pVoid + 1 = 1
art-folko
Цитата(jojo @ May 22 2011, 09:42) *
>получается записать и прочитать только 32 значения. Как я понимаю запись произвелась только в BAR0 (4 byte * 32 values = 128 bytes), а не в встроенную память.

Вроде у вас в первом варианте всё работало. Вы прочитали из BAR0 32 четырёхбайтовых числа.
Только я не понял противопоставления BAR0 и встроенной памяти. В примере PIO только встроенная память и выступает в качестве хранилища данных.

Да, и адрес должен быть кратным 4 для int32..

как мне объяснил инженер,который формировал прошивку для данного устройства, что через BAR0 можно получить доступ к этой встроенной памяти. Честно говоря я тоже не сильно понял как такое может быть.Я считаю что именно BAR0 и есть память ввода/вывода размером 128 байт,которая берётся из встроенной памяти.связанной с ПЛИС.

Цитата(sasamy @ May 22 2011, 11:06) *
Не знаете что такое указатель в С

Код
sasa@sasa-laptop:~/test$ cat void_vs_int.c
#include <stdio.h>

int main(void)
{
    int *pInt = 0;
    void *pVoid = 0;

    pInt += 1;
    pVoid += 1;
    
    printf("pInt + 1 = %u\n", (int)pInt);
    printf("pVoid + 1 = %u\n", (int)pVoid);
    
    return 0;
}    
sasa@sasa-laptop:~/test$ gcc void_vs_int.c && ./a.out
pInt + 1 = 4
pVoid + 1 = 1


Спасибо, за ваше замечание и пример.В моём коде присутствует ошибка.Не внимательно проверял код при вставке,случайно стёр приведение типа в операции формирования адреса для чтения.Вот правильный код.
CODE
address = ((unsigned int)pCur_dev->virt_addr+pd.Address);
iowrite32(pd.Value,(unsigned int*) address);

address = ((unsigned int)pCur_dev->virt_addr+pd.Address);
pd.Value = ioread32((unsigned int *)address);

jojo
> мне объяснил инженер,который формировал прошивку для данного устройства, что через BAR0 можно получить доступ к этой встроенной памяти. Честно говоря я тоже не сильно понял как такое может быть.Я считаю что именно BAR0 и есть память ввода/вывода размером 128 байт,которая берётся из встроенной памяти.связанной с ПЛИС.

Мне кажется, всё, что вы могли сделать с этой прошивкой, уже сделано.
Если хотите прочитать 2048 байт в BAR0, то и размер BAR0 нужно сделать 2048, а у вас он равен 128.
Потом, если читаете 2048 байт, судя по циклу, то вызывать надо чтение байта, а не слова.
sasamy
Цитата(art-folko @ May 22 2011, 14:06) *
Не внимательно проверял код при вставке,случайно стёр приведение типа в операции формирования адреса для чтения.Вот правильный код.
CODE
address = ((unsigned int)pCur_dev->virt_addr+pd.Address);
iowrite32(pd.Value,(unsigned int*) address);


В каком месте он правильный ?
Цитата
Адрес я получаю складывая виртуальный адрес и адрес,который задаёт пользователь (например адрес от пользователя = 0х1, 0х2)


При таком раскладе вы обращаетесь по невыровненным адресам
Код
sasa@sasa-laptop:~/test$ cat void_vs_int.c
#include <stdio.h>

int main(void)
{
    int *pInt = 0;
    void *pVoid = 0;

    printf("pInt + 1 = %u\n", (int)pInt + 1);
    printf("pVoid + 1 = %u\n", (int)pVoid + 1);
    
    return 0;
}    
sasa@sasa-laptop:~/test$ gcc void_vs_int.c && ./a.out
pInt + 1 = 1
pVoid + 1 = 1


Короче говоря срочно освежайте знания об указателях и приведениях типов в С.
art-folko
Цитата(sasamy @ May 22 2011, 14:28) *
В каком месте он правильный ?


При таком раскладе вы обращаетесь по невыровненным адресам
Код
sasa@sasa-laptop:~/test$ cat void_vs_int.c
#include <stdio.h>

int main(void)
{
    int *pInt = 0;
    void *pVoid = 0;

    printf("pInt + 1 = %u\n", (int)pInt + 1);
    printf("pVoid + 1 = %u\n", (int)pVoid + 1);
    
    return 0;
}    
sasa@sasa-laptop:~/test$ gcc void_vs_int.c && ./a.out
pInt + 1 = 1
pVoid + 1 = 1


Короче говоря срочно освежайте знания об указателях и приведениях типов в С.

Да,действительно,вы правы,мне стоит освежить знания по теме указателей. Сказывается отсутствие практики программирования,во время службы ВС РФ sm.gif


Цитата(jojo @ May 22 2011, 14:21) *
> мне объяснил инженер,который формировал прошивку для данного устройства, что через BAR0 можно получить доступ к этой встроенной памяти. Честно говоря я тоже не сильно понял как такое может быть.Я считаю что именно BAR0 и есть память ввода/вывода размером 128 байт,которая берётся из встроенной памяти.связанной с ПЛИС.

Мне кажется, всё, что вы могли сделать с этой прошивкой, уже сделано.
Если хотите прочитать 2048 байт в BAR0, то и размер BAR0 нужно сделать 2048, а у вас он равен 128.
Потом, если читаете 2048 байт, судя по циклу, то вызывать надо чтение байта, а не слова.

Да,я прекрасно понимаю по поводу того какой у меня размер BAR0 и размер данных которые я читаю.Такой размер цикла я привёл ради примера.
Если я правило вас понял, то все мои действия являются правильными,а по поводу встроенной памяти это имеет отношение к аппаратчикам.То есть это они должны думать как у них организована работа PIO и этой встроенной памяти.
jojo
>Если я правило вас понял, то все мои действия являются правильными,а по поводу встроенной памяти это имеет отношение к аппаратчикам.То есть это они должны думать как у них организована работа PIO и этой встроенной памяти.

Где-то так оно и есть.
art-folko
Спустя почти год, наткнулся на свой вопрос. Спасибо участникам форума, за помощь на тот момент. Проект закончился успехом.Аппаратчики разработали прошивку для ПЛИС, я написал драйвер и СПО для работы с платой.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.