Hello. My FPGA has the following PCI bar:
0000:01:00.0 Signal processing controller: Device 1738:2259
Region 0: [virtual] Memory at 1000000000 (64-bit, prefetchable) [size=4G]
The FPGA has a register at offset 0x9003000, that I am trying to write.
My PCI driver probes the successfully, but hangs the kernel when trying to
write the registers. I believe the address 0xffffff8150030000 is correct.
Here is the printk output:
root@rudma-mtf:~# modprobe ifpgapci
[ 54.760168] IFPGA device resource 0: start at 0x1000000000 with length 4294967296
[ 54.767663] IFPGA device mapped resource 0x1000000000 to 0xffffff80c0000000
[ 54.774655] IFPGA call __raw_writel with data_to_write = 12345678 pAddr = 0xffffff8150030000
Any help is greatly appreciated.
My code is based on Olega Kutkov's blog at
https://olegkutkov.me/2021/01/07/wri...ver-for-linux/
and is as follows:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#define MY_DRIVER "ifpgapci"
static struct pci_device_id my_driver_id_table[] = {
{ PCI_DEVICE(0x1738, 0x2259) }, {0,}
};
MODULE_DEVICE_TABLE(pci, my_driver_id_table);
static int my_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void my_driver_remove(struct pci_dev *pdev);
static struct pci_driver my_driver = {
.name = MY_DRIVER,
.id_table = my_driver_id_table,
.probe = my_driver_probe,
.remove = my_driver_remove
};
struct my_driver_priv {
void __iomem* hwmem;
};
static int __init mypci_driver_init(void)
{
return pci_register_driver(&my_driver);
}
static void __exit mypci_driver_exit(void)
{
pci_unregister_driver(&my_driver);
}
static int my_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int bar, err;
unsigned long mmio_start,mmio_len;
struct my_driver_priv *drv_priv;
void* pAddr;
unsigned int data_to_write = 0x12345678;
bar = pci_select_bars(pdev, IORESOURCE_MEM);
err = pci_enable_device_mem(pdev);
if (err) {
return err;
}
err = pci_request_region(pdev, bar, MY_DRIVER);
if (err) {
return err;
}
mmio_start = pci_resource_start(pdev, 0);
mmio_len = pci_resource_len(pdev, 0);
printk("IFPGA device resource 0: start at 0x%lx with length %lu\n", mmio_start, mmio_len);
drv_priv = kzalloc(sizeof(struct my_driver_priv), GFP_KERNEL);
if (!drv_priv) {
return -ENOMEM;
}
drv_priv->hwmem = ioremap(mmio_start, mmio_len);
if (!drv_priv->hwmem) {
return -EIO;
}
printk("IFPGA device mapped resource 0x%lx to 0x%px\n", mmio_start, drv_priv->hwmem);
pci_set_drvdata(pdev, drv_priv);
drv_priv = (struct my_driver_priv *) pci_get_drvdata(pdev);
if (!drv_priv) {
printk("drv_priv is NULL\n");
return -EIO;
}
pAddr = drv_priv->hwmem + 0x90030000;
printk("IFPGA call __raw_writel with data_to_write = %08X pAddr = 0x%px\n", data_to_write, pAddr);
__raw_writel(data_to_write, pAddr);
printk("IFPGA after __raw_writel\n");
return 0;
}
static void my_driver_remove(struct pci_dev *pdev)
{
struct my_driver_priv *drv_priv = pci_get_drvdata(pdev);
if (drv_priv) {
if (drv_priv->hwmem) {
iounmap(drv_priv->hwmem);
}
kfree(drv_priv);
}
pci_release_region(pdev, pci_select_bars(pdev, IORESOURCE_MEM));
pci_disable_device(pdev);
}
MODULE_LICENSE("GPL");
module_init(mypci_driver_init);
module_exit(mypci_driver_exit);