www.pudn.com > BSP_pcPentium.rar > sysEl3c90xEnd.c


/* sysEl3c90xEnd.c - system configuration module for el3c90xEnd driver */

/* Copyright 1984-2001 Wind River Systems, Inc. */

/*
modification history
--------------------
01h,07mar02,pai  Specify pciIntConnect() as the default driver interrupt
                 connect routine (SPR# 73501).
01g,28nov01,pai  Added code to determine whether 32-bit NPF memory decoder is
                 implemented.
01f,18oct01,pai  Updated documentation and routines for new device discovery
                 algorithm (SPR# 35716).
01e,11oct01,bur  Added more device ids to el3c90xBrds[] for different 
		 versions of 3COM 3c90x network cards.
01d,01oct01,pai  Removed INCLUDE_MMU_BASIC conditional-compilation block.
                 Fixed function comment-headers.
01c,11sep01,hdn  replaced "irq + EXT_INTERRUPT_BASE" with INT_NUM_GET(irq)
01b,12mar99, jkf renamed boardResource and pciResources to dev specific.
01a,12mar99, cn  created.
*/

/*
DESCRIPTION
This is the WRS-supplied configuration module for the VxWorks
el3c90xEnd (elPci) END driver.  It has routines for initializing
device resources and provides BSP-specific el3c90xEnd driver routines
for 3Com EtherLink and Fast EtherLink PCI network interface cards.
 
The number of supported devices that can be configured for a particular
system is finite and is specified by the EL_3C90X_MAX_DEV configuration
constant found is this file.  This configuration constant, and the data
structures using it, can be modified in this file for specific
implementations.
*/


#if defined(INCLUDE_EL_3C90X_END)

/* includes */

#include "end.h"
#include "drv/end/el3c90xEnd.h"


/* defines */

/* specify the maximum number of physical devices to configure */

#define EL_3C90X_MAX_DEV        (8)

#define THREECOM_PCI_VENDOR_ID   (0x10b7)   /* 3COM PCI vendor ID */

/* BSP specific 3Com ethernet device type constants */

#define TYPE_BOOMERANG_10BT           (1)   /* 3COM 3c900-TPO */
#define TYPE_BOOMERANG_10BT_COMBO     (2)   /* 3COM 3c900-COMBO */
#define TYPE_BOOMERANG_10_100BT       (3)   /* 3COM 3c905-TX */
#define TYPE_BOOMERANG_100BT4         (4)   /* 3COM 3c905-T4 */
#define TYPE_CYCLONE_10BT             (5)   /* 3COM 3c900B-TPO */
#define TYPE_CYCLONE_10BT_COMBO       (6)   /* 3COM 3c900B-COMBO */
#define TYPE_CYCLONE_10_100BT         (7)   /* 3COM 3c905B-TX */
#define TYPE_CYCLONE_10_100BT4        (8)   /* 3COM 3c905B-T4 */
#define TYPE_CYCLONE_10_100FX         (9)   /* 3COM 3c980-TX */
#define TYPE_CYCLONE_10_100BT_SERV   (10)   /* 3COM 3c980-TX */
#define TYPE_CYCLONE_10FL            (11)   /* 3COM 3c900B-FL */
#define TYPE_CYCLONE_10_100_COMBO    (12)   /* 3COM 3c905B-COMBO */
#define TYPE_KRAKATOA_10BT_TPC       (13)   /* 3COM 3c900B-TPC */
#define TYPE_TORNADO_10_100BT        (14)   /* 3COM 3c920-TX */
#define TYPE_TORNADO_10_100BT_SERV   (15)   /* 3COM 3c980-TX */
#define TYPE_TORNADO_HOMECONNECT     (16)   /* 3COM Home Connect */
#define TYPE_HURRICANE_SOHO100TX     (17)   /* 3COM Soho */

#define EL_3C90X_END_FLAGS      (0)
#define EL_3C90X_BUFF_MTPLR     (NONE)


/* imports */

IMPORT STATUS     sysMmuMapAdd (void * address, UINT len,
                                UINT initialStateMask,
                                UINT initialState);

IMPORT END_OBJ *  el3c90xEndLoad (char *);
IMPORT FUNCPTR    el3c90xIntConnectRtn;


/* locals */

LOCAL UINT32 etherLinkUnits = 0;     /* the number of physical units found */

/* This string table stores English descriptions of supported devices.
 * TYPE_XXX device type constants index the table to get descriptions.
 */

LOCAL const char * elDescription [] =
    {
    "3COM 3c90X Fast Etherlink Endhanced Network Driver."
    "3COM 3c900-TPO Etherlink Endhanced Network Driver."
    "3COM 3c900-COMBO Etherlink Endhanced Network Driver."
    "3COM 3c905-TX Etherlink Endhanced Network Driver."
    "3COM 3c905-T4 Etherlink Endhanced Network Driver."
    "3COM 3c900B-TPO Etherlink Endhanced Network Driver."
    "3COM 3c900B-COMBO Etherlink Endhanced Network Driver."
    "3COM 3c905B-TX Etherlink Endhanced Network Driver."
    "3COM 3c905B-T4 Etherlink Endhanced Network Driver."
    "3COM 3c980-TX Etherlink Endhanced Network Driver."
    "3COM 3c980-TX Etherlink Endhanced Network Driver."
    "3COM 3c900B-FL Etherlink Endhanced Network Driver."
    "3COM 3c905B-COMBO Etherlink Endhanced Network Driver."
    "3COM 3c900B-TPC Etherlink Endhanced Network Driver."
    "3COM 3c920-TX Etherlink Endhanced Network Driver."
    "3COM 3c980-TX Etherlink Endhanced Network Driver."
    "3COM 3c90X Home Connect Etherlink Endhanced Network Driver."
    "3COM 3c90X Soho Etherlink Endhanced Network Driver."
    };

/*
 * This array defines the board-specific PCI resources.  Each table entry
 * stores this information for specific physical devices found on the system
 * bus.  There is a unique END unit associated with each unique physical
 * device recorded in this table.  The END unit number is equivalent to an
 * index into this table.
 */

LOCAL PCI_BOARD_RESOURCE elPciResources [EL_3C90X_MAX_DEV] =
    {
    {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
    {NONE, NONE, NONE, NONE, NONE, NONE}, NULL
    },

    {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
    {NONE, NONE, NONE, NONE, NONE, NONE}, NULL
    },

    {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
    {NONE, NONE, NONE, NONE, NONE, NONE}, NULL
    },

    {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
    {NONE, NONE, NONE, NONE, NONE, NONE}, NULL
    },

    {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
    {NONE, NONE, NONE, NONE, NONE, NONE}, NULL
    },

    {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
    {NONE, NONE, NONE, NONE, NONE, NONE}, NULL
    },

    {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
    {NONE, NONE, NONE, NONE, NONE, NONE}, NULL
    },

    {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
    {NONE, NONE, NONE, NONE, NONE, NONE}, NULL
    }
    };


/* forward declarations */

LOCAL UINT32 sys3comDevToType (UINT32, UINT32, UINT8);
LOCAL UINT32 sys3comMmioGet (UINT32, UINT32, UINT32);



