[Edited]
I am trying to access an I/O port of a PCI device under Linux x86_64, however
inl()
only ever reads 0xFFFFFFFFoutl()
does not effect the hardware
It works under Windows (XP x86) as long as any driver (I tested with a completely empty one) is loaded for that device.
The I/O port range is different under the OSes and seems to be auto-configured by PCI bus driver.
No amount of enabling/disabling/installing/configuring other devices, buses or BIOS settings changes the port range that is assigned to the device by either OS.
The linux driver does only the following:
- From my kernel module
init()
function:pci_register_driver()
specifying relevant PCI vendor/device IDs
- From my
pci_probe()
handler function:pci_enable_device()
pci_resource_*()
which return same PCI BAR data aslspci
pci_request_regions()
inl()
/outl()
- From my kernel module
exit()
functionpci_unregister_driver()
Here is the code:
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/uaccess.h>
static void pci_release(struct pci_dev* pcidev)
{
pci_release_regions(pcidev);
pci_disable_device(pcidev);
pr_err("pci_disable_device");
return;
}
static int pci_probe(struct pci_dev* pcidev, const struct pci_device_id* pcidev_id)
{
long result;
result = pci_enable_device(pcidev);
pr_err("pci_enable_device()=%ld", result);
pr_err("res0=0x%lX", (ulong)pci_resource_flags(pcidev, 0));
pr_err("start=0x%lX", (ulong)pci_resource_start(pcidev, 0));
pr_err("end=0x%lX", (ulong)pci_resource_end(pcidev, 0));
result = pci_request_regions(pcidev, "iotest");
pr_err("pci_request_regions()=%ld", result);
result = inl(pci_resource_start(pcidev, 0));
pr_err("inl()=%lX", result);
return 0;
}
static struct pci_device_id pci_ids[] =
{
{ PCI_DEVICE(0x4321, 0x9876), },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, pci_ids);
static struct pci_driver pcidriver =
{
.probe = pci_probe,
.remove = pci_release,
.id_table = pci_ids,
.name = "iotest"
};
static int __init kmodule_init(void)
{
pr_err("init");
return pci_register_driver(&pcidriver);
}
static void __exit kmodule_exit(void)
{
pr_err("exit");
pci_unregister_driver(&pcidriver);
}
module_init(kmodule_init);
module_exit(kmodule_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("iotest");
MODULE_DESCRIPTION("iotest");
MODULE_VERSION("1.0");
My pci_probe()
function is called, no errors are returned, but I/O behaves as if ports are not truly allocated.
[ 8809.201100] init
[ 8809.203209] pci_enable_device()=0
[ 8809.205237] res0=0x40101
[ 8809.206911] start=0xEF00
[ 8809.208574] end=0xEF3F
[ 8809.210230] pci_request_regions()=0
[ 8809.211868] inl()=FFFFFFFF
[ 8820.426361] exit
The I/O ports are reported to be the same as in lspci -n -vv
output:
03:0e.0 1100: 4321:9876
Subsystem: 4321:9876
Control: I/O+ Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap- 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Interrupt: pin A routed to IRQ 22
Region 0: I/O ports at ef00 [size=64]
relevant section of /proc/ioports
:
0d00-ffff : PCI Bus 0000:00
e000-efff : PCI Bus 0000:02
e000-efff : PCI Bus 0000:03
ef00-ef3f : 0000:03:0e.0
ef00-ef3f : iotest
Does anyone have any ideas why can this be happening? Am I missing something?