FIX: CEPC Ethernet Boot Loader (Eboot.bin) Appears to Halt During PCI Bus Enumeration (252670)



The information in this article applies to:

  • Microsoft Windows CE Platform Builder 2.12

This article was previously published under Q252670

SYMPTOMS

On a Windows CE PC-based (CEPC) hardware platform, the Ethernet boot loader (Eboot.bin) scans for devices on the Peripheral Component Interconnect (PCI) bus and presents a comprehensive inventory of the devices found. However, certain hardware implementations cause Eboot.bin to appear to stop responding (halt or hang) during this scanning process.

CAUSE

Certain host-PCI hardware bridge implementations (a comprehensive list of such devices has not been developed) demonstrate a bus address aliasing problem whereby they respond positively to queries with devices that actually reside on a lower-numbered bus. This problem is apparent when you scan bus numbers greater than some hardware-assumed maximum number. The result is a slow-down of the PCI bus enumeration process. Because phantom devices are being found, the enumeration process takes a long time (giving the appearance that the system has halted). Also, detecting phantom devices on these buses can cause other side effects.

RESOLUTION

The solution to the problem is to modify the Pciconfig.c file to first establish a maximum PCI bus number present in the system. The Pciconfig.c file does this by scanning PCI bus 0 (zero) for the highest sub-bus number. Once the PCI enumeration loop finishes scanning this highest-numbered bus, the process ends.

Included below is the entire contents of the Pciconfig.c file for the Windows CE Platform Builder version 2.12 Eboot.bin file. Make a backup copy of the existing Pciconfig.c file on your computer (Wince212\Platform\Cepc\Eboot\Pciconfig.c), replace the contents of the original with what follows, and then rebuild the Eboot.bin image:

//------------------------------------------------------------------------------
// 
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//  Copyright (c) 1995-1999  Microsoft Corporation
//  
//------------------------------------------------------------------------------
#include <windows.h>
#include <ethdbg.h>
#include <nkintr.h>
#include <halether.h>
#include <bootarg.h>

#include "eboot.h"
#include "ethdown.h"
#include <ceddk.h>
#include <pc.h>
#include <pci.h>

#undef TEXT
#define TEXT                                     
#define NKDbgPrintfW    EdbgOutputDebugString

const LPSTR BaseClass[] = {
    TEXT("PRE_20"),
    TEXT("MASS_STORAGE_CTLR"),
    TEXT("NETWORK_CTLR"),
    TEXT("DISPLAY_CTLR"),
    TEXT("MULTIMEDIA_DEV"),
    TEXT("MEMORY_CTLR"),
    TEXT("BRIDGE_DEV"),
    TEXT("SIMPLE_COMMS_CTLR"),
    TEXT("BASE_SYSTEM_DEV"),
    TEXT("INPUT_DEV"),
    TEXT("DOCKING_STATION"),
    TEXT("PROCESSOR"),
    TEXT("SERIAL_BUS_CTLR")
};


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
VOID 
PrintConfig(
    int bus,
    int device,
    int function,
    PPCI_COMMON_CONFIG pCfg
    )
{
    DWORD i;

    RETAILMSG(1, (TEXT("========================================================\r\n")));
    RETAILMSG(1, (TEXT(" Bus, Device, Function = %d, %d, %d\r\n"), bus, device, function));
    RETAILMSG(1, (TEXT(" Vendor ID, Device ID  = 0x%H, 0x%H\r\n"), pCfg->VendorID, pCfg->DeviceID));
    RETAILMSG(1, (TEXT(" Base Class, Subclass  = %d, %d => %s\r\n"), pCfg->BaseClass, pCfg->SubClass, BaseClass[pCfg->BaseClass]));

    if ((pCfg->HeaderType & 0x7F) == PCI_DEVICE_TYPE) {

        RETAILMSG(1, (TEXT(" Interrupt             = %d\r\n"), pCfg->u.type0.InterruptLine));
        
        for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) {
            if (pCfg->u.type0.BaseAddresses[i]) {
                if (pCfg->u.type0.BaseAddresses[i] & 1) {
                    RETAILMSG(1, (TEXT(" BaseAddress[%d]        = 0x%x (I/O)\r\n"),
                        i, pCfg->u.type0.BaseAddresses[i] & 0xFFFFFFFC));
                } else {
                    RETAILMSG(1, (TEXT(" BaseAddress[%d]        = 0x%x (Memory)\r\n"),
                        i, pCfg->u.type0.BaseAddresses[i] & 0xFFFFFFE0));
                }
            }
        }
    
    } 
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BYTE
GetMaxBusNumber()
{
    PCI_SLOT_NUMBER     slotNumber;
    PCI_COMMON_CONFIG   pciConfig;
    int                 bus, device, function;
    int                 length;
    BYTE                bMaxBus = 0;

    // 
    // Scan bus 0 for bridges. They'll tell us the number of buses.
    // 
    bus = 0;
    
    for (device = 0; device < PCI_MAX_DEVICES; device++) {
        slotNumber.u.bits.DeviceNumber = device;

        for (function = 0; function < PCI_MAX_FUNCTION; function++) {
            slotNumber.u.bits.FunctionNumber = function;

            length = PCIGetBusDataByOffset(bus, slotNumber.u.AsULONG,
                                   &pciConfig, 0, sizeof(pciConfig));

            if (length == 0 || pciConfig.VendorID == 0xFFFF) 
                break;

            if (pciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV && pciConfig.SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) {
                if (pciConfig.u.type1.SubordinateBusNumber > bMaxBus) {
                    bMaxBus = pciConfig.u.type1.SubordinateBusNumber;
                }
            }

            if (function == 0 && !(pciConfig.HeaderType & 0x80)) 
                break;
            
        }
        if (length == 0)
            break;
    }

    return bMaxBus;
}


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#define IGNOREBRIDGES 1		// Set to 0 to print out basic bridge info.

BOOL
PrintPCIConfig()
{
    PCI_SLOT_NUMBER     slotNumber;
    PCI_COMMON_CONFIG   pciConfig;
    int                 bus, device, function;
    int                 length;
    int                 maxbus;

    maxbus = (int) GetMaxBusNumber();

    RETAILMSG(1, (TEXT("PCI Device Configurations (%d PCI bus(es) present)...\r\n"), maxbus + 1));

    for (bus = 0; bus <= maxbus; bus++) {
        
        for (device = 0; device < PCI_MAX_DEVICES; device++) {
            slotNumber.u.bits.DeviceNumber = device;

            for (function = 0; function < PCI_MAX_FUNCTION; function++) {
                slotNumber.u.bits.FunctionNumber = function;

                length = PCIGetBusDataByOffset(bus, slotNumber.u.AsULONG,
                                       &pciConfig, 0, sizeof(pciConfig));

                if (length == 0 || pciConfig.VendorID == 0xFFFF) 
                    break;

#if IGNOREBRIDGES
                if (pciConfig.BaseClass == 6)
                    // Ignore bridges
                    break;
#endif

                PrintConfig(bus, device, function, &pciConfig);
                
                if (function == 0 && !(pciConfig.HeaderType & 0x80)) 
                    break;
                
            }
            if (length == 0)
                break;
        }

        if (length == 0 && device == 0)
            break;
    }

    RETAILMSG(1, (TEXT("========================================================\r\n")));
    return TRUE;
}

				

STATUS

Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.

Modification Type:MinorLast Reviewed:12/26/2003
Keywords:kbbug kbETK212fix kbfix kbOSWinCE212fix KB252670