/*******************************************************************************
*
* sysEl3c90xPciInit - initialize a 3c90x PCI ethernet device
*
* This routine performs basic PCI initialization for 3c90x PCI ethernet
* devices supported by the el3c90xEnd END driver.  Parameters to this
* routine specify a PCI function, including PCI ID registers, to
* initialize.  If supported, the device memory and I/O addresses are
* mapped into the local CPU address space and an internal board-specific
* PCI resources table is updated with information on the board type,
* memory address, and IO address.
*
* CAVEATS
* This routine must be performed prior to MMU initialization, usrMmuInit().
* If the number of supported 3c90x physical device instances installed
* on the PCI bus exceeds EL_3C90X_MAX_DEV, then the extra devices will not be
* initialized in this routine.
*
* RETURNS:
* OK, or ERROR if the specified device is not supported, or if
* the device could not be mapped into the local CPU memory space.
*/
STATUS sysEl3c90xPciInit
    (
    UINT32  pciBus,      /* store a PCI bus number */
    UINT32  pciDevice,   /* store a PCI device number */
    UINT32  pciFunc,     /* store a PCI function number */
    UINT32  vendorId,    /* store a PCI vendor ID */
    UINT32  deviceId,    /* store a PCI device ID */
    UINT8   revisionId   /* store a PCI revision ID */
    )
    {
    UINT32  boardType;   /* store a BSP-specific board type constant */

    UINT32  ioBase;      /* IO base address (BAR 0) */
    UINT32  memIo32;     /* memory-mapped IO address (BAR 1) */
    UINT8   irq;         /* interrupt line number (IRQ) for device */


    /* number of physical units exceeded the number supported ? */

    if (etherLinkUnits >= EL_3C90X_MAX_DEV)
        {
        return (ERROR);
        }

    if ((boardType = sys3comDevToType (vendorId, deviceId, revisionId))
        == BOARD_TYPE_UNKNOWN)
        {
        return (ERROR);
        }


    pciConfigInLong  (pciBus, pciDevice, pciFunc,
                      PCI_CFG_BASE_ADDRESS_0, &ioBase);

    ioBase &= PCI_IOBASE_MASK;


    /* supported 3Com devices may or may not implement memory mapped IO */

    if ((memIo32 = sys3comMmioGet (pciBus, pciDevice, pciFunc)) != NONE)
        {
        memIo32 &= PCI_MEMBASE_MASK;

        /* map a 4Kb 32-bit non-prefetchable memory address decoder */

        if (sysMmuMapAdd ((void *)(memIo32 & PCI_DEV_MMU_MSK),
           PCI_DEV_ADRS_SIZE, VM_STATE_MASK_FOR_ALL, VM_STATE_FOR_PCI) == ERROR)
            {
            return (ERROR);
            }
        }


    /* get the interrupt line number (IRQ) for the device */

    pciConfigInByte (pciBus, pciDevice, pciFunc,
                     PCI_CFG_DEV_INT_LINE, &irq);


    /* update the board-specific resource table */

    elPciResources[etherLinkUnits].bar[0]     = ioBase;
    elPciResources[etherLinkUnits].bar[1]     = memIo32;
    elPciResources[etherLinkUnits].irq        = irq;
    elPciResources[etherLinkUnits].irqvec     = INT_NUM_GET (irq);

    elPciResources[etherLinkUnits].vendorID   = vendorId;
    elPciResources[etherLinkUnits].deviceID   = deviceId;
    elPciResources[etherLinkUnits].revisionID = revisionId;
    elPciResources[etherLinkUnits].boardType  = boardType;


    /* enable mapped memory and IO decoders */

    pciConfigOutWord (pciBus, pciDevice, pciFunc, PCI_CFG_COMMAND,
                      PCI_CMD_MEM_ENABLE | PCI_CMD_IO_ENABLE |
                      PCI_CMD_MASTER_ENABLE);

    /* disable sleep mode */

    pciConfigOutByte (pciBus, pciDevice, pciFunc, PCI_CFG_MODE,
                      SLEEP_MODE_DIS);


    ++etherLinkUnits;  /* increment number of units initialized */

    /* Bind the driver-specific PCI interrupt connection routine. */

    el3c90xIntConnectRtn = (FUNCPTR) pciIntConnect;

    return (OK);
    }

/*******************************************************************************
*
* sysEl3c90xIntEnable - enable 3c90x ethernet device interrupts
*
* This routine enables el3c90x interrupts.  This may involve operations on
* interrupt control hardware.
*
* RETURNS: OK or ERROR for invalid arguments.
*/
STATUS sysEl3c90xIntEnable
    (
    int    level        /* level number */
    )
    {
    return (sysIntEnablePIC (level));
    }

/*******************************************************************************
*
* sysEl3c90xIntDisable - disable 3c90x ethernet device interrupts
*
* This routine disables el3c90x interrupts.  This may involve operations on
* interrupt control hardware.
*
* RETURNS: OK or ERROR for invalid arguments.
*/
STATUS sysEl3c90xIntDisable
    (
    int    level        /* level number */
    )
    {
    return (sysIntDisablePIC (level));
    }

