Hi,
brain wrote:As i understood it, you can just write a new page-aligned address to the BAR and it will remap them, as i did not see anywhere in the spec i read that these registers were readonly?
First determine if the BAR is for physical memory or IO ports, and (for MMIO) if it's a 64-bit BAR or not and if the area is prefetchable.
The lowest address bits of the BAR are hard-wired to zero to indicate both the alignment restrictions and the size of the area. You should write 0xFFFFFFFF (or 0xFFFFFFFFFFFFFFFF for 64-bit) to the BAR and then read it back to determine the minimum alignment required. The size of the area is the same as the minimum alignment required. For example, if you can only set the highest 16 address bits of a 32-bit BAR, then the area has a 64 KiB minimum alignment and a 64 KiB size. Once you know the alignment and size, you can allocate a suitable area in the physical address space and then set the BAR properly.
Also note that you also have to setup any PCI bridges - there's no point telling a device to accept accesses within a certain area if the bridge/s above it aren't setup to forward accesses in that area towards the device. For each bridge (starting from the host controller), determine how much space you need for all of the bridge's children (for IO ports, for prefetchable MMIO, and for non-prefetchable MMIO); then allocate a range of IO ports and 2 different areas of the physical address space for the bridge; then split those larger areas into pieces for the bridge's children.
For example, if there's one bridge and 2 devices, like this;
Code: Select all
bridge 2
|__device 3 (one BAR for a 64 KiB area of non-prefetchable, one BAR for a 256 MiB area of prefetchable)
|__device 4 (one BAR for a 64 KiB area of non-prefetchable, one BAR for a 16 IO ports)
|__device 5 (one BAR for a 512 MiB area of prefetchable, one BAR for a 8 IO ports)
Then you'd check the children to determine you need:
- a 128 KiB area for non-prefetchable MMIO (64 KiB for device 3 and 64 KiB for device 4)
- a 1 GiB area for prefetchable MMIO (256 MiB for device 3, 512 MiB for device 5, and 256 MiB unused due to rounding up)
- 32 IO ports (16 IO ports for device 4, 8 IO ports for device 5, 8 IO ports unused due to rounding up)
Now imagine that bridge2 is underneath bridge1:
Code: Select all
bridge 1
|__device 1 (one BAR for a 4 KiB area of non-prefetchable)
|__device 2 (one BAR for a 128 KiB area of non-prefetchable, one BAR for a 16 IO ports)
|__bridge 2 (128 KiB of non-prefetchable, 1 GiB of prefetchable and 32 IO ports)
|__device 3 (one BAR for a 64 KiB area of non-prefetchable, one BAR for a 256 MiB area of prefetchable)
|__device 4 (one BAR for a 64 KiB area of non-prefetchable, one BAR for a 16 IO ports)
|__device 5 (one BAR for a 512 MiB area of prefetchable, one BAR for a 8 IO ports)
For bridge 1 you need:
- a 512 KiB area for non-prefetchable MMIO (4 KiB for device 1, 128 KiB for device 2, 128 KiB for bridge 2 and 252 KiB unused due to rounding up)
- a 1 GiB area for prefetchable MMIO (1 GiB for bridge 2)
- 64 IO ports (16 IO ports for device 2, 32 IO ports for bridge 2 and 16 IO ports unused due to rounding up)
Now that you know what you need, you allocate the IO space and 2 pieces of the physical address space. Lets pretend that the 64 IO ports you allocated are IO ports 0xD000 to 0xD03F, the first area (for non-prefetchable MMIO) is from 0xC0000000 to 0xC007FFFF
and the second area (for prefetchable MMIO) is from 0x80000000 to 0xBFFFFFFF. You might end up with IO space looking like this:
Code: Select all
0xD000 to 0xD03F accepted by bridge 1 and forwarded to its secondary bus
0xD000 to 0xD00F accepted by device 1
0xD010 to 0xD01F unused
0xD020 to 0xD03F accepted by bridge 2 and forwarded to its secondary bus
0xD020 to 0xD02F accepted by device 4
0xD030 to 0xD037 accepted by device 5
0xD038 to 0xD03f unused
The physical address space might look like this (showing areas used by PCI only):
Code: Select all
0x80000000 to 0xBFFFFFFF accepted by bridge 1 and forwarded to its secondary bus
0x80000000 to 0xBFFFFFFF accepted by bridge 2 and forwarded to its secondary bus
0x80000000 to 0x8FFFFFFF accepted by device 3
0x90000000 to 0x9FFFFFFF unused
0xA0000000 to 0xBFFFFFFF accepted by device 4
0xC0000000 to 0xC007FFFF accepted by bridge 1 and forwarded to its secondary bus
0xC0000000 to 0xC0000FFF accepted by device 1
0xC0001000 to 0xC003FFFF unused
0xC0040000 to 0xC005FFFF accepted by device 2
0xC0060000 to 0xC007FFFF accepted by bridge 2 and forwarded to its secondary bus
0xC0060000 to 0xC006FFFF accepted by device 3
0xC0070000 to 0xC007FFFF accepted by device 4
Cheers,
Brendan