[U-Boot] PCIe bridge pci memory limit register problem

Hello, I am a first time poster so here goes:
u-boot 1.3.1 rc2 (I checked the code in 1.3.4 rc2 and it is still there)
The problem is that when enumeration is taking place when a bridge is discovered it goes through pciauto_prescan_setup_bridge() which takes the current bus_lower value from the region struct and places it in the bridge pci_memory_base register. The next process is to scan behind the bridge and then to go through pciauto_postscan_setup_bridge() to figure out what needs to be put into the pci_memory_limit register.
However, the algorithm for setting the limit register does not take into account that if nothing is found behind the bridge requiring memory then bus_lower has not changed, thus when it sets the register to bus_lower - 1 this makes the limit register less than the base register.
I am able to duplicate this rather easily on our ATCA carrier with 8347 processor connected to a PLX 8111 pci2pcie bridge that in turn is connected to a PLX 8524 PCIe switch that connects to our 4 PCIe x4 AMC slots. I only populate the first AMC slot with a card that requires 8MB of space and after u-boot enumeration you cannot display the memory at the address from the AMC's BAR register. This is because the other bridge segments have all programmed the limit registers incorrectly. I put code in that checks to see if anything is behind the bridge with memory and if not then zero out the base and limit registers otherwise use the bus_lower - 1 value and everything works.
So, here are the changes I did here local and am thinking that if this looks ok, then I will also need to add this to the pre-fetch logic as well.
void pciauto_postscan_setup_bridge(struct pci_controller *hose,
pci_dev_t dev, int sub_bus)
{
struct pci_region *pci_mem = hose->pci_mem;
struct pci_region *pci_prefetch = hose->pci_prefetch;
struct pci_region *pci_io = hose->pci_io;
unsigned int bridge_mem_base = 0;
/* Configure bus number registers */
pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS,
sub_bus - hose->first_busno);
if (pci_mem) {
/* Round memory allocator to 1MB boundary */
pciauto_region_align(pci_mem, 0x100000);
+ /* danny, 15aug08
+ * read the the bus_lower value that was placed in the
+ * PCI_MEMORY_BASE register during pciauto_prescan_setup_bridge
+ * and check to see if anything behind it consumed memory
+ */
+ pci_hose_read_config_word(hose, dev, PCI_MEMORY_BASE, &bridge_mem_base)
;
+
+ if((bridge_mem_base >> 16) == ((pci_mem->bus_lower & 0xfff00000) >> 16)
) {
+ /* danny, 15aug08
+ * since no memory was allocated behind this bridge
+ * then don't try to program the base and limit
+ * otherwise the -1 will make the upper limit value
+ * less than the base causing memory routing problems
+ */
+ pci_hose_write_config_dword(hose, dev, PCI_MEMORY_BASE, 0);
+ } else {
+ /* danny, 15aug08
+ * else set the limit -1 behind the next address
+ * boundry
+ */
+ pci_hose_write_config_word(hose, dev, PCI_MEMORY_LIMIT,
+ (pci_mem->bus_lower - 1) >> 16);
+ }
+ }
void pciauto_postscan_setup_bridge(struct pci_controller *hose,
pci_dev_t dev, int sub_bus)
{
struct pci_region *pci_mem = hose->pci_mem;
struct pci_region *pci_prefetch = hose->pci_prefetch;
struct pci_region *pci_io = hose->pci_io;
/* Configure bus number registers */
pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS,
sub_bus - hose->first_busno);
if (pci_mem) {
/* Round memory allocator to 1MB boundary */
pciauto_region_align(pci_mem, 0x100000);
- pci_hose_write_config_word(hose, dev, PCI_MEMORY_LIMIT,
(pci_mem->bus_lower-1) >> 16);
}
------------------------------------------------------ Interphase - Designed to Perform, Designed to Last (R) Danny Waldron - Technical Support Phone - 214.654.5244 ------------------------------------------------------
Disc Golf - the wind is my friend...or....every putt is an adventure for this Texas Chain Ranger!