/******************************************************************************
*
* sysEl3c90xEndLoad - construct a load string and load an el3c90xEnd device
*
* This routine will be invoked by the MUX for the purpose of loading an
* el3c90xEnd (elPci) device with initial parameters.  This routine is
* constructed as an interface wrapper for the driver load routine.  Thus,
* the arguments and return values are consistent with any xxxEndLoad()
* routine defined for an END driver and the MUX API.
*
* INTERNAL
* The muxDevLoad() operation calls this routine twice.  A zero length
*  parameter string indicates that this is the first time
* through this routine.  The driver load routine should return the
* driver name in .
*
* On the second pass though this routine, the initialization parameter
* string is constructed.  Note that on the second pass, the 
* consists of a colon-delimeted END device unit number and rudimentary
* initialization string (often empty) constructed from entries in the
* BSP END Device Table such that:
*
*      = ":"
*
* In the process of building the rest of , the prepended unit
* number must be preserved and passed to the driver load routine.  The
*  portion mentioned above is discarded,
* but future versions of this routine may use it.
*
* The complete el3c90xEnd driver load string has format:
*
*     ::::::
*     ::::
*
* RETURNS: An END object pointer, or NULL on error, or 0 and the name of the
* device if the  was NULL.
*
* SEE ALSO: el3c90xEndLoad()
*/
END_OBJ * sysEl3c90xEndLoad
    (
    char *    pParamStr,   /* pointer to initialization parameter string */
    void *    unused       /* unused optional argument */
    )
    {
    END_OBJ * pEnd;
    char      paramStr [END_INIT_STR_MAX];

    static const char * const paramTemplate = 
        "%d:0x%x:0x%x:0x%x:%d:%d:-1:-1:-1:0x%x:0x%x:%p";

    /* point to 3c90x board resource table */

    PCI_BOARD_RESOURCE * const pRsrc = elPciResources;


    if (strlen (pParamStr) == 0)
        {
        /* PASS (1)
         * The driver load routine returns the driver name in .
         */

        pEnd = el3c90xEndLoad (pParamStr);
        }
    else
        {
        /* PASS (2)
         * The END  number is prepended to .  Construct
         * the rest of the driver load string based on physical devices
         * discovered in sysEl3c90xPciInit().  When this routine is called
         * to process a particular END  number, use the END  as
         * an index into the PCI "resources" table to build the driver
         * parameter string.
         */

        int    typeIdx;   /* index to the string resource table */

        char * holder  = NULL;
        int    endUnit = atoi (strtok_r (pParamStr, ":", &holder));


        /* is there a PCI resource associated with this END unit ? */

        if (endUnit >= etherLinkUnits)
            {
            return NULL;
            }


        /* construct an index into the string resource table */

        typeIdx = (pRsrc[endUnit].boardType);


        /* finish off the initialization parameter string */

        sprintf (paramStr, paramTemplate,
                 endUnit,                   /* END unit number */
                 pRsrc[endUnit].bar[1],     /* memory-mapped IO base */
                 pRsrc[endUnit].bar[0],     /* IO address space base */
                 PCI2DRAM_BASE_ADRS,        /* host PCI mem. base */
                 pRsrc[endUnit].irqvec,     /* IRQ vector */
                 pRsrc[endUnit].irq,        /* IRQ number */
                 EL_3C90X_END_FLAGS,        /* flags for type */
                 EL_3C90X_BUFF_MTPLR,       /* buff alloc factor */
                 &elDescription[typeIdx]    /* device description */
                );

        if ((pEnd = el3c90xEndLoad (paramStr)) == (END_OBJ *) NULL)
            {
            printf ("Error el3c90xEndLoad:  failed to load driver.\n");
            }
        }

    return (pEnd);
    }

/*******************************************************************************
*
* sys3comDevToType - convert PCI Vendor and Device IDs to a device type
*
* Given , , and  values read from PCI Vendor
* and Device ID registers in PCI configuration space, this routine will
* attempt to map the IDs to an 3c90x device type value defined in this file.
*
* RETURNS:
* A board type value which will be one of
*
* .IP
* TYPE_BOOMERANG_10BT
* .IP
* TYPE_BOOMERANG_10BT_COMBO
* .IP
* TYPE_BOOMERANG_10_100BT
* .IP
* TYPE_BOOMERANG_100BT4
* .IP
* TYPE_CYCLONE_10BT
* .IP
* TYPE_CYCLONE_10BT_COMBO
* .IP
* TYPE_CYCLONE_10_100BT
* .IP
* TYPE_CYCLONE_10_100BT4
* .IP
* TYPE_CYCLONE_10_100FX
* .IP
* TYPE_CYCLONE_10_100BT_SERV
* .IP
* TYPE_CYCLONE_10FL
* .IP
* TYPE_CYCLONE_10_100_COMBO
* .IP
* TYPE_KRAKATOA_10BT_TPC
* .IP
* TYPE_TORNADO_10_100BT
* .IP
* TYPE_TORNADO_10_100BT_SERV
* .IP
* TYPE_TORNADO_HOMECONNECT
* .IP
* TYPE_HURRICANE_SOHO100TX
* .LP
*
* BOARD_TYPE_UNKNOWN will be returned if the Device ID does not map to
* a supported board type.
*
* NOMANUAL
*/
LOCAL UINT32 sys3comDevToType
    (
    UINT32 vendorId,    /* specifies a PCI Vendor ID value */
    UINT32 deviceId,    /* specifies a PCI Device ID value */
    UINT8  revisionId   /* specifies a PCI Revision ID values */
    )
    {
    /* At the moment, we are only supporting vendor 3Com */

    if (vendorId == THREECOM_PCI_VENDOR_ID)
        {
        switch (deviceId)
            {
            case TC_DEVICEID_BOOMERANG_10BT:
                return TYPE_BOOMERANG_10BT;

            case TC_DEVICEID_BOOMERANG_10BT_COMBO:
                return TYPE_BOOMERANG_10BT_COMBO;

            case TC_DEVICEID_BOOMERANG_10_100BT:
                return TYPE_BOOMERANG_10_100BT;

            case TC_DEVICEID_BOOMERANG_100BT4:
                return TYPE_BOOMERANG_100BT4;

            case TC_DEVICEID_CYCLONE_10BT:
                return TYPE_CYCLONE_10BT;

            case TC_DEVICEID_CYCLONE_10BT_COMBO:
                return TYPE_CYCLONE_10BT_COMBO;

            case TC_DEVICEID_CYCLONE_10_100BT:
                return TYPE_CYCLONE_10_100BT;

            case TC_DEVICEID_CYCLONE_10_100BT4:
                return TYPE_CYCLONE_10_100BT4;

            case TC_DEVICEID_CYCLONE_10_100FX:
                return TYPE_CYCLONE_10_100FX;

            case TC_DEVICEID_CYCLONE_10_100BT_SERV:
                return TYPE_CYCLONE_10_100BT_SERV;

            case TC_DEVICEID_CYCLONE_10FL:
                return TYPE_CYCLONE_10FL;

            case TC_DEVICEID_CYCLONE_10_100_COMBO:
                return TYPE_CYCLONE_10_100_COMBO;

            case TC_DEVICEID_KRAKATOA_10BT_TPC:
                return TYPE_KRAKATOA_10BT_TPC;

            case TC_DEVICEID_TORNADO_10_100BT:
                return TYPE_TORNADO_10_100BT;

            case TC_DEVICEID_TORNADO_10_100BT_SERV:
                return TYPE_TORNADO_10_100BT_SERV;

            case TC_DEVICEID_TORNADO_HOMECONNECT:
                return TYPE_TORNADO_HOMECONNECT;

            case TC_DEVICEID_HURRICANE_SOHO100TX:
                return TYPE_HURRICANE_SOHO100TX;

            default:
                break;
            }
        }

    return (BOARD_TYPE_UNKNOWN);
    }

