經過大量的研究,我找到了一種方法,讀寫PCI BAR2
。看來,ioremap
,pci_ioremap_bar
或memremap()
(內核4.3+)允許CPU緩存在PCI設備和內核空間內存之間傳輸的數據。這會導致數據損壞。但我不知道它終於來自哪裏。
解決此問題的方法使用的ioremap_nocache
。以下代碼顯示了PCI探針功能。
static int
_pci_probe (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int ret = 0;
int i;
unsigned long *pbas2addr;
u8 buf8;
u8 *mem8;
buf8 = 0xF0;
// put mem8 to the heap and initialize them with zeros
mem8 = kcalloc((0x020000),sizeof(u8), GFP_KERNEL);
// enabling the device
ret = pci_enable_device(pdev);
if(ret)
{
printk(KERN_ERR "Failed to enable PCI device.\n");
goto no_enable;
}
// take ownership of pci related regions
pci_request_regions(pdev, "expdev");
// checking if PCI-device reachable by checking that BAR0 is defined and
// memory mapped
if(!(pci_resource_flags(pdev,0) & IORESOURCE_MEM))
{
printk(KERN_ERR "Incorrect BAR configuration.\n");
ret = -ENODEV;
goto bad_bar;
}
// remap BAR2 avoiding the use of CPU cache
pbas2addr = ioremap_nocache(pci_resource_start(pdev,2),
pci_resource_len(pdev,2));
printk(KERN_INFO "BAR2 Addr: %p\n",pbas2addr);
printk(KERN_INFO "BAR2 len: %x\n",(int)pci_resource_len(pdev,2));
// write something to BAR2
buf8 = 0xF0;
for (i = 0x000000; i<0x020000; i++)
{
*((u8*)pbas2addr+i) = buf8; // it's important to cast the pointer
}
// read back
buf8 = 0;
for (i = 0x000000; i<0x020000; i++)
{
mem8[i] = *((u8*)pbas2addr+i);
}
return 0;
bad_bar:
pci_disable_device(pdev);
no_enable:
return ret;
}
此外:
- 使用
iowrite
不起作用穩定映射內存的訪問。有時會在PCI BAR2
內存中找到人造廢話。也許有這個命令的保留序列。我不知道。
- 在我的情況下,
BAR2
內存的一些地址範圍需要寫入兩次。我認爲這是該設備的特殊行爲。
- 在我的情況下,並不是所有的地址範圍都可以通過32位訪問達到。我認爲這也是這種設備的特殊行爲。
你不能訪問任何東西而不映射它。你試圖解決的實際問題是什麼? –
目標是訪問PCI設備上的存儲空間以實現快速數據交換。我知道我需要映射地址。但我讀到有兩種不同類型的映射。 IO映射達到IO空間和內存映射達到內存空間。我知道通過io映射到達內存空間的方式,但現在我正在尋找通過內存映射來實現它的更快方法。 – Alex44
在x86(-64)上,我只能通過內存映射通過I/O映射和內存BAR映射I/O BAR,據我所知。其他體系結構不一定有區別,其實現可以使用I/O範圍的內存映射(例如PPC)。 – pmdj