'How is a PCI / PCIe BAR size determined?

I know that the base address register (BAR) in PCI configuration space defines the start location of a PCI address, but how does the size of this region get established?

Surely this is a property of the hardware since only it knows how far into its address space it can deal. However, I cannot seem to see a BAR size field in the PCI configuration structure.



Solution 1:[1]

First of all, the BAR size must be a power of two (e.g., 1 KiB, 2 MiB), and each area must be aligned in memory such that the lower log2(size) bits of the base address are always zero. For example, assume that an endpoint has a 4 KiB memory area, which gives an address range of 0-0xfff. The host may remap the start of this area to f.x. 0x1000 or 0xabcd000 by writing to the BAR register, but not to 0x1080 or 0xabcd100.

When the BAR register is written, the endpoint will ignore LSBs and always return zeros on read. Thus writing 0xffffffff to the register and then reading back the value indicates the size of the area. For the 4 KiB example this returns 0xfffff00X (the lower four bits are reserved, see specification). To determine the size:

  • Clear the lower four bits to zeros (0xfffff000)
  • Invert all 32 bits (0xfff)
  • Add one to the result (0x1000 = 4096 bytes)

This works for 64-bit areas as well. The value of the next base address register forms the MSBs of the base address. This is described in section 6.2.5.1 of the PCI 3.0 specification.

Solution 2:[2]

Found the answer at OSDev Wiki:

"To determine the amount of address space needed by a PCI device, you must save the original value of the BAR, write a value of all 1's to the register, then read it back."

Solution 3:[3]

PCIe Device can have either Type-0 (Endpoints) or Type-1( RC or Switches or Bridges) Configuration Space.

--Type-0 device can have total of 6 BARs while Type-1 can have only 2 BARs.

--BAR gives the information about address space needed by the device.

--Each BAR is 32 bit , out of which first 4 bit 3:0 are always Read Only.

-- 2^(Position of last R/W bits from least significant bit) = Address window required by particular BAR.

How to know the address window or size of the region represneted by any BAR :

1) Initially Read any BAR( Suppose BAR0 in our case) , we got value 32'h0000_000F. (Remember : last 4 bits read only!! ).

2) Write all 1's to BAR0.

3) Read again BAR0 and Suppose we got value 32'hFFFF_000F. So bit position 16 is the least significant R/W bit. So address space required by BAR0 will be 2^16.

Solution 4:[4]

As other people have said, you can get size by writing all 1's to BAR, here is what Linux kernel does:

/**
 * __pci_read_base - Read a PCI BAR
 * @dev: the PCI device
 * @type: type of the BAR
 * @res: resource buffer to be filled in
 * @pos: BAR position in the config space
 *
 * Returns 1 if the BAR is 64-bit, or 0 if 32-bit.
 */
int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
            struct resource *res, unsigned int pos)
{
    u32 l = 0, sz = 0, mask;
    u64 l64, sz64, mask64;
    u16 orig_cmd;
    struct pci_bus_region region, inverted_region;

    mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
    ...
    pci_read_config_dword(dev, pos, &l);
    pci_write_config_dword(dev, pos, l | mask);
    pci_read_config_dword(dev, pos, &sz);
    pci_write_config_dword(dev, pos, l);
    ...
}

When standard PCI BAR probe, mask is ~0, aka all 1's. so it writes all 1's to BAR then read the size from BAR.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 pc3e
Solution 2 JeffV
Solution 3 prl
Solution 4 Chen Li