/*******************************************************************************
*
* sys3comMmioGet - get a 3Com EtherLink memory mapped IO decoder value
*
* This routine gets the memory mapped IO decoder, if any, for a 3Com
* EtherLink or Fast EtherLink PCI network controller specified by PCI
* bus, device, and function numbers.  Many of the WRS supported PCI
* ethernet devices support both memory mapped IO and IO address space
* decoders.  This assumption cannot be made in the case of supported
* 3Com EtherLink PCI devices.  If a memory mapped IO decoder is
* implemented, assume it is in BAR 1.
*
* RETURNS: The 32-bit memory decoder value read from BAR 1, else NONE.
*
* NOMANUAL
*/
LOCAL UINT32 sys3comMmioGet
    (
    UINT32  pciBus,         /* store a PCI bus number */
    UINT32  pciDevice,      /* store a PCI device number */
    UINT32  pciFunc         /* store a PCI function number */
    )
    {
    UINT16  cmdSave;        /* saves 16-bit PCI command word register */
    UINT32  barSave;        /* saves 32-bit PCI base address register 1 */
    UINT32  barRead;        /* memory decoder (if any) read from BAR 1 */

    UINT32  retVal = NONE;  /* assume the BAR is not implemented */


    /* disable PCI device memory decode */

    pciConfigInWord (pciBus, pciDevice, pciFunc,
                     PCI_CFG_COMMAND, &cmdSave);

    pciConfigOutWord (pciBus, pciDevice, pciFunc,
                      PCI_CFG_COMMAND, (cmdSave & (~PCI_CMD_MEM_ENABLE)));


    /* save the BAR and determine whether it specifies a memory decoder */

    pciConfigInLong (pciBus, pciDevice, pciFunc,
                     PCI_CFG_BASE_ADDRESS_1, &barSave);

    pciConfigOutLong (pciBus, pciDevice, pciFunc,
                      PCI_CFG_BASE_ADDRESS_1, 0xffffffff);

    pciConfigInLong (pciBus, pciDevice, pciFunc,
                     PCI_CFG_BASE_ADDRESS_1, &barRead);


    /* this BAR specifies a memory decoder? */

    if (barRead != 0)
        {
        retVal = barSave;

        pciConfigOutLong (pciBus, pciDevice, pciFunc,
                          PCI_CFG_BASE_ADDRESS_1, barSave);
        }


    /* re-enable PCI device memory decode */

    pciConfigOutWord (pciBus, pciDevice, pciFunc,
                      PCI_CFG_COMMAND, cmdSave);


    return (retVal);
    }

#endif /* INCLUDE_EL_3C90X_END */