я пишу драйвер для 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). Но в результате получаются неверные значения.Подскажите что я делаю не так.