Skip to content

Instantly share code, notes, and snippets.

@TobleMiner
Created March 5, 2022 21:06
Show Gist options
  • Save TobleMiner/78fa225dc20a15b4bfb29eb948646ed3 to your computer and use it in GitHub Desktop.
Save TobleMiner/78fa225dc20a15b4bfb29eb948646ed3 to your computer and use it in GitHub Desktop.
Simple Linux kernel module to test device vs normal memory PCI BAR accesses
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/string.h>
static int vendor_id = -1;
module_param(vendor_id, int, S_IRUGO);
MODULE_PARM_DESC(vendor_id, "PCI vendor id");
static int device_id = -1;
module_param(device_id, int, S_IRUGO);
MODULE_PARM_DESC(device_id, "PCI device id");
static int bar = -1;
module_param(bar, int, S_IRUGO);
MODULE_PARM_DESC(bar, "PCI bar");
static bool device_mem = false;
module_param(device_mem, bool, S_IRUGO);
MODULE_PARM_DESC(device_mem, "Map bar as device memory");
static int bar_test_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int err;
resource_size_t start;
resource_size_t len;
void __iomem* mmio;
unsigned int shift;
/* enable device */
err = pcim_enable_device(pdev);
if (err) {
return err;
}
/* get specified bar */
err = pci_request_region(pdev, bar, "bar_write_test");
if (err) {
pr_err("Failed to request PCI region\n");
return err;
}
start = pci_resource_start(pdev, bar);
len = pci_resource_len(pdev, bar);
pr_info("BAR%d has size 0x%08llx\n", bar, len);
if (device_mem) {
pr_info("Mapping BAR%d as device memory\n", bar);
mmio = ioremap(start, len);
} else {
pr_info("Mapping BAR%d as regular memory\n", bar);
mmio = ioremap_wc(start, len);
}
if (!mmio) {
pr_err("Failed to map BAR %d\n", bar);
goto out;
}
pr_info("Testing BAR write sizes\n");
for (shift = 2; (1ull << shift) <= len; shift++) {
pr_info("Trying 2^%u...\n", shift);
if (device_mem) {
memset_io(mmio, 0, 1ull << shift);
__iowmb();
} else {
memset(mmio, 0, 1ull << shift);
wmb();
}
}
pr_info("BAR seems to be writable at all sizes\n");
iounmap(mmio);
out:
pci_release_region(pdev, bar);
return -1;
}
static struct pci_device_id pci_id_table[] = {
{ PCI_DEVICE(0, 0), },
{ 0, }
};
static struct pci_driver bar_test_driver = {
.name = "bar_write_test",
.id_table = pci_id_table,
.probe = bar_test_pci_probe,
.remove = NULL,
};
static int __init bar_test_driver_init(void)
{
if (vendor_id < 0) {
pr_err("Invalid vendor id %d\n", vendor_id);
return -EINVAL;
}
if (device_id < 0) {
pr_err("Invalid device id %d\n", device_id);
return -EINVAL;
}
if (bar < 0) {
pr_err("Invalid bar %d\n", bar);
return -EINVAL;
}
pci_id_table[0].vendor = vendor_id;
pci_id_table[0].device = device_id;
return pci_register_driver(&bar_test_driver);
}
module_init(bar_test_driver_init);
static void __exit bar_test_driver_exit(void)
{
pci_unregister_driver(&bar_test_driver);
}
module_exit(bar_test_driver_exit);
MODULE_AUTHOR("Tobias Schramm <[email protected]>");
MODULE_DESCRIPTION("PCI BAR write size test driver");
MODULE_LICENSE("Dual BSD/GPL");
obj-m += bar-write-test.o
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment