PCI device probe in Linux sysfs always returns is_prefetchable and is_64 as zero
On a CentOS 6 Linux system have a FPGA based PCIe device configured with a single bar set set as 64-bit and prefetchable. lspci
reported that the bar was 64-bit, prefetchable
as expected:
$ lspci -d 10ee: -v
01:00.0 Memory controller: Xilinx Corporation Device 7024
Subsystem: Xilinx Corporation Device 0007
Flags: bus master, fast devsel, latency 0
Memory at f0100000 (64-bit, prefetchable) [size=1M]
Capabilities: <access denied>
When attempted to use libpciacess to report the device information using the following:
rc = pci_device_probe (device);
if (rc == 0)
{
printf ("domain=%04x bus=%02x dev=%02x func=%02x\n vendor_id=%04x device_id=%04x subvendor_id=%04x subdevice_id=%04x\n",
device->domain, device->bus, device->dev, device->func,
device->vendor_id, device->device_id, device->subvendor_id, device->subvendor_id);
for (unsigned bar_index = 0; bar_index < 6; bar_index++)
{
const struct pci_mem_region *const region = &device->regions[bar_index];
if (region->size > 0)
{
printf (" bar[%u] base_addr=%" PRIx64 " size=%" PRIx64 " is_IO=%u is_prefetchable=%u is_64=%u\n",
bar_index, region->base_addr, region->size, region->is_IO, region->is_prefetchable, region->is_64);
}
}
}
Then the is_prefetchable
is_64
fields were both incorrectly reported as zero:
domain=0000 bus=01 dev=00 func=00
vendor_id=10ee device_id=7024 subvendor_id=10ee subdevice_id=10ee
bar[0] base_addr=f0100000 size=100000 is_IO=0 is_prefetchable=0 is_64=0
The pciaccess.h defines the struct pci_mem_region
following fields as single bits:
unsigned is_IO:1;
unsigned is_prefetchable:1;
unsigned is_64:1;
The issue is that the pci_device_linux_sysfs_probe
function in src/linux_sysfs.c attempts to store the result of a bit-wise and on the flags read from the resource file in the structure fields which are single bit. Therefore, is_64
and is_prefetchable
always end up as zero:
dev->regions[i].is_IO = (flags & 0x01);
dev->regions[i].is_64 = (flags & 0x04);
dev->regions[i].is_prefetchable = (flags & 0x08);
A fix is to test the masked flag
value against zero:
dev->regions[i].is_IO = (flags & 0x01) != 0;
dev->regions[i].is_64 = (flags & 0x04) != 0;
dev->regions[i].is_prefetchable = (flags & 0x08) != 0;
With that change is_IO
and is_prefetchable
were reported with the expected values:
domain=0000 bus=01 dev=00 func=00
vendor_id=10ee device_id=7024 subvendor_id=10ee subdevice_id=10ee
bar[0] base_addr=f0100000 size=100000 is_IO=0 is_prefetchable=1 is_64=1