[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Base Addresses, PCI Spec 2.2, Section 6.2.5



|<><><><><> Original message from David Shema  <><><><><>
|I'm new to PCI.  After thoroughly reading the PCI 2.2 spec, it is
|painfully obvious that section 6.2.5 (and subparagraphs) are NOT clear
|in describing the usage of the Base Address Registers -- BAR0 through
|BAR5.
|
|There is no definitive part of the specification clearly stating that
|once the size of a particular device's address space is determined by
|the using system, and after the using system assigns the device to a
|specific block in the overall system memory map, that the data
|originally found in the device's Base Address Area is overwritten by the
|system software with the actual starting address of the block assigned
|to the device by the system software.

This is pretty much outside of the scope of the PCI specification.
There is no requirement that system software size and initialize the
BAR's in any particular fashion.

|Specifically, the implementation note in paragraph 6.2.5.1, pg 204,
|"Sizing a 32-bit base address register example" is in error, and needs
|to be corrected.
|
|According to the example, the device at power-up, or after reset,
|contains in its Base Address Register location(s) information to allow
|the system software to determine the size of the block of memory (or I/O
|space) required by the device, and information as to whether the device
|is intended for memory space, I/O space, whether the block is
|prefetchable, and if the device is a 32-bit or 64-bit device.
|
|Again, according to the example, the host software reads the information
|in the BAR "and saves the original value of the Base Address Register".
|Next, the host sofware writes ones to the register, then performs a
|read.  The lower four-bits of the data read back are translated to
|zeros, then the host software calculates the two's-complement of the
|value read from the BAR in question.  This yields the size of the memory
|or I/O block required by the device.  At this point, the host now knows
|how large a block of space to allocate in the host memory map.  I assume
|at this point the host actually makes the assignment of a specific
|address space for this device.
|
|Continuing with the example in the spec, "the original value in the Base
|Address Register is restored before enabling decode in the command
|register of the device."

This algorithm maybe used after address assignments have been made
and will preserve any prior address assignments.  Address assignments
need not be static.

|So, we read a value, saved it, performed a two's-complement of the value
|to determine block size, then simply wrote the original value back into
|the BAR.  At no time, did the host software write the ACTUAL PHYSICAL
|BASE ADDRESS allocated by the host software into the BASE ADDRESS
|REGISTER of the device.  Therefore, the device does NOT know which set
|of actual physical addresses to respond to within the system.

This is true, but if the an address had previously been assigned
to the BAR, you can find the address of the BAR's decoded block
by directly reading the BAR and the size of the block by using
the sizing algorithm.

|Nowhere within the spec is there a clear, unambiguous statement that the
|BAR initially contains the block size required by the device, 

Because this is not a requirement.

|                                                              and once
|the using system determines where the device is to reside in the
|memory-I/O map of the system, that the initial SIZING data in the BAR is
|REPLACED with the ACTUAL PHYSICAL
|ADDRESS assigned by the using system to the device.  

This is not the way the BAR's work.  The sizing algorithm works independent
of the programming of the BAR.

Let assume that you have a 1Mb memory BAR.  It would be implemented 
with 12 R/W bits and 20 read zero bits.

    RRRR.RRRR.RRRR.0000.0000.0000.0000.0000

To size BAR you:

	1) save away the current value.

		XXXX.XXXX.XXXX.0000.0000.0000.0000.0000

	2) write all ones to the BAR

		this sets it to

		    1111.1111.1111.0000.0000.0000.0000.0000

	3) read the BAR value back

	4) restore the saved value

		XXXX.XXXX.XXXX.0000.0000.0000.0000.0000

	5) compute the size from the value that was read back.

		if (val & 1)
		    size = (~val | 3) + 1;		/* I/O space */
		else
		    size = (~val | 0xF) + 1;		/* memory space */

		size is

		val 		-> 1111.1111.1111.0000.0000.0000.0000.0000 
		~val 		-> 0000.0000.0000.1111.1111.1111.1111.1111
		~val | 0xF 	-> 0000.0000.0000.1111.1111.1111.1111.1111
		size 		-> 0000.0000.0001.0000.0000.0000.0000.0000

		or 1Mb

|                                                     The only example
|given to demonstrate this sequence is in error, and tells us that the
|ACTUAL PHYSICAL ADDRESS is NOT written into the BAR, but rather, the
|initial sizing data is restored to the BAR.

The example is illustrating something more general than I beleive you
think it is.  The sizing algorithm can be used many times at startup and
not just during address assignment, thus the need to restore the original
value.  Hardware should not treat writes of all ones specially either
since the device may actually be assigned an address with all of the
bits all ones.

|My recommendation is that the spec be clarified with respect to the
|actual usage of the BARs, and that the example be corrected to show that
|the host software writes the ACTUAL PHYSICAL BASE ADDRESS assigned to
|the device into the BAR (instead of the original stored value), after
|reading the initial sizing information, and mapping of all devices in
|the system.

Thomas J. Merritt
tjm@codegen.com
1-415-834-9111