Dear Danny,
In message D2CCC86D6128D043B074E2A927250D0694090D@EXMAIL.interphase.iphase.com you wrote:
So, here are the changes I did here local and am thinking that if this looks ok, then I will also need to add this to the pre-fetch logic as well.
void pciauto_postscan_setup_bridge(struct pci_controller *hose,
pci_dev_t dev, int sub_bus)
{
struct pci_region *pci_mem = hose->pci_mem; struct pci_region *pci_prefetch = hose->pci_prefetch; struct pci_region *pci_io = hose->pci_io; unsigned int bridge_mem_base = 0;
Why do you add allthese empty lines ???
/* Configure bus number registers */ pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, sub_bus - hose->first_busno); if (pci_mem) { /* Round memory allocator to 1MB boundary */ pciauto_region_align(pci_mem, 0x100000);
/* danny, 15aug08
* read the the bus_lower value that was placed in the
* PCI_MEMORY_BASE register during pciauto_prescan_setup_bridge
* and check to see if anything behind it consumed memory
*/
pci_hose_read_config_word(hose, dev, PCI_MEMORY_BASE,
&bridge_mem_base)
^^^^^^^^^^^^^^^^^^^
;
if((bridge_mem_base >> 16) == ((pci_mem->bus_lower &
0xfff00000) >> 16)
^^^^^^^^^^^^^^^^^^^^
Line wrapping.
If you want to discuss code changes, then please submit a regular patch. Please see http://www.denx.de/wiki/U-Boot/Patches for instructions.
Best regards,
Wolfgang Denk

The extra lines and line wrap are a result of my cut and paste, won't happen again.
Any comments on the logic change?
------------------------------------------------------ Interphase - Designed to Perform, Designed to Last (R) Danny Waldron - Technical Support Phone - 214.654.5244 ------------------------------------------------------ Disc Golf - the wind is my friend...or....every putt is an adventure for this Texas Chain Ranger! -----Original Message----- From: wd@denx.de [mailto:wd@denx.de] Sent: Friday, August 15, 2008 4:55 PM To: Danny Waldron Cc: u-boot@lists.denx.de Subject: Re: [U-Boot] PCIe bridge pci memory limit register problem
Dear Danny,
In message D2CCC86D6128D043B074E2A927250D0694090D@EXMAIL.interphase.iphase.com you wrote:
So, here are the changes I did here local and am thinking that if this looks ok, then I will also need to add this to the pre-fetch logic as well.
void pciauto_postscan_setup_bridge(struct pci_controller *hose,
pci_dev_t dev, int sub_bus)
{
struct pci_region *pci_mem = hose->pci_mem; struct pci_region *pci_prefetch = hose->pci_prefetch; struct pci_region *pci_io = hose->pci_io; unsigned int bridge_mem_base = 0;
Why do you add allthese empty lines ???
/* Configure bus number registers */ pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, sub_bus - hose->first_busno); if (pci_mem) { /* Round memory allocator to 1MB boundary */ pciauto_region_align(pci_mem, 0x100000);
/* danny, 15aug08
* read the the bus_lower value that was placed in the
* PCI_MEMORY_BASE register during
pciauto_prescan_setup_bridge
* and check to see if anything behind it consumed memory
*/
pci_hose_read_config_word(hose, dev, PCI_MEMORY_BASE,
&bridge_mem_base)
^^^^^^^^^^^^^^^^^^^
;
if((bridge_mem_base >> 16) == ((pci_mem->bus_lower &
0xfff00000) >> 16)
^^^^^^^^^^^^^^^^^^^^
Line wrapping.
If you want to discuss code changes, then please submit a regular patch. Please see http://www.denx.de/wiki/U-Boot/Patches for instructions.
Best regards,
Wolfgang Denk
participants (2)
-
Danny Waldron
-
Wolfgang Denk