vxworks interrupt initialization and connection analysis

Posted by DamianTV on Mon, 24 Jun 2019 20:34:24 +0200

This blog is mainly divided into three parts:

1. Interrupt initialization

2. Connection of vxbus architecture interruption

3. Interrupt Linking of Non-vxbus Architecture


1. Initialization of interruption
Function calls:
usrInit->sysStart->palInit->palDescInit()

/* For easy viewing, the function is deleted here.
* The palDescInit() function initializes the default interrupt function
*/

void palDescInit (void)
    {
    int idx;
#ifndef _WRS_MIPS_NONCOMPLIANT_CONFIG_REG
    UINT32 config;
#endif	/* _WRS_MIPS_NONCOMPLIANT_CONFIG_REG */

    bzero((char *)&palDesc, sizeof(palDesc));

    palDesc.coreNum = 0;
    palDesc.version = "1.1";

    /* Hopefully code further down will be able to refine these */
    palDesc.iCache.present = FALSE;
    palDesc.dCache.present = FALSE;
    palDesc.l2Cache.present = FALSE;
    palDesc.l3Cache.present = FALSE;
    if (IS_KSEGM((UINT32) &palDescInit))
	{
	/* executing a mapped kernel */

	palDesc.tVec.vectorAddr = (VIRT_ADDR *)T_VEC;
	palDesc.tVec.excHandler = (VIRT_ADDR *)mmuMipsTlbVec;
	palDesc.tVec.excSize    = mmuMipsTlbVecSize;

	palDesc.xVec.vectorAddr = (VIRT_ADDR *)X_VEC;
	palDesc.xVec.excHandler = (VIRT_ADDR *)mmuMipsXtlbVec;
	palDesc.xVec.excSize    = (UINT)mmuMipsXtlbVecSize;

	palDesc.cVec.vectorAddr = (VIRT_ADDR *)C_VEC;
	palDesc.cVec.excHandler = (VIRT_ADDR*)excCacheVec;
	palDesc.cVec.excSize    = (UINT)excCacheVecSize;

	palDesc.eVec.vectorAddr = (VIRT_ADDR *)E_VEC;
	palDesc.eVec.excHandler = (VIRT_ADDR *)excNormVmVec;
	palDesc.eVec.excSize    = (UINT)excNormVmVecSize;
	}
    /* Reasonable defaults */
    palDesc.tlb.supportedPageSizes = MMU_PAGE_MASK_8K;
palDesc.tlb.mmuCacheable=MMU_R4K_STATE_INVALID_STATE >> MMU_R4K_CACHE_START;
    palDesc.tlb.mmuUncacheable = CFG_CCA_UNCACHED;
    palDesc.tlb.mmuCacheCopyback = CFG_CCA_CACHEABLE;
    palDesc.tlb.mmuCacheWritethrough = CFG_CCA_ALIAS_CACHEABLE;
    palDesc.tlb.mmuCacheCoherency =  CFG_CCA_COHERENT;
    palDesc.iCache.modes = CACHE_MODES_SUPPORTED;
    palDesc.dCache.modes = CACHE_MODES_SUPPORTED;
}

//Important Structures

#define	T_VEC		K0BASE			/* tlbmiss vector */
#define	X_VEC		(K0BASE+0x80)		/* xtlbmiss vector */
#define	C_VEC		(K1BASE+0x100)		/* cache exception vector */
#define	E_VEC		(K0BASE+0x180)		/* exception vector */

#define	R_VEC		(K1BASE+0x1fc00000)	/* reset vector */
#define BEV_VEC		(K1BASE+0x1fc00380)	/* boot exception vector */

typedef struct
    {
    char		*version;	/* PAL version string */
    int			coreNum;	/* processor number */
    MIPS_EXC_VECTOR	tVec;           /*tlbmiss interrupt*/
    MIPS_EXC_VECTOR	xVec;		/*xtlbmiss interrupt*/
    MIPS_EXC_VECTOR	cVec;		/*cache Abnormal interruption*/
    MIPS_EXC_VECTOR	eVec;		/*Exceptional interrupts, including interrupts (distinguished by exccode codes)*/
    MIPS_MMU_INFO	tlb;  		/**/
    MIPS_CACHE_INFO	iCache;        /*Instruction cache correlation*/
    MIPS_CACHE_INFO	dCache;	       /*Data cache correlation*/
    MIPS_CACHE_INFO	l2Cache;       /*Secondary cache correlation*/
    MIPS_CACHE_INFO	l3Cache;       /*Tertiary cache correlation*/
    int			mmuType;	/* CR bits 9:7 */
    BOOL		hasCP2;
    BOOL		hasWatch;
    BOOL		hasFPU;
    } MIPS_PAL_DESC;

Installation of default interrupt function:

Function calls:
usrInit->excVecInit

/*The default interrupt handler is installed here*/
STATUS excVecInit (void)
    {
    ULONG srValue;		/* status register placeholder */
	/* Load tlb and Xtlb vectors */
	vecInit (&palDesc.tVec);
	vecInit (&palDesc.xVec);

	/* Load cache exception vector */
	vecInit (&palDesc.cVec);

	/* Load normal/interrupt vector */
	vecInit (&palDesc.eVec);
    srValue = intSRGet();
    srValue &= ~SR_BEV;
    intSRSet(srValue);

    return (OK);
    }

LOCAL void vecInit
    (
    MIPS_EXC_VECTOR * vectorDesc
    )
    {
    if (vectorDesc->excSize)
	{
	/*Copy the function to the set address*/
	bcopy ((const char *) vectorDesc->excHandler,
	       (char *) vectorDesc->vectorAddr, vectorDesc->excSize);
	 /*Brush cache operation*/
	CACHE_TEXT_UPDATE (vectorDesc->vectorAddr, vectorDesc->excSize);
	}
    }
//At this point, the system's default interrupt handler is initialized.

Here we find a specific interrupt controller initialization to illustrate. (This is an abstract interrupt controller, as for what is abstract, that is, there is no specific physical hardware device corresponding to this controller, which is only a simplification at the software level, so the interrupt processing is more obvious and direct. )

Function call relationships:
usrInit->sysHwInit->vxbMipsLsnIntCtlrRegister
 When this controls its registration:
vxbMipsLsnIntCtlrRegister->vxbDevRegister->vxbNewDriver->vxbDevInitRun

/*vxbDevInitRun The function initializes the device by calling the initialization function corresponding to the device.*/
LOCAL void vxbDevInitRun
    (
    VXB_DEVICE_ID devID,
    struct vxbDevRegInfo * pDrv
    )
    {
    /* first pass */
    if (!(devID->flags & VXB_INST_INIT_DONE))
        {
        if ( pDrv->pDrvBusFuncs->devInstanceInit != NULL )
	    (*(pDrv->pDrvBusFuncs->devInstanceInit))(devID);
        devID->flags |= VXB_INST_INIT_DONE;
        }
    /* second pass */

    if (vxbInitPhase >= 2 && !(devID->flags & VXB_INST_INIT2_DONE))
        {
        if ( pDrv->pDrvBusFuncs->devInstanceInit2 != NULL )
	    (*(pDrv->pDrvBusFuncs->devInstanceInit2))(devID);
        devID->flags |= VXB_INST_INIT2_DONE;
        }
    /* third pass */

    if (vxbInitPhase >= 3 && !(devID->flags & VXB_INST_CONNECT_DONE))
        {
        if ( pDrv->pDrvBusFuncs->devInstanceConnect != NULL )
	    (*(pDrv->pDrvBusFuncs->devInstanceConnect))(devID);
        devID->flags |= VXB_INST_CONNECT_DONE;
        }
    }

Here, the pDrv - > pDrvBusFuncs - > devInstanceInit function corresponds to the lsnIntCtlrInstInit function of the controller. In the lsnIntCtlrInstInit function, the vxbMipsLsnIntCtlrInit function is called to initialize the interrupt.
LOCAL VOID vxbMipsLsnIntCtlrInit
    (
    VXB_DEVICE_ID       pInst
    )
    {
    HCF_DEVICE *pHcf = NULL;
    BOOL icw4Needed = FALSE;
    pVXB_LSN_INT_DRV_CTRL pDrvCtrl = pInst->pDrvCtrl;
/*Notice here that intCtlrHwConfGet, which is a really concrete initialization function*/
    intCtlrHwConfGet(pInst, pHcf, &(pDrvCtrl->isrHandle));
    Loongson2H_interrupt_init();
	return;
    }

The function intCtlrHwConfGet is relatively long. By deleting the following, it can be seen that the work of this function is to get the interrupt information of the device from hwconf.c, and initialize each pin into a specific structure. The members included in the structure can be seen.
STATUS intCtlrHwConfGet
    (
    VXB_DEVICE_ID               pInst,
    HCF_DEVICE *                pHcf,
    struct intCtlrHwConf *      pEntries
    )
    {
    struct intrCtlrInputs *     pCtlrInputs;  /*Interrupt control pin*/
    struct intrCtlrXBar *       pXbar;	      /*xbar Route*/
    struct intrCtlrCpu *        pCpuTable;    /*Corresponding to that cpu*/
    struct intrCtlrPriority *   pPrioTable;   /*priority*/
    struct intrCtlrTrigger *    pTrigTable;   /*Initiation mode, rising edge, high and low level, falling edge*/
    int                         tableSize;    /*Control pin array size*/	 
    int                         i;
    STATUS                      stat;
    void *                      pValue;
    void **                     ppValue;

    /* save intCtlr ID */
    pEntries->ctlrDev = pInst;
    ppValue = &pValue;
/*Gets an array of interrupt control pins*/
    stat = devResourceGet(pHcf, "input", HCF_RES_ADDR, ppValue);
    pCtlrInputs = (struct intrCtlrInputs *)pValue;
    if ( stat == OK )
        {
	/*Get the size of the interrupt control pin array*/
        stat = devResourceGet(pHcf, "inputTableSize", HCF_RES_INT, ppValue);
        tableSize = (UINT32)pValue;

        /*Traverse each element in the table and create the corresponding structure for each pin*/
        for ( i = 0 ; i < tableSize ; i++ )
            {
	    /*Create a structure for pins*/
            stat = intCtlrTableCreate(pEntries, pCtlrInputs->inputPin);

            /*Assignment of elements in the created structure, including PIN numbers (pin numbers connected to hardware), driver names, drvunit, and drvIndex */
   intCtlrTableUserSet(pEntries, pCtlrInputs->inputPin, pCtlrInputs->drvName,pCtlrInputs->drvUnit, pCtlrInputs->drvIndex);
            pCtlrInputs++;
            }
        }

/*Get the array corresponding to the priority*/
    stat = devResourceGet(pHcf, "priority", HCF_RES_ADDR, ppValue);
    pPrioTable = (struct intrCtlrPriority *)pValue;
    if ( stat == OK )
        {
	/*Get the size of the priority table*/
      stat = devResourceGet(pHcf, "priorityTableSize", HCF_RES_INT, ppValue);
        tableSize = (UINT32)pValue;
	/*Traverse all the elements in the table and fill in the values in the corresponding pin structure*/
        for ( i = 0 ; i < tableSize ; i++ )
            {
            /*Again a creates pin structure to prevent non-creation */
            stat = intCtlrTableCreate(pEntries, pPrioTable->inputPin);
            /*Fill in the priority for the structure */
            intCtlrTablePrioSet(pEntries, pPrioTable->inputPin,pPrioTable->priority);
            pPrioTable++;
            }
        }
/*The following operations are basically similar, obtaining the corresponding interrupt information and traversing it into the pin structure.*/
/*How to get the pin to start*/
    stat = devResourceGet(pHcf, "trigger", HCF_RES_ADDR, ppValue);
    pTrigTable = (struct intrCtlrTrigger *)pValue;
    if ( stat == OK )
        {
       stat = devResourceGet(pHcf, "triggerTableSize", HCF_RES_INT, ppValue);
        tableSize = (UINT32)pValue;

        for ( i = 0 ; i < tableSize ; i++ )
            {
            /* ensure pin record exists */

            stat = intCtlrTableCreate(pEntries, pTrigTable->inputPin);
            /* fill in trigger */

            intCtlrTableTrigSet(pEntries, pTrigTable->inputPin, pTrigTable->trigger);
            pTrigTable++;
            }
        }

/*Get the crossbar routing table*/
    stat = devResourceGet(pHcf, "crossBar", HCF_RES_ADDR, ppValue);
    pXbar = (struct intrCtlrXBar *)pValue;
    if ( stat == OK )
        {
        stat = devResourceGet(pHcf, "crossBarTableSize", HCF_RES_INT, ppValue);
        tableSize = (UINT32)pValue;
        for ( i = 0 ; i < tableSize ; i++ )
            {
            /* ensure pin record exists */
            stat = intCtlrTableCreate(pEntries, pXbar->inputPin);

            intCtlrTableOutputSet(pEntries, pXbar->inputPin, pXbar->outputPin);
            pXbar++;
            }
        }


    stat = devResourceGet(pHcf, "cpuRoute", HCF_RES_ADDR, ppValue);
    pCpuTable = (struct intrCtlrCpu *)pValue;

#ifdef _WRS_CONFIG_SMP
    if ( stat == OK )
        {
        stat = devResourceGet(pHcf, "cpuRouteTableSize", HCF_RES_INT, ppValue);
        tableSize = (UINT32)pValue;
        /* iterate through table */

        for ( i = 0 ; i < tableSize ; i++ )
            {
            /* ensure pin record exists */
            stat = intCtlrTableCreate(pEntries, pCpuTable->inputPin);

            /* set destination CPU for this input pin  */

            if (stat == OK)
                intCtlrTableCpuSet (pEntries, pCpuTable->inputPin,
                                    pCpuTable->cpuNum);
            pCpuTable++;
            }
        }
#endif /* _WRS_CONFIG_SMP */
    return(OK);
    }


/*Create interrupt tables*/
STATUS intCtlrTableCreate
    (
    struct intCtlrHwConf *	pInputs,
    int				inputPin
    )
    {
    int	  tblIndx = VXB_INTCTLRLIB_TBL_IDX(pInputs,inputPin);
    int	  startPin = inputPin - (inputPin % VXB_INTCTLRLIB_LOWLVL_SIZE);
    int	  i;

    if ( pInputs->pTop == NULL )
	{
	/*Assign a structure vxbIntCtlrInpTop*/
	pInputs->pTop = (struct vxbIntCtlrInpTop *)
			hwMemAlloc(sizeof(struct vxbIntCtlrInpTop));
        }

    if ( pInputs->pTop->tbl[tblIndx] == NULL )
	{
	/*Distribution structure vxbIntCtlrInput*/
        pInputs->pTop->tbl[tblIndx] = (struct vxbIntCtlrInput *)
			hwMemAlloc(sizeof(struct vxbIntCtlrInput) +
				   VXB_INTCTLRLIB_MIN_CACHE_LINE_SIZE);
	/*Alignment operation*/
	pInputs->pTop->tbl[tblIndx] = (struct vxbIntCtlrInput *)
			ROUND_UP(pInputs->pTop->tbl[tblIndx],
				 VXB_INTCTLRLIB_MIN_CACHE_LINE_SIZE);
	/*Assignment value is 0*/
	memset(pInputs->pTop->tbl[tblIndx],0,sizeof(struct vxbIntCtlrInput));

	/*Assign a default system value for interrupt function and interrupt function parameters in each pin structure */
	for ( i = 0 ; i < VXB_INTCTLRLIB_NUM_PINS(pInputs) ; i++ )
	    {
	    pInputs->pTop->tbl[tblIndx]->pins[i].isr = intCtlrStrayISR;
	    pInputs->pTop->tbl[tblIndx]->pins[i].pArg = pInputs;
	    pInputs->pTop->tbl[tblIndx]->pins[i].pinFlags = startPin + i;
	    }
	}
    return(OK);
    }

Important structure for corresponding pins:

struct intCtlrHwConf
    {
    VXB_DEVICE_ID	  ctlrDev;	  /* VXB_DEVICE_ID of int ctlr */
    struct vxbIntCtlrInpTop * pTop;       /* top-level table of entries */
    struct vxbLock         vxbIntCtlrLibLock;
    };

struct vxbIntCtlrInpTop
    {
    struct vxbIntCtlrInpTop * pNext;          /* not implemented */
    struct vxbIntCtlrInput *  tbl[VXB_INTCTLRLIB_TOPLVL_SIZE];
    UINT32                    reserved;
    };
#define VXB_INTCTLRLIB_TOPLVL_SIZE    496

struct vxbIntCtlrInput
    {
    struct vxbIntCtlrPin      pins[VXB_INTCTLRLIB_LOWLVL_SIZE];
    };
/*The final operation is 2^x, which is defined as 8.*/
#define VXB_INTCTLRLIB_LOWLVL_SIZE_POW 3 
#define VXB_INTCTLRLIB_LOWLVL_SIZE   ( 1<< VXB_INTCTLRLIB_LOWLVL_SIZE_POW)

struct vxbIntCtlrPin
    {
    struct intCtlrMoreDrvName * pMoreNames;
    char *                      drvName;
    int                         drvUnit;
    int                         intIndex;

    void                        (*isr)(void * pArg, int inputPin);
    void *                      pArg;
    int                         pinFlags;
    UINT32                      pinPriority;
    UINT32                      pinOutput;
    UINT32                      pinCpu;
    int				reserved [2];
    };
This is equivalent to creating a two-level table, the first level is 496 size, the second level corresponds to each element of the first level, the size is 8, where the creation and initialization of interrupts is completed.


2. Interrupted connection
The initialization of vxbus architecture in vxWorks can be divided into three stages. The first and second stages are usually to initialize the device, and the third stage is to connect and enable interrupts. The example here is a bit special. This is the interrupt hooking and enabling in the second stage. On the other hand, there is no specific code for naming, which is for convenience.


Function call relationships:
usrRoot->sysClkInit->sysClkConnect->sysHwInit2->vxbDevInit->vxbDevInitInternal->vxbDevIterate->vxbDevInit2Helper->

LOCAL STATUS vxbDevInit2Helper
    (
    struct vxbDev * pInst,
    void * pArg
    )
    {
    if ( pInst->pDriver->pDrvBusFuncs->devInstanceInit2 == NULL )
        return(OK);
	/*The second stage initialization function is called here.*/
    (*pInst->pDriver->pDrvBusFuncs->devInstanceInit2)(pInst);

    pInst->flags |= VXB_INST_INIT2_DONE;

    return(OK);
    }
//The second stage initialization function called here corresponds to the following functions:
LOCAL VOID lsnIntCtlrInstInit2
    (
    VXB_DEVICE_ID       pInst
    )
    {
     vxbIntConnect(pInst, 0, vxbMipsLsnIntCtrlIsr, (void*)pInst);
    vxbIntEnable(pInst, 0, vxbMipsLsnIntCtrlIsr, (void*)pInst);
    return;
    }
/*As you can see, all you have to do here is hook interrupts and enablements.*/
Here the function call relationship of the hook function is interrupted:
vxbIntConnect->vxbDevIterate->vxbIntCtlrMatch->vxbIntCtlrConnect

Look directly at the function: Familiar with the process can be:

STATUS vxbIntConnect
    (
    struct vxbDev * pDev,       /* Device Information */
    int             index,      /* index of interrupt vector */
    VOIDFUNCPTR     pIsr,       /* ISR */
    void *          pArg        /* parameter */
    )
    {
    VXB_ACCESS_INTERRUPT_INFO   accessIntrInfo;
    struct vxbintCtlrMgmt info;

    VXB_ASSERT(pDev!=NULL, ERROR)

    info.found = FALSE;
    info.pIntCtlr = NULL;
    info.inputPin = 0;
    info.pDev = pDev;
    info.index = index;
    info.pIsr = pIsr;
    info.pArg = pArg;
    /*This matches all instantiated devices and info s to be registered at once*/
    vxbDevIterate(vxbIntCtlrMatch, &info, VXB_ITERATE_INSTANCES);

    if ( info.found == TRUE )
        return(OK);
    return (vxbDevControl (pDev, (pVXB_DEVCTL_HDR)&accessIntrInfo));
    }


LOCAL STATUS vxbIntCtlrMatch
    (
    struct vxbDev * pInst,
    void * pArg
    )
    {
    struct vxbintCtlrMgmt * pInfo = (struct vxbintCtlrMgmt *)pArg;
    FUNCPTR   func;
    STATUS    stat;
    struct plbIntrEntry * pIntrEntry;
    int			inputPin;
    struct pIntCtlrTable * pICTab;
    struct plbIntCtlrTable * pICTab2;
    int		x;
    int		y;
    struct plbIntCtlrEntry * pEnt;
    /*In this case, the interrupt hook function of the matched device will be called. In other words, the interrupt hook function of the corresponding interrupt controller will be called for different interrupt controllers.*/
    func = vxbDevMethodGet(pInst, DEVMETHOD_CALL(vxbIntCtlrConnect));
    stat = (*func)(pInst, pInfo->pDev, pInfo->index, pInfo->pIsr, pInfo->pArg, &inputPin);

    if ( stat != OK )
      return(OK);

    pInfo->found = TRUE;

    return(OK);
    }

The corresponding interrupt hook function here is:
LOCAL STATUS vxbMipsLsnIntCtlrDevIsrConnect
    (
    VXB_DEVICE_ID	pIntCtlr,
    VXB_DEVICE_ID	pDev,
    int			indx,
    void		(*pIsr)(void * pArg),
    void              *	pArg,
    int               *	pInputPin
    )
    {
    pVXB_LSN_INT_DRV_CTRL pDrvCtrl = pIntCtlr->pDrvCtrl;
    int                 inputPin = ERROR;
    struct intCtlrHwConf * pIsrHandle = NULL;
  
    inputPin = intCtlrPinFind (pDev, indx, pIntCtlr, &pDrvCtrl->isrHandle);

    pIsrHandle = &(pDrvCtrl->isrHandle);
    
    /*Call the intCtlrISRAdd function here, which will actually hook up the user's interrupt function*/
    if (intCtlrISRAdd(pIsrHandle, inputPin, pIsr, pArg) == ERROR)
        return ERROR;

    *pInputPin = inputPin;
    return OK;
    }


STATUS intCtlrISRAdd
    (
    struct intCtlrHwConf *	pEntries,
    int				inputPin,
    void 			(*isr),
    void *			pArg
    )
    {
    struct intCtlrISRChainEntry * pChain;
    struct intCtlrISRChainEntry * pChain2;
    void *			  installedIsr;

    /*Here, make sure that the interrupt table is created */
    intCtlrTableCreate(pEntries, inputPin);

    /*Here, two structures are created and initialized as user interrupts for use when hooking interrupts*/
    pChain = (struct intCtlrISRChainEntry *)hwMemAlloc(sizeof(*pChain));

    pChain2 = (struct intCtlrISRChainEntry *)hwMemAlloc(sizeof(*pChain));

    pChain->isr = isr;
    pChain->pArg = pArg;

    /*Gets the interrupt function currently hooked in the current table. If the function intCtlrStrayISR indicates that it has been initialized as the default interrupt function,
It only needs to be replaced by the user's interrupt function. If the function intCtlrChainISR is used, it means that at least one user interrupt function has been connected (multiple interrupt functions can be connected to an interrupt pin).
If it is empty, it means no initialization, then use pChain2 to save the interrupt function to be hooked, assign it to pChain, and fill it in on the corresponding pin.*/
     installedIsr = intCtlrTableIsrGet(pEntries, inputPin);
    if ( installedIsr == (void *)intCtlrStrayISR )
	{
	intCtlrTableFill(pEntries, inputPin, pChain->isr, pChain->pArg);
	}
    else if ( installedIsr == (void *)intCtlrChainISR )
        {
	pChain->pNext = (struct intCtlrISRChainEntry *)intCtlrTableArgGet(pEntries, inputPin);
	intCtlrTableFill(pEntries, inputPin, intCtlrChainISR, pChain);
	}
    else
        {
	/* create chain, add original entry and the new one */

	pChain2->flags = intCtlrTableFlagsGet(pEntries, inputPin);

	pChain2->pArg = intCtlrTableArgGet(pEntries, inputPin);

	pChain2->isr = installedIsr;

	pChain->pNext = pChain2;
	pChain2->pNext = NULL;

	intCtlrTableFill(pEntries, inputPin, intCtlrChainISR, pChain);
	}
    return(OK);
    }
struct intCtlrISRChainEntry
    {
    struct intCtlrISRChainEntry * pNext;
    void			  (*isr)(void * pArg, int inputPin);
    void *			  pArg;
    UINT32			  flags;
    };


Hu ~~, the interruption of the forehead connection here is completed. Of course, this is only a connection of functions belonging to vxbus architecture in vxWorks system, but it contains most interrupts.

3. Connection of non-vxbus interrupts
Let's talk about the connection of interrupt functions that are not vxbus structures.
It is not the interrupt function of vxbus architecture that uses intConnect function to connect. Say less nonsense. Look at the function:

STATUS intConnect
    (
    VOIDFUNCPTR * vector,	/* interrupt vector to attach to     */
    VOIDFUNCPTR   routine,	/* routine to be called              */
    int           parameter	/* parameter to be passed to routine */
    )
    {
    /*First of all, three judgments are made, which represent three interrupt connections. The first one is _func_isrConnect.
      This is an isrobject n interrupt hook, which has not been thoroughly analyzed yet, but it must open the macro definition of # INCLUDE_ISR_OBJECT.
      It does not run here; intArchConnect is the function of the forehead connection of the structure interrupt, an interrupt registration and an interrupt, which of course can not be executed here;
   _func_vxbIntConnect This function is the focus of this time. This function is assigned in vxb Legacy IntInit.
    _func_vxbIntConnect = vxbLegacyIntConnect,Look at this initialization function*/

    if (_func_isrConnect != NULL)
	if (_func_isrConnect (vector, routine, parameter) == OK)
	    return (OK);


    if (_func_vxbIntConnect != NULL)
        if (_func_vxbIntConnect(vector, routine, parameter) == OK)
            return (OK);

    return (intArchConnect (vector, (VOIDFUNCPTR) routine, 
                            (int) parameter));        
    }

void vxbLegacyIntInit()
    {
    VXB_DEVICE_ID devID;
    struct plbIntrEntry *       pIntrInfo;

    /*Apply for a legacy device (legacy here means not a vxbus architecture device or a legacy device)*/
    devID = vxbDevStructAlloc(WAIT_FOREVER);
    
    /*Initialization devices, mainly names and bus numbers, are used to match the interrupt controller later.*/
    devID->pName = "legacy";
    devID->pParentBus = pPlbDev->u.pSubordinateBus;
    devID->busID = VXB_BUSID_PLB;
    devID->pRegBase[0] = (void *)1;


    pIntrInfo = (struct plbIntrEntry *)hwMemAlloc(sizeof(*pIntrInfo)); 

    devID->pIntrInfo = pIntrInfo;

    /*Declare that the device has been registered in the system*/
    if ( vxbDeviceAnnounce(devID) != OK )
	{
	vxbDevStructFree(devID);
        return;
	}

    vxbLegacyIntDevice = devID;
    _func_vxbIntConnect = vxbLegacyIntConnect;
    _func_vxbIntDisconnect = vxbLegacyIntDisconnect;
    _func_vxbIntEnable = vxbLegacyIntEnable;
    _func_vxbIntDisable = vxbLegacyIntDisable;
    }

LOCAL STATUS vxbLegacyIntConnect
    (
    VOIDFUNCPTR * vector,       /* interrupt vector to attach to     */
    VOIDFUNCPTR   routine,      /* routine to be called              */
    int           parameter     /* parameter to be passed to routine */
    )
    {
    /*Call the vxbIntConnect function here to register interrupts in the interrupt table of the vxbus architecture*/
    if ((vxbIntConnect(vxbLegacyIntDevice,(int)vector,routine,
           (void *)parameter)) != OK)
        return ERROR;
    
    return(vxbIntEnable(vxbLegacyIntDevice,(int)vector,routine,
           (void *)parameter));
    }

And then it's the same connection as the vxbus interrupt above:
vxbIntConnect->vxbDevIterate->vxbIntCtlrMatch->vxbDevMethodGet->vxbIntCtlrConnect->vxbMipsLsnIntCtlrDevIsrConnect

OK... Here the interrupt hook of the non-vxbus structure is also completed.

Here I would like to point out that:
Func = vxbDevMethodGet (pInst, DEVMETHOD_CALL) (vxbIntCtlrConnect); this function calls the vxbIntCtlrConnect function for all devices registered in the system and instantiated, but there is also a function that ensures that the interrupt function is registered in the corresponding interrupt controller, input = intCtrPind (Depv, Finindx, pIntCtlr,&pvCtrl-> Handle), which An intCtlrPinFind function can only find the corresponding pin structure in the corresponding interrupt controller. This also ensures that it will be registered in the corresponding pin structure.


ok ~~, the analysis is here first, if there is anything wrong, please leave a message...




Topics: less