original files of m241

This commit is contained in:
neelimap
2026-07-30 11:19:44 +05:30
parent 170c2b3f3a
commit afc7070c1f
12254 changed files with 7655111 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
# Makefile - makefile for bsp/src/drv/CAN
#
# Copyright (c) 2001, 2004-2005, 2007-2008, 2012-2013 Wind River Systems, Inc.
#
# The right to copy, distribute, modify or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
# modification history
# --------------------
# 01p,15apr13,hcl remove compilation support in SMP. (WIND00395068)
# 01o,30nov12,wqi Added TIam335x dcan support
# 01n,30dec08,x_f Added mpc5121e mscan support
# 01m,20aug08,j_z Added support for tolapai
# 01l,16jul08,pee VSB.
# 01k,13jul08,pee VSB adaptation.
# 01j,09nov07,mdo Add bsptoucan and bspflexcan libraries
# 01i,18jun05,tpw Refactor doc build settings.
# 01h,15may05,tpw Update documentation build settings.
# 01g,18apr05,lsg removed building adlink, biscayne and tahoe amanda board
# objects
# 01f,29mar05,dat update for B6, using LIB_BASE_NAME
# 01f,07oct04,lsg remove ADDED_CFLAGS.
# 01e,17sep04,lsg modify ref gen file list
# 01d,30aug04,mjk updated to build documentation.
# 01c,25jun04,bjn Make motMsCan.o and mpc5200Can.o PPC603 specific
# 01b,26feb04,bjn Added mpc5200 mscan support
# 01a,20dec01,dnb created
#
# DESCRIPTION
# This file contains the makefile rules for building the vx library
#
TGT_DIR=$(WIND_BASE)/target
LIB_BASE_NAME=wnCAN
include $(TGT_DIR)/h/make/defs.library
EXTRA_INCLUDE=-I$(WIND_BASE)/target/h/
OBJS_PPC32 = motMsCan.o mpc5200Can.o mpc5121eCan.o
OBJS_PENTIUM4 = can_fifo.o icp_can.o
OBJS_COMMON = wnCAN.o can_api.o canBoard.o canController.o canFixedLL.o \
esd_pc104_200.o esd_pci_200.o hcan2.o i82527.o am335XCan.o TiDcan.o \
msmcan.o sja1000.o wncanDevIO.o
OBJS = $(OBJS_COMMON) $(OBJS_$(CPU))
ifndef _WRS_CONFIG_COMPONENT_CAN
all : clean
endif
ifdef _WRS_CONFIG_SMP
all : rclean
endif
DOC_FILES = can_api.c \
motMsCan.c \
../../../config/comps/src/bsptoucan.c \
../../../config/comps/src/bspflexcan.c
include $(TGT_DIR)/h/make/rules.library
CC_OPTIM=$(CC_OPTIM_DRIVER)
include $(WIND_BASE)/vx_components/$(COMP_CAN)/config/defs.docs
File diff suppressed because it is too large Load Diff
+731
View File
@@ -0,0 +1,731 @@
/* am335xCan.c - implementation of Board Interface for the AM335X */
/*
* Copyright (c) 2012, 2014 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
13aug14,hcl fix prevent NULL pointer issue. (VXW6-83297)
01a,30nov12,wqi written.
*/
/*
DESCRIPTION
This file contains the functions that provide a board-level interface
to the AM335X processor.
*/
/* includes */
#include <vxWorks.h>
#include <errnoLib.h>
#include <intLib.h>
#include <iv.h>
#include <sysLib.h>
#include <dllLib.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <CAN/wnCAN.h>
#include <CAN/canController.h>
#include <CAN/canBoard.h>
#include <CAN/TiDCan.h>
#include <CAN/TiDCanOffsets.h>
#include <CAN/private/am335xCan.h>
#define SYS_DCAN_DEBUG
#ifdef SYS_DCAN_DEBUG
#include <logLib.h>
#endif
/* debug macros */
#ifdef SYS_DCAN_DEBUG
#define DCAN_DRV_DEBUG_OFF 0x00000000
#define DCAN_DRV_DEBUG_RX 0x00000001
#define DCAN_DRV_DEBUG_TX 0x00000002
#define DCAN_DRV_DEBUG_ISR 0x00000004
#define DCAN_DRV_DEBUG_INIT 0x00000010
#define DCAN_DRV_DEBUG_IOCTL 0x00000020
#define DCAN_DRV_DEBUG_ENTRY 0x00000040
#define DCAN_DRV_DEBUG_ERR 0x00000080
#define DCAN_DRV_DEBUG_ISR_TX 0x00000100
#define DCAN_DRV_DEBUG_ISR_RX 0x00000200
#define DCAN_DRV_DEBUG_ASSERT 0x80000000
IMPORT FUNCPTR _func_logMsg;
LOCAL UINT32 tiDcanDebug = (DCAN_DRV_DEBUG_ERR);
#define DRV_ASSERT(arg) \
do \
{ \
if (tiDcanDebug & DCAN_DRV_DEBUG_ASSERT) \
{ \
if (!(arg)) \
{ \
if (_func_logMsg != NULL) \
_func_logMsg ("Assertion failed: %s, %s, %d\n", \
(_Vx_usr_arg_t) #arg, \
(_Vx_usr_arg_t)__FILE__, \
(_Vx_usr_arg_t)__LINE__,4,5,6); \
} \
} \
} \
while (FALSE)
#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \
do \
{ \
if (tiDcanDebug & (FLG)) \
{ \
if (_func_logMsg != NULL) \
_func_logMsg (X0, (_Vx_usr_arg_t)X1, \
(_Vx_usr_arg_t)X2, \
(_Vx_usr_arg_t)X3, \
(_Vx_usr_arg_t)X4, \
(_Vx_usr_arg_t)X5, \
(_Vx_usr_arg_t)X6); \
} \
} \
while (FALSE)
#else /* SYS_DCAN_DEBUG */
#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) do {} while (FALSE)
#define DRV_ASSERT(arg) ((void)0)
#endif /* SYS_DCAN_DEBUG */
/* globals */
/* locals */
LOCAL const char am335xCan_deviceName[] ="AM335X DCAN";
LOCAL DL_LIST *pFifoDataList = NULL;
/* external reference */
IMPORT STATUS CAN_DEVICE_establishLinks (WNCAN_DEVICE * pDev,
WNCAN_BoardType brdType,
WNCAN_ControllerType ctrlType);
IMPORT void tiDcan_ISR (struct WNCAN_Device * pDev);
/****************************************************************************
*
* am335xCan_cfg - configure AM335X device specific data
*
* This route configures the AM335X device specific datas.
*
* RETURNS: OR or ERROR
*
* ERRNO: N/A
*/
LOCAL STATUS am335xCan_cfg
(
am335x_mscan_instance * pDCANboardCfg,
UINT32 ctrlNdx
)
{
struct WNCAN_Device * pDev = NULL;
struct WNCAN_Controller * pCtrlr = NULL;
struct dcanDev * pDCANdev = NULL;
STATUS status = OK;
DRV_LOG (DCAN_DRV_DEBUG_ENTRY, "am335xCan_cfg ctrlNdx %d, AM335X %d"
", freq %d, Reg Base 0x%08x\n",
ctrlNdx, pDCANboardCfg[ctrlNdx].DCANcontrollerId,
pDCANboardCfg[ctrlNdx].freq,
(int)pDCANboardCfg[ctrlNdx].pDevBaseAddr,
0, 0);
pDev = am335x_cfgGet_canDevicePtr (BRD_NDX, ctrlNdx);
pCtrlr = am335x_cfgGet_canControllerPtr (BRD_NDX, ctrlNdx);
if ((pDev == NULL) || (pCtrlr == NULL))
goto error;
pDCANdev = (DCAN_DEV *)pCtrlr->csData;
pDCANdev->pDCANregs = pDCANboardCfg[ctrlNdx].pDevBaseAddr;
pDCANdev->intMsg = pDCANboardCfg[ctrlNdx].intNummsg;
pDCANdev->intSys = pDCANboardCfg[ctrlNdx].intNumsys;
pDCANdev->intErr = pDCANboardCfg[ctrlNdx].intNumerr;
pDCANdev->rxChl = pDCANboardCfg[ctrlNdx].rxChl;
pDCANdev->txChl = pDCANboardCfg[ctrlNdx].txChl;
pDCANdev->taChl = pDCANboardCfg[ctrlNdx].taChl;
pDCANdev->cfgOptions = pDCANboardCfg[ctrlNdx].cfgOptions;
pDCANdev->freq = pDCANboardCfg[ctrlNdx].freq;
pDev->pCtrl->brp = pDCANboardCfg[ctrlNdx].brp;
pDev->pCtrl->sjw = pDCANboardCfg[ctrlNdx].sjw;
pDev->pCtrl->tseg1 = pDCANboardCfg[ctrlNdx].tseg1;
pDev->pCtrl->tseg2 = pDCANboardCfg[ctrlNdx].tseg2;
pDev->pCtrl->samples = FALSE; /* FALSE means one sample per bit */
/* connect the interrupt to the controller */
status = intConnect ((VOIDFUNCPTR *)pDCANboardCfg[ctrlNdx].intNummsg,
(VOIDFUNCPTR) tiDcan_ISR, (int)pDev);
if (status != OK)
goto error;
status = intConnect ((VOIDFUNCPTR *)pDCANboardCfg[ctrlNdx].intNumsys,
(VOIDFUNCPTR) tiDcan_ISR, (int)pDev);
if (status != OK)
goto error;
status = intConnect ((VOIDFUNCPTR *)pDCANboardCfg[ctrlNdx].intNumerr,
(VOIDFUNCPTR) tiDcan_ISR, (int)pDev);
if (status != OK)
goto error;
return (status);
error:
status = ERROR;
DRV_LOG (DCAN_DRV_DEBUG_ENTRY, "am335xCan_init intConnect failed %d, %d\n",
status,ctrlNdx,0,0,0,0);
return (status);
}
/************************************************************************
*
* am335xCan_init - initialize the am335X board
*
* This routine initializes the am335X board.
*
* RETURNS: OK or ERROR
*
* ERRNO:
* \is
* \i S_can_out_of_memory
* No memory can be allocted.
*
* \i S_can_illegal_channel_no
* Illegal channel number is unputted.
* \ie
*/
STATUS am335xCan_init
(
am335x_mscan_instance * pDCANboardCfg
)
{
struct WNCAN_Board * pBrd = NULL;
struct WNCAN_Device * pDev = NULL;
struct WNCAN_Controller * pCtrlr = NULL;
STATUS status = OK;
int i = 0;
DRV_LOG (DCAN_DRV_DEBUG_ENTRY, "am335xCan_init()\n",1,2,3,4,5,6);
/* check if driver instance is already in use */
if (am335x_cfgGet_inUse (BRD_NDX) == TRUE)
{
errnoSet (S_can_out_of_memory);
status = ERROR;
goto exit;
}
else
{
/* set board as in use. */
am335x_cfgSet_inUse (BRD_NDX, TRUE);
}
/* configure the WNCAN_Board data */
pBrd = am335x_cfgGet_canBoardPtr (BRD_NDX);
pBrd->xtalFreq = 0; /* Not used */
pBrd->irq = 0; /* Not used */
pBrd->ioAddress = 0; /* Not used */
pBrd->bar0 = 0; /* Not used */
pBrd->bar1 = 0; /* Not used */
pBrd->bar2 = 0; /* Not used */
/* initialize each controller on the board */
for (i = 0; i < am335x_cfgGet_NumControllers(); i++)
{
pDev = am335x_cfgGet_canDevicePtr (BRD_NDX, i);
pCtrlr = am335x_cfgGet_canControllerPtr (BRD_NDX, i);
if ((pDev == NULL) || (pCtrlr == NULL))
{
status = ERROR;
break;
}
/* configure the WNCAN_Device data */
pDev->deviceName = am335xCan_deviceName;
pDev->deviceId = i; /* Note, board number is always 0 for this device */
pDev->pCtrl = pCtrlr; /* Back pointer to WNCAN_Controller */
/* back pointer to board */
pDev->pBrd = am335x_cfgGet_canBoardPtr (BRD_NDX);
pDev->userData = NULL;
/* configure the WNCAN_Controller data */
pCtrlr->ctrlID = (UCHAR)i;
pCtrlr->pDev = pDev; /* backward pointer to WNCAN_Device */
pCtrlr->chnType = am335x_cfgGet_chTypePtr(BRD_NDX, i);
pCtrlr->numChn = pDCANboardCfg[i].taChl;
pCtrlr->chnMode = am335x_cfgGet_chModePtr (BRD_NDX, i);
/* AM335X pointer to driver specific data */
pCtrlr->csData = am335x_cfgGet_mscanDevPtr (BRD_NDX, i);
/* configure device specific data */
if ((status = am335xCan_cfg (pDCANboardCfg, i)) != OK)
{
DRV_LOG (DCAN_DRV_DEBUG_ENTRY, "am335xCan_cfg failed"
": status %d, i %d\n", status, i, 3, 4, 5, 6);
status = ERROR;
break;
}
/* establish WNCAN links */
status = CAN_DEVICE_establishLinks (pDev, WNCAN_AM335X,
WNCAN_TIDCAN);
if (status == ERROR)
{
DRV_LOG (DCAN_DRV_DEBUG_ENTRY, "am335xCan_init "
"CAN_DEVICE_establishLinks failed, errno %d %d, "
"pDev %08x, i %d\n",
(0xffff0000 & errnoGet ()) >> 16,
0x0000ffff & errnoGet (),
(int)pDev,i,0,0);
status = ERROR;
break;
}
}
exit:
return (status);
}
/************************************************************************
*
* am335xCan_establishLinks - set up function pointers
*
* Set up function pointers for driver.
*
* RETURNS: OK or ERROR
*
* ERRNO:
* \is
* \i S_can_illegal_config
* The CAN controller ID is incorrect.
* \ie
*/
STATUS am335xCan_establishLinks
(
struct WNCAN_Device *pDev
)
{
STATUS retCode = OK;
/* initialize the WNCAN_Board struct */
pDev->pBrd->onEnterISR = NULL;
pDev->pBrd->onLeaveISR = NULL;
pDev->pBrd->enableIrq = NULL;
pDev->pBrd->disableIrq = NULL;
if (pDev->pCtrl->ctrlType == WNCAN_TIDCAN)
{
pDev->pBrd->canInByte = NULL;
pDev->pBrd->canOutByte = NULL;
}
else
{
errnoSet(S_can_illegal_config);
retCode = ERROR;
}
return (retCode);
}
/************************************************************************
*
* am335xCan_open - open a CAN device
*
* This function opens the CAN device.
*
* RETURNS: pointer to a WNCAN_Device structure or NULL if error.
*
* ERRNO:
* \is
* \i S_can_illegal_board_no
* The board number is incorrect.
* \i S_can_illegal_ctrl_no
* The controller number is incorrect.
* \i S_can_busy
* The controller is busying.
* \ie
*/
struct WNCAN_Device * am335xCan_open
(
UINT32 brdNdx,
UINT32 ctrlNdx
)
{
struct WNCAN_Device *pRet = NULL;
if (
(brdNdx >= MAX_NUM_AM335X_CAN_BOARDS) ||
(am335x_cfgGet_inUse (brdNdx) == FALSE)
)
{
errnoSet (S_can_illegal_board_no);
}
else if (ctrlNdx >= am335x_cfgGet_NumControllers ())
{
errnoSet (S_can_illegal_ctrl_no);
}
else if (am335x_cfgGet_allocated (BRD_NDX, ctrlNdx) == TRUE)
{
errnoSet (S_can_busy);
}
else
{
am335x_cfgSet_allocated (BRD_NDX, ctrlNdx, TRUE);
pRet = am335x_cfgGet_canDevicePtr (BRD_NDX, ctrlNdx);
}
return (pRet);
}
/************************************************************************
*
* am335xCan_close - close the CAN device
*
* This function closes the CAN device.
*
* RETURNS: OK
*
* ERRNO: N/A
*/
STATUS am335xCan_close
(
struct WNCAN_Device * pDev
)
{
UINT32 ctrlNdx;
DRV_LOG (DCAN_DRV_DEBUG_ENTRY, "am335xCan_close() deviceId: %d\n",
pDev->deviceId,0,0,0,0,0);
if(pDev != NULL)
{
ctrlNdx = (pDev->deviceId) & 0xFF;
am335x_cfgSet_allocated (BRD_NDX, ctrlNdx, FALSE);
}
return (OK);
}
/***************************************************************************
*
* CAN_SetupFifoRxChannel - get a free receive channel
*
* This routine gets a free receive channel with fifo supported ,then set the
* ID, ext flag, interrupt type and mask value to the corresponding channel.
* The corresponding channel will be enabled when the
* CAN_SetupFifoRxChannel() was called.
*
* RETURNS: 'OK', or 'ERROR' if no channel is available.
*
* ERRNO:
* \is
* \i S_can_no_available_channels
* There is no channel available.
*
* \i S_can_out_of_memory
* There is no memory available.
* \ie
*/
STATUS CAN_SetupFifoRxChannel
(
struct WNCAN_Device *pDev, /* CAN device pointer */
UCHAR *channelNum, /* channel number */
UCHAR size, /* fifo size */
ULONG canID, /* CAN ID */
BOOL ext, /* TRUE = extended CAN msg */
WNCAN_IntType intSetting, /* interrupt type */
long mask /* filter mask value */
)
{
STATUS status = ERROR;
DCAN_FIFO *pfifoData = NULL;
UINT32 tempVal = 0;
DRV_ASSERT (pDev != NULL);
pfifoData = (DCAN_FIFO * )malloc(sizeof(DCAN_FIFO));
if (pfifoData == NULL)
{
DRV_LOG (DCAN_DRV_DEBUG_ENTRY, "No memory available!!! \n",
1, 2, 3, 4, 5, 6);
errnoSet (S_can_out_of_memory);
status = ERROR;
return status;
}
memset((void *)pfifoData,0, sizeof(DCAN_FIFO));
for(tempVal = 0; tempVal < size; tempVal++)
{
status = CAN_GetRxChannel(pDev, &pfifoData->channelNum[tempVal]);
if (status == ERROR )
goto err;
status = CAN_SetLocalMsgFilter(pDev, pfifoData->channelNum[tempVal],
mask, ext);
if (status == ERROR )
goto err;
status = CAN_WriteID(pDev, pfifoData->channelNum[tempVal],
canID, ext);
if (status == ERROR )
goto err;
}
for(tempVal = 0; tempVal < size; tempVal++)
{
if(tempVal == size -1)
{
/*
* the WNCAN_INT_RX menas tell the DCAN driver the buffer
* is the last one.
*
*/
status = CAN_EnableChannel(pDev, pfifoData->channelNum[tempVal],
WNCAN_INT_RX);
}
else
{
/*
* the WNCAN_INT_SPURIOUS menas tell the DCAN driver the buffer
* is not the last one.
*
*/
status = CAN_EnableChannel(pDev, pfifoData->channelNum[tempVal],
WNCAN_INT_SPURIOUS);
}
if (status == ERROR )
goto err;
}
pfifoData->bufferSize = size;
/* the channel 0 will be saved for releasing functions */
*channelNum = pfifoData->channelNum[0];
if (pFifoDataList == NULL)
{
pFifoDataList = dllCreate();
if (pFifoDataList == NULL)
goto err;
}
dllAdd (pFifoDataList, &pfifoData->pNode);
return OK;
err:
DRV_LOG (DCAN_DRV_DEBUG_ENTRY, "Alloc channel with fifo supported failed !!",
1, 2, 3, 4, 5, 6);
for(tempVal = 0; tempVal < size; tempVal ++)
{
if (pfifoData->channelNum[tempVal] != NULL)
{
status = CAN_DisableChannel(pDev, pfifoData->channelNum[tempVal]);
status = CAN_FreeChannel(pDev, pfifoData->channelNum[tempVal]);
}
}
errnoSet (S_can_no_available_channels);
free((void * )pfifoData);
return ERROR;
}
/***************************************************************************
* CAN_FreeFifoRxChannel - free the specified channel
*
* This routine frees a channel allocate by CAN_SetupFifoRxChannel( ).
*
* RETURNS: 'OK', or 'ERROR' if requested channel is invalid.
*
* ERRNO: N/A
*/
STATUS CAN_FreeFifoRxChannel
(
struct WNCAN_Device *pDev, /* CAN device pointer */
UCHAR channelNum /* channelNum */
)
{
DCAN_FIFO *pTmpFifoData = NULL;
DL_NODE *pTmpNode = NULL;
STATUS status = ERROR;
UINT32 tempVal = 0;
if (pFifoDataList == NULL )
{
goto err;
}
if (DLL_EMPTY(pFifoDataList))
{
goto err;
}
pTmpNode = DLL_FIRST(pFifoDataList);
pTmpFifoData = (DCAN_FIFO *)pTmpNode;
if (pTmpFifoData == NULL)
{
goto err;
}
while(
(pTmpFifoData != NULL) &&
(pTmpFifoData->channelNum[0] != channelNum)
)
{
pTmpNode = DLL_NEXT(pTmpNode);
pTmpFifoData = (DCAN_FIFO *)pTmpNode;
}
if (pTmpFifoData != NULL)
{
for(tempVal = 0; tempVal < pTmpFifoData->bufferSize; tempVal++)
{
status = CAN_DisableChannel(pDev,
pTmpFifoData->channelNum[tempVal]);
if (status == ERROR )
goto err;
status = CAN_FreeChannel(pDev,
pTmpFifoData->channelNum[tempVal]);
if (status == ERROR )
goto err;
}
dllRemove(pFifoDataList, pTmpNode);
free((void * )pTmpFifoData);
}
else
{
goto err;
}
return OK;
err:
DRV_LOG (DCAN_DRV_DEBUG_ENTRY, "Free channel failed !! \n",
1, 2, 3, 4, 5, 6);
return ERROR;
}
#ifdef SYS_DCAN_DEBUG
/***************************************************************************
* CAN_ShowFifoList - List the allocated channel
*
* This routine list the allocated channel.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
void CAN_ShowFifoList (void)
{
DCAN_FIFO *pTmpFifoData = NULL;
DL_NODE *pTmpNode = NULL;
UINT32 tempVal = 0;
UINT32 tempVa2 = 0;
if (pFifoDataList == NULL )
{
return ;
}
pTmpNode = DLL_FIRST(pFifoDataList);
pTmpFifoData = (DCAN_FIFO *)pTmpNode;
while(pTmpFifoData != NULL)
{
printf("channel fifo ID %d size %d \n",
pTmpFifoData->channelNum[0], pTmpFifoData->bufferSize);
for(tempVal = 0; tempVal < pTmpFifoData->bufferSize; tempVal ++)
{
printf("%d ", pTmpFifoData->channelNum[tempVal]);
}
printf("\n");
pTmpNode = DLL_NEXT(pTmpNode);
pTmpFifoData = (DCAN_FIFO *)pTmpNode;
}
return ;
}
#endif /* SYS_DCAN_DEBUG */
+155
View File
@@ -0,0 +1,155 @@
/* canBoard.c - implementation of CAN Board routines */
/* Copyright 2001 Wind River Systems, Inc. */
/*
modification history
--------------------
09nov01,dnb modified for integration into Tornado
12jul01,jac written
*/
/*
DESCRIPTION
implementation of CAN Board routines
*/
/* includes */
#include <vxWorks.h>
#include <errnoLib.h>
#include <stdlib.h>
#include <string.h>
#include <CAN/wnCAN.h>
#include <CAN/canBoard.h>
#include <CAN/canController.h>
#include <CAN/canFixedLL.h>
/* *************************************************************************** */
/* **** global variables */
/* fixed-node linked list instance for all boards */
FLL_RootType g_BoardLLRoot;
/************************************************************************
*
* WNCAN_Board_establishLinks - connect the function pointers in the
* board structure to the appropriate routines
*
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_unknown_board
*
*/
STATUS WNCAN_Board_establishLinks
(
struct WNCAN_Device *pDev,
WNCAN_BoardType brdType
)
{
STATUS retCode = ERROR;
BoardLLNode *pBoardNode;
pBoardNode = BOARDLL_GET(brdType);
if (pBoardNode && pBoardNode->nodedata.boarddata.establinks_fn)
{
retCode = (*pBoardNode->nodedata.boarddata.establinks_fn)(pDev);
}
else
{
errnoSet(S_can_unknown_board);
retCode = ERROR;
}
return retCode;
}
/************************************************************************
*
* WNCAN_Board_Open - attempt to open specified board
*
* RETURNS: point to device structure, or 0 on error
*
* ERRNO: S_can_unknown_board
*
*/
struct WNCAN_Device *WNCAN_Board_Open
(
UINT brdType,
UINT brdNdx,
UINT ctrlNdx
)
{
struct WNCAN_Device *retDev = 0;
BoardLLNode *pBoardNode;
pBoardNode = BOARDLL_GET(brdType);
if (pBoardNode && pBoardNode->nodedata.boarddata.open_fn)
{
retDev = (*pBoardNode->nodedata.boarddata.open_fn)(brdNdx, ctrlNdx);
}
else
{
errnoSet(S_can_unknown_board);
retDev = 0;
}
return retDev;
}
/************************************************************************
*
* WNCAN_Board_Close - close specified CAN Device
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
void WNCAN_Board_Close
(
struct WNCAN_Device *pDev
)
{
WNCAN_BoardType brdType = pDev->pBrd->brdType;
BoardLLNode *pBoardNode;
pBoardNode = BOARDLL_GET(brdType);
if (pBoardNode && pBoardNode->nodedata.boarddata.close_fn)
{
(*pBoardNode->nodedata.boarddata.close_fn)(pDev);
}
return;
}
/************************************************************************
*
* stringToUlong - helper function used by boards to
*
* RETURNS: Ulong
*
* ERRNO: N/A
*
*/
ULONG stringToUlong(const char *pStr)
{
ULONG retVal = 0;
UINT base;
if(pStr)
{
if(!strncmp(pStr, "0x", 2) || !strncmp(pStr, "0X", 2))
base = 16;
else
base = 10;
retVal = strtoul(pStr, NULL, base);
}
return retVal;
}
@@ -0,0 +1,68 @@
/* canController.c - implementation of CAN Controller routines */
/* Copyright 2001 Wind River Systems, Inc. */
/*
modification history
--------------------
09nov01,dnb modified for integration into Tornado
12jul01,jac written
*/
/*
DESCRIPTION
implementation of CAN controller routines
*/
/* includes */
#include <vxWorks.h>
#include <errnoLib.h>
#include <CAN/wnCAN.h>
#include <CAN/canBoard.h>
#include <CAN/canController.h>
#include <CAN/canFixedLL.h>
/* fixed-node linked list instance for all controllers */
FLL_RootType g_ControllerLLRoot;
/************************************************************************
*
* WNCAN_Controller_establishLinks - connect the function pointers in the
* Device structure to the appropriate
* routines. Set the number of channels in
* the controller structure
*
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_unknown_controller
*
*/
STATUS WNCAN_Controller_establishLinks
(
struct WNCAN_Device *pDev,
WNCAN_ControllerType ctrlType
)
{
STATUS retCode = OK;
ControllerLLNode *pCtrlrNode;
pCtrlrNode = CONTROLLERLL_GET(ctrlType);
if (pCtrlrNode && pCtrlrNode->nodedata.controllerdata.establinks_fn)
{
(*pCtrlrNode->nodedata.controllerdata.establinks_fn)(pDev);
}
else
{
errnoSet(S_can_unknown_controller);
retCode = ERROR;
}
return retCode;
}
+106
View File
@@ -0,0 +1,106 @@
/* canFixedLL.c - WN-CAN fixed-node linked lists */
/* Copyright 2002 Wind River Systems, Inc. */
/*
modification history
--------------------
07nov02,rgp written
*/
/*
DESCRIPTION
implementation of generic fixed-node linked list
*/
/* includes */
#include <vxWorks.h>
#include <taskLib.h>
#include <errnoLib.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <CAN/canFixedLL.h>
/************************************************************************
*
* FLL_Create - Initialize the linked list
*
* RETURNS: none
*
*/
void FLL_Create
(
FLL_RootType *pRoot
)
{
assert(pRoot); /* internal error */
/* initialize the linked list instance */
pRoot->pFirst = NULL;
}
/************************************************************************
*
* FLL_Add - Add a node into the linked list
*
* NOTE: a node with a duplicate key will *not* be added!
*
* RETURNS: none
*
*
*/
void FLL_Add
(
FLL_RootType *pRoot,
FLL_NodeType *pNode
)
{
assert(pRoot);
if (!pNode) return; /* nothing to add, then exit */
taskLock();
/* only add a unique instance of the node's key into the list */
if (FLL_Find(pRoot, pNode->key) == NULL)
{
pNode->pNext = pRoot->pFirst;
pRoot->pFirst = pNode;
}
taskUnlock();
}
/************************************************************************
*
* FLL_Find - find a node matching the specified key
*
* RETURNS: ptr to matching node or NULL
*
*/
FLL_NodeType *FLL_Find
(
FLL_RootType *pRoot,
int key
)
{
FLL_NodeType *pCur;
assert(pRoot);
/* linear seach for the key */
for(pCur = pRoot->pFirst; pCur; pCur = pCur->pNext)
if (pCur->key == key) break;
return pCur;
}
File diff suppressed because it is too large Load Diff
+264
View File
@@ -0,0 +1,264 @@
/*****************************************************************************
* %LICENSE_DUAL%
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007, 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*
* Contact Information:
* Intel Corporation
*
* BSD LICENSE
*
* Copyright(c) 2007 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*
modification history
--------------------
01a,16sep13,xms fix RETURN_NULL error. (WIND00414265)
*/
#include <vxWorks.h>
#include <stdio.h>
#include <stdlib.h>
#include <CAN/icp_can.h>
#include <CAN/can_fifo.h>
/******************************************************************************
* A FIFO element is a CAN msg.
*****************************************************************************/
typedef struct can_fifo_item {
icp_can_msg_t msg;
struct can_fifo_item *next;
} can_fifo_item_t;
/******************************************************************************
* The FIFO.
*****************************************************************************/
typedef struct can_fifo {
can_fifo_item_t *head;
can_fifo_item_t *tail;
unsigned int size;
} can_fifo_t;
/******************************************************************************
* Check if FIFO is empty.
*****************************************************************************/
int can_fifo_empty(icp_can_handle_t handle)
{
can_fifo_t *f = (can_fifo_t *) handle;
return (f->head==f->tail);
}
/******************************************************************************
* Check if FIFO is full.
*****************************************************************************/
int can_fifo_full(icp_can_handle_t handle)
{
can_fifo_t *f = (can_fifo_t *) handle;
return (f->head->next==f->tail);
}
/******************************************************************************
* Create a CAN messsage FIFO of size specifified.
*****************************************************************************/
icp_can_handle_t can_fifo_create(unsigned int num_nodes)
{
unsigned int i;
can_fifo_item_t *curr;
can_fifo_t *f;
f = (can_fifo_t *) CAN_MEM_ALLOC(sizeof(can_fifo_t));
if (!f) {
CAN_PRINT_DEBUG(ICP_CAN_ERR_ALLOC, "msg queue");
return (icp_can_handle_t) 0;
}
f->head = (can_fifo_item_t *) CAN_MEM_ALLOC(sizeof(can_fifo_item_t));
f->tail = f->head;
if (!(f->head)) {
CAN_PRINT_DEBUG(ICP_CAN_ERR_ALLOC, "msg queue head");
CAN_MEM_FREE(f);
return (icp_can_handle_t) 0;
}
curr = f->head;
for (i=1; i<num_nodes; i++) {
curr->next = (can_fifo_item_t *) CAN_MEM_ALLOC(sizeof(can_fifo_item_t));
if (!(curr->next)) {
CAN_PRINT_DEBUG(ICP_CAN_ERR_ALLOC, "msg queue node");
f->size = i-1;
CAN_MEM_FREE(f);
return (icp_can_handle_t) 0;
}
curr = curr->next;
}
curr->next = f->head;
f->size = num_nodes;
return (icp_can_handle_t) f;
}
/******************************************************************************
* Delete the FIFO.
*****************************************************************************/
void can_fifo_destroy(icp_can_handle_t handle)
{
unsigned int i;
can_fifo_item_t *curr;
can_fifo_item_t *next;
can_fifo_t *f = (can_fifo_t *) handle;
if (handle) {
curr = f->head;
if (curr == NULL)
return;
next = curr->next;
for (i=0; i<f->size; i++) {
if (!curr) {
CAN_PRINT_DEBUG(ICP_CAN_ERR_FREE,
"msg queue node");
}
CAN_MEM_FREE(curr);
curr = next;
if (curr == NULL)
break;
next = (can_fifo_item_t *) curr->next;
}
CAN_MEM_FREE(f);
}
}
/******************************************************************************
* Get the first element of the FIFO.
*****************************************************************************/
int can_fifo_get(
icp_can_handle_t handle,
icp_can_msg_t *msg)
{
int i;
can_fifo_t *f = (can_fifo_t *) handle;
icp_can_msg_t msg_tmp = f->tail->msg;
if ((!handle) || (!msg)) {
return -1;
}
#if TOLAPAI_CAN_DRV_DEBUG
printf("can_fifo_get() \n");
#endif
if (f->head==f->tail) {
#if TOLAPAI_CAN_DRV_DEBUG
printf("can_fifo_get() queue empty\n");
#endif
return -1;
}
msg->ide = msg_tmp.ide;
msg->id = msg_tmp.id;
msg->dlc = msg_tmp.dlc;
msg->rtr = msg_tmp.rtr;
for (i=0; i<ICP_CAN_MSG_DATA_LEN; i++) {
msg->data[i] = msg_tmp.data[i];
}
f->tail = f->tail->next;
return 0;
}
/******************************************************************************
* Put a message into the FIFO.
*****************************************************************************/
int can_fifo_put(
icp_can_handle_t handle,
icp_can_msg_t *msg)
{
int i;
can_fifo_t *f = (can_fifo_t *) handle;
icp_can_msg_t *msg_tmp = &(f->head->msg);
if ((!handle) || (!msg)) {
return -1;
}
#if TOLAPAI_CAN_DRV_DEBUG
printf("can_fifo_put() \n");
#endif
if (f->head->next==f->tail) {
#if TOLAPAI_CAN_DRV_DEBUG
printf("can_fifo_put() queue full\n");
#endif
return -1;
}
msg_tmp->ide = msg->ide;
msg_tmp->rtr = msg->rtr;
msg_tmp->id = msg->id;
msg_tmp->dlc = msg->dlc;
for (i=0; i<ICP_CAN_MSG_DATA_LEN; i++) {
msg_tmp->data[i] = msg->data[i];
}
f->head = f->head->next;
return 0;
}
@@ -0,0 +1,517 @@
/* esd_can_pc104_200.c - implementation of Board Interface for ESD CAN PC104/200 */
/* Copyright 2001, 2013 Wind River Systems, Inc. */
/*
modification history
--------------------
01c,09sep13,xms fix CHECKED_RETURN error. (WIND00414265)
01b,03sep04,lag set default baud rate to 125 Kbps
01a,27nov01,dnb written
*/
/*
DESCRIPTION
This file contains the functions that provide a board-level interface
to the ESD CAN PC104/200 card.
*/
/* includes */
#include <vxWorks.h>
#include <errnoLib.h>
#include <intLib.h>
#include <iv.h>
#include <sysLib.h>
#include <string.h> /* for strtok_r */
#include <CAN/wnCAN.h>
#include <CAN/canController.h>
#include <CAN/canBoard.h>
#include <CAN/i82527.h>
#include <CAN/sja1000.h>
#include <CAN/private/esd_can_pc104_200.h>
#if (CPU != SH7750)
static const char deviceName[] ="ESD CAN PC104/200";
const UINT esd_can_pc104_200_i82527_ndx = 0;
const UINT esd_can_pc104_200_sja1000_ndx = 1;
UINT max_esd_can_pc104_200_boards;
struct ESD_CAN_PC104_200_DeviceEntry *esd_can_pc104_200_DeviceArray;
/* external reference */
STATUS CAN_DEVICE_establishLinks(WNCAN_DEVICE *pDev, WNCAN_BoardType brdType,
WNCAN_ControllerType ctrlType);
/************************************************************************
*
* esd_can_pc104_200_setirq - sets the IRQ level of the ESD PC104/200 board
*
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
void esd_can_pc104_200_setirq
(
ULONG ioBase,
UINT irqLevel
)
{
UINT l, l1, stat;
int oldLevel;
/* Lock out all interrupts */
oldLevel = intLock();
/* Assign interrupt level on card */
l1 = irqLevel;
for (l = 0; l < 4; l++)
{
stat=l;
if (l1 & 0x01)
stat |= 0x80;
sysOutByte(ioBase+3,stat);
l1 = l1 >> 1;
}
/* Change the IRQ-output from Tri-state into driven status. */
#if (CPU_FAMILY == I80X86)
sysOutByte(ioBase+3, (char)0x87);
#else
sysOutByte(ioBase+3, 0x87);
#endif
/* latch 1000 times */
for(l = 0; l < 1000; l++)
{
sysOutByte(ioBase+3, 5);
}
/* Unlock interrupts */
intUnlock(oldLevel);
return;
}
/************************************************************************
*
* esd_can_pc104_200_isr - board-level isr
*
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
static void esd_can_pc104_200_isr
(
ULONG param
)
{
struct ESD_CAN_PC104_200_DeviceEntry *pDE;
pDE = (struct ESD_CAN_PC104_200_DeviceEntry *)param;
/* disabling the interrupt. Deactivate the bits in the latch.*/
sysOutByte(pDE->ioAddress+3,0x06);
if(pDE->allocated[esd_can_pc104_200_i82527_ndx])
{
i82527ISR((ULONG)&pDE->canDevice[esd_can_pc104_200_i82527_ndx]);
}
if(pDE->allocated[esd_can_pc104_200_sja1000_ndx])
{
sja1000ISR((ULONG)&pDE->canDevice[esd_can_pc104_200_sja1000_ndx]);
}
/* Enable the interrupt. This enabling pin is also used for disabling
interrupts without changing the state of the outputs to tristate.
Writing 0x06 to the same address disables interrupts, writing 0x86
reenables interrupts */
#if (CPU_FAMILY == I80X86)
sysOutByte(pDE->ioAddress+3, (char)0x86);
#else
sysOutByte(pDE->ioAddress+3, 0x86);
#endif
}
/************************************************************************
*
* esd_can_pc104_200_new - install driver for pc104/200 board
*
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_out_of_memory
*
*/
STATUS esd_can_pc104_200_new
(
ULONG ioAddress,
UINT irq
)
{
UINT i;
UINT brdNdx=0;
int oldLevel;
STATUS retCode;
VOIDFUNCPTR* irqVec = 0;
struct WNCAN_Device *pDev[2];
struct ESD_CAN_PC104_200_DeviceEntry *pDeviceEntry;
retCode = ERROR; /* pessimistic */
pDeviceEntry = 0;
/* find a free device data structure */
for(i = 0 ; i < max_esd_can_pc104_200_boards; i++)
{
if(esd_can_pc104_200_DeviceArray[i].inUse == 0)
{
esd_can_pc104_200_DeviceArray[i].inUse = 1;
pDeviceEntry = &esd_can_pc104_200_DeviceArray[i];
brdNdx = i;
break;
}
}
if(i == (max_esd_can_pc104_200_boards + 1))
{
retCode = ERROR;
errnoSet(S_can_out_of_memory);
goto exit;
}
if(!pDeviceEntry)
{
errnoSet(S_can_out_of_memory);
retCode = ERROR;
goto exit;
}
/* setup data structures */
for(i = 0 ; i < ESD_CAN_PC104_200_MAX_CONTROLLERS ; i++)
{
pDev[i] = &pDeviceEntry->canDevice[i];
pDev[i]->pCtrl = &pDeviceEntry->canControllerArray[i];
pDev[i]->pBrd = &pDeviceEntry->canBoardArray[i];
pDev[i]->deviceName = deviceName;
pDev[i]->pBrd->irq = irq;
pDev[i]->pBrd->ioAddress = ioAddress;
pDev[i]->pBrd->xtalFreq = _16MHZ;
/* set default baud rate to 125 Kbits/sec */
pDev[i]->pCtrl->brp = 3;
pDev[i]->pCtrl->sjw = 0;
pDev[i]->pCtrl->tseg1 = 0xc;
pDev[i]->pCtrl->tseg2 = 0x1;
pDev[i]->pCtrl->samples = 0;
}
pDev[esd_can_pc104_200_i82527_ndx]->pCtrl->chnType = g_i82527chnType;
pDev[esd_can_pc104_200_i82527_ndx]->pCtrl->numChn = I82527_MAX_MSG_OBJ;
pDev[esd_can_pc104_200_i82527_ndx]->pCtrl->chnMode = &pDeviceEntry->i82527chnMode[0];
pDev[esd_can_pc104_200_i82527_ndx]->pCtrl->csData = &pDeviceEntry->can82527;
pDev[esd_can_pc104_200_sja1000_ndx]->pCtrl->chnType = g_sja1000chnType;
pDev[esd_can_pc104_200_sja1000_ndx]->pCtrl->numChn = SJA1000_MAX_MSG_OBJ;
pDev[esd_can_pc104_200_sja1000_ndx]->pCtrl->chnMode = &pDeviceEntry->sja1000chnMode[0];
pDev[esd_can_pc104_200_sja1000_ndx]->pCtrl->csData = &pDeviceEntry->txMsg;
if(CAN_DEVICE_establishLinks(pDev[esd_can_pc104_200_i82527_ndx],
WNCAN_ESD_PC104_200, WNCAN_I82527) == ERROR)
{
pDev[esd_can_pc104_200_i82527_ndx] = 0;
goto exit;
}
if(CAN_DEVICE_establishLinks(pDev[esd_can_pc104_200_sja1000_ndx],
WNCAN_ESD_PC104_200, WNCAN_SJA1000) == ERROR)
{
pDev[esd_can_pc104_200_sja1000_ndx] = 0;
goto exit;
}
pDev[esd_can_pc104_200_i82527_ndx]->deviceId = (brdNdx << 8);
pDev[esd_can_pc104_200_sja1000_ndx]->deviceId = (brdNdx << 8) | esd_can_pc104_200_sja1000_ndx;
/* set the irq on the board */
esd_can_pc104_200_setirq(ioAddress, irq);
/* connect to isr */
oldLevel = intLock();
#if CPU_FAMILY == I80X86
irqVec = INUM_TO_IVEC(irq+0x20);
#elif CPU_FAMILY == PPC
irqVec = INUM_TO_IVEC(irq+0x40);
#else
#warning irqVec not defined
#endif
/* don't need return from function call */
(void) intConnect(irqVec,esd_can_pc104_200_isr,(ULONG)pDeviceEntry);
/* activate IRQ at the board and CPU level */
#if (CPU_FAMILY == I80X86)
sysOutByte(ioAddress+3, (char)0x86);
sysIntEnablePIC(irq);
#elif CPU_FAMILY == PPC
sysOutByte(ioAddress+3, 0x86);
intEnable(irq+0x40);
#else
#warning interrupts cannot be enabled
#endif
intUnlock(oldLevel);
pDeviceEntry->ioAddress = ioAddress;
pDeviceEntry->irq = irq;
retCode = OK;
exit:
return retCode;
}
/************************************************************************
*
* esd_can_pc104_enableIrq - enable irq on board
*
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
static void esd_can_pc104_enableIrq
(
struct WNCAN_Device *pDev
)
{
#if (CPU_FAMILY == I80X86)
sysOutByte(pDev->pBrd->ioAddress+3, (char)0x86);
#else
sysOutByte(pDev->pBrd->ioAddress+3, 0x86);
#endif
return;
}
/************************************************************************
*
* esd_can_pc104_disableIrq - disable irq on board
*
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
static void esd_can_pc104_disableIrq
(
struct WNCAN_Device *pDev
)
{
sysOutByte(pDev->pBrd->ioAddress+3, 0x06);
return;
}
/************************************************************************
*
* esd_can_pc104_canInByteForI82527
*
*
* RETURNS:
*
* ERRNO:
*
*/
static UCHAR esd_can_pc104_canInByteForI82527
(
struct WNCAN_Device *pDev,
unsigned int offset
)
{
sysOutByte(pDev->pBrd->ioAddress + 7,offset);
return sysInByte(pDev->pBrd->ioAddress+4);
}
/************************************************************************
*
* esd_can_pc104_canOutByteForI82527
*
*
* RETURNS:
*
* ERRNO:
*
*/
static void esd_can_pc104_canOutByteForI82527
(
struct WNCAN_Device *pDev,
unsigned int offset,
UCHAR value
)
{
sysOutByte(pDev->pBrd->ioAddress + 7,offset);
sysOutByte(pDev->pBrd->ioAddress + 4, value);
}
/************************************************************************
*
* esd_can_pc104_canInByteForSJA1000
*
*
* RETURNS:
*
* ERRNO:
*
*/
static UCHAR esd_can_pc104_canInByteForSJA1000
(
struct WNCAN_Device *pDev,
unsigned int offset
)
{
sysOutByte(pDev->pBrd->ioAddress + 1,offset);
return sysInByte(pDev->pBrd->ioAddress);
}
/************************************************************************
*
* esd_can_pc104_canOutByteForSJA1000
*
*
* RETURNS:
*
* ERRNO:
*
*/
static void esd_can_pc104_canOutByteForSJA1000
(
struct WNCAN_Device *pDev,
unsigned int offset,
UCHAR value
)
{
sysOutByte(pDev->pBrd->ioAddress + 1,offset);
sysOutByte(pDev->pBrd->ioAddress, value);
}
/************************************************************************
*
* esd_can_pc104_200_establishLinks - set up function pointers
*
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_illegal_config
*
*/
STATUS esd_can_pc104_200_establishLinks(struct WNCAN_Device *pDev)
{
STATUS retCode = OK;
pDev->pBrd->onEnterISR = 0;
pDev->pBrd->onLeaveISR = 0;
pDev->pBrd->enableIrq = esd_can_pc104_enableIrq;
pDev->pBrd->disableIrq = esd_can_pc104_disableIrq;
if(pDev->pCtrl->ctrlType == WNCAN_I82527)
{
pDev->pBrd->canInByte = esd_can_pc104_canInByteForI82527;
pDev->pBrd->canOutByte = esd_can_pc104_canOutByteForI82527;
}
else if(pDev->pCtrl->ctrlType == WNCAN_SJA1000)
{
pDev->pBrd->canInByte = esd_can_pc104_canInByteForSJA1000;
pDev->pBrd->canOutByte = esd_can_pc104_canOutByteForSJA1000;
}
else
{
errnoSet(S_can_illegal_config);
retCode = ERROR;
}
return retCode;
}
/************************************************************************
*
* esd_can_pc104_200_open - open a CAN device
*
* RETURNS: pointer to a WNCAN_Device structure or 0 if error
*
* ERRNO: S_can_illegal_board_no
* S_can_illegal_ctrl_no
* S_can_busy
*
*/
struct WNCAN_Device *esd_can_pc104_200_open(UINT brdNdx, UINT ctrlNdx)
{
struct WNCAN_Device *pRet = 0; /* pessimistic */
if((brdNdx >= max_esd_can_pc104_200_boards) ||
(esd_can_pc104_200_DeviceArray[brdNdx].inUse == 0))
{
errnoSet(S_can_illegal_board_no);
}
else if(ctrlNdx >= ESD_CAN_PC104_200_MAX_CONTROLLERS)
{
errnoSet(S_can_illegal_ctrl_no);
}
else if(esd_can_pc104_200_DeviceArray[brdNdx].allocated[ctrlNdx] == 1)
{
errnoSet(S_can_busy);
}
else
{
esd_can_pc104_200_DeviceArray[brdNdx].allocated[ctrlNdx] = 1;
pRet = &esd_can_pc104_200_DeviceArray[brdNdx].canDevice[ctrlNdx];
}
return pRet;
}
/************************************************************************
*
* esd_can_pc104_200_close - close the CAN device
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
void esd_can_pc104_200_close(struct WNCAN_Device *pDev)
{
UINT brdNdx;
UINT ctrlNdx;
if(pDev != 0)
{
brdNdx = ((pDev->deviceId) & 0xFFFFFF00) >> 8;
ctrlNdx = (pDev->deviceId) & 0xFF;
esd_can_pc104_200_DeviceArray[brdNdx].allocated[ctrlNdx] = 0;
}
return;
}
#endif
@@ -0,0 +1,348 @@
/* esd_pci_200.c - implementation of Board Interface for ESD CAN PCI/200 */
/* Copyright 2001 Wind River Systems, Inc. */
/*
modification history
--------------------
27nov01,dnb written
*/
/*
DESCRIPTION
This file contains the functions that provide a board-level interface
to the ESD CAN PCI/200 card.
*/
/* includes */
#include <vxWorks.h>
#include <errnoLib.h>
#include <intLib.h>
#include <iv.h>
#include <sysLib.h>
#include "CAN/wnCAN.h"
#include "CAN/canController.h"
#include "CAN/canBoard.h"
#include "CAN/i82527.h"
#include "CAN/sja1000.h"
#include "CAN/private/esd_pci_200.h"
/* external reference */
extern STATUS sys_ESD_PCI_200_Init(UINT brdNum);
UINT ESD_PCI_200_MaxBrdNumGet(void);
struct ESD_PCI_200_DeviceEntry* ESD_PCI_200_DeviceEntryGet(UINT brdNum);
void sys_ESD_PCI_200_canOutByte(struct WNCAN_Device *pDev, unsigned int reg,
UCHAR value);
UCHAR sys_ESD_PCI_200_canInByte(struct WNCAN_Device *pDev, unsigned int reg);
void sys_ESD_PCI_200_IntConnect(UINT brdNum);
/*****************************************************************************
* ESD_PCI_200_EnableIRQ - The ESD specific function for enabling interrupts
* on the PCI bus by the PLX 9052 bridge.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
void ESD_PCI_200_EnableIRQ
(
struct WNCAN_Device *pDev
)
{
UINT32 offset = pDev->pBrd->bar0;
ULONG memBase = pDev->pBrd->ioAddress;
UCHAR data;
UCHAR *addr;
addr = (UCHAR*)memBase + offset + 0x4c;
data = *(addr);
data |= 0x41;
*(addr) = data;
#ifdef DEBUG
data = *(addr);
#endif
return;
}
/*****************************************************************************
* ESD_PCI_200_DisableIRQ - The ESD specific function for disabling interrupts
* on the PCI bus by the PLX 9052 bridge.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
void ESD_PCI_200_DisableIRQ
(
struct WNCAN_Device *pDev
)
{
UINT32 offset = pDev->pBrd->bar0;
ULONG memBase = pDev->pBrd->ioAddress;
UCHAR data;
data = *((UCHAR*)memBase + offset + 0x4c);
data &= ~0x41;
*((UCHAR*)memBase + offset + 0x4c) = data;
return;
}
/************************************************************************
*
* ESD_PCI_200_IntConnect - connect board-level interrupts
*
* This routine connects and enables the board level interrupt of the
* specified ESD PCI/200 CAN card.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
void ESD_PCI_200_IntConnect
(
UINT brdNum
)
{
sys_ESD_PCI_200_IntConnect(brdNum);
return;
}
/************************************************************************
*
* ESD_PCI_200_IntConnectAll - connect all board-level interrupts
*
* This routine connects and enables the board level interrupts of all
* installed ESD PCI/200 CAN cards.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
void ESD_PCI_200_IntConnectAll
(
void
)
{
int brdNum = ESD_PCI_200_MaxBrdNumGet();
int i;
struct ESD_PCI_200_DeviceEntry *pDE;
for (i = 0; i < brdNum; i++)
{
if ((pDE = ESD_PCI_200_DeviceEntryGet(i)) == NULL)
continue;
else
{
if (pDE->intConnect == FALSE)
sys_ESD_PCI_200_IntConnect(i);
}
}
return;
}
/************************************************************************
*
* esd_can_pci_200_open - open a CAN device
*
* RETURNS: pointer to a WNCAN_Device structure or 0 if error
*
* ERRNO: S_can_illegal_board_no
* S_can_illegal_ctrl_no
* S_can_busy
*
*/
struct WNCAN_Device *esd_can_pci_200_open
(
UINT brdNdx,
UINT ctrlNdx
)
{
struct WNCAN_Device *pRet = 0; /* pessimistic */
UINT maxBrdNum;
struct ESD_PCI_200_DeviceEntry *pDE;
maxBrdNum = ESD_PCI_200_MaxBrdNumGet();
pDE = ESD_PCI_200_DeviceEntryGet(brdNdx);
if((brdNdx >= maxBrdNum) || (pDE->inUse == FALSE))
{
errnoSet(S_can_illegal_board_no);
}
else if(ctrlNdx >= ESD_PCI_200_MAX_CONTROLLERS)
{
errnoSet(S_can_illegal_ctrl_no);
}
else if(pDE->allocated[ctrlNdx] == 1)
{
errnoSet(S_can_busy);
}
else
{
pDE->allocated[ctrlNdx] = 1;
pRet = &(pDE->canDevice[ctrlNdx]);
}
return pRet;
}
/************************************************************************
*
* esd_can_pci_200_close - close a CAN device
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
void esd_can_pci_200_close
(
struct WNCAN_Device *pDev
)
{
UINT brdNdx;
UINT ctrlNdx;
struct ESD_PCI_200_DeviceEntry *pDE;
if(pDev != 0)
{
brdNdx = ((pDev->deviceId) & 0xFFFFFF00) >> 8;
ctrlNdx = (pDev->deviceId) & 0xFF;
pDE = ESD_PCI_200_DeviceEntryGet(brdNdx);
pDE->allocated[ctrlNdx] = 0;
}
return;
}
/************************************************************************
*
* ESD_PCI_200_Init - install driver for the ESD PCI/200 board
*
* This routine initializes the ESD PCI/200 by calling the BSP dependent
* routine sys_ESD_PCI_200_Init().
*
* RETURNS: OK or ERROR
*
* ERRNO: N/A
*
*/
STATUS ESD_PCI_200_Init
(
UINT brdNum
)
{
STATUS status;
status = sys_ESD_PCI_200_Init(brdNum);
return(status);
}
/************************************************************************
*
* ESD_PCI_200_InitAll - init all installed ESD PCI/200 boards.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
void ESD_PCI_200_InitAll(void)
{
UINT i,
maxBrds;
/* get the maximum number of ESD PCI/200 boards */
maxBrds = ESD_PCI_200_MaxBrdNumGet();
for(i = 0; i < maxBrds; i++)
{
ESD_PCI_200_Init(i);
}
return;
}
/*******************************************************************
* ESD_PCI_200_canOutByte - The ESD specific function for CAN writes
* on the PCI/200 board.
*
* RETURNS: NONE
*
* ERRNO: N/A
*/
void ESD_PCI_200_canOutByte
(
struct WNCAN_Device *pDev,
unsigned int reg,
UCHAR value
)
{
sys_ESD_PCI_200_canOutByte(pDev,reg,value);
return;
}
/*******************************************************************
* ESD_PCI_200_canInByte - The ESD specific function for CAN reads
* on the PCI/200 board.
*
* RETURNS: UCHAR - The register contents
*
* ERRNO: N/A
*/
UCHAR ESD_PCI_200_canInByte
(
struct WNCAN_Device *pDev,
unsigned int reg
)
{
UCHAR value;
value = sys_ESD_PCI_200_canInByte(pDev,reg);
return(value);
}
/************************************************************************
*
* esd_can_pci_200_establishLinks - set up function pointers
*
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_illegal_config
*
*/
STATUS esd_can_pci_200_establishLinks(struct WNCAN_Device *pDev)
{
STATUS retCode = OK;
if(pDev->pCtrl->ctrlType == WNCAN_SJA1000)
{
pDev->pBrd->onEnterISR = 0;
pDev->pBrd->onLeaveISR = 0;
pDev->pBrd->enableIrq = ESD_PCI_200_EnableIRQ;
pDev->pBrd->disableIrq = ESD_PCI_200_DisableIRQ;
pDev->pBrd->canInByte = ESD_PCI_200_canInByte;
pDev->pBrd->canOutByte = ESD_PCI_200_canOutByte;
}
else
{
errnoSet(S_can_illegal_config);
retCode = ERROR;
}
return retCode;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,496 @@
/* mpc5121eCan.c - implementation of Board Interface for the MPC5121E */
/*
* Copyright (c) 2008 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01a,01dec08,x_f derived from version 01b of mpc5200Can.c
*/
/*
DESCRIPTION
This file contains the functions that provide a board-level interface
to the MPC5121E processor.
*/
/* includes */
#include <vxWorks.h>
#include <errnoLib.h>
#include <intLib.h>
#include <iv.h>
#include <sysLib.h>
#if MSCAN_DRV_DEBUG
#include <logLib.h>
#endif
#include "CAN/wnCAN.h"
#include "CAN/canController.h"
#include "CAN/canBoard.h"
#include "CAN/motMsCan.h"
#include "CAN/motMsCanOffsets.h"
#include "CAN/private/mpc5121eCan.h"
IMPORT void MOTMSCAN_ISR (struct WNCAN_Device *);
/* globals */
LOCAL const char mpc5121eCan_deviceName[] ="MPC5121E MSCAN";
/* external reference */
IMPORT STATUS CAN_DEVICE_establishLinks (WNCAN_DEVICE * pDev,
WNCAN_BoardType brdType,
WNCAN_ControllerType ctrlType);
IMPORT void MOTMSCAN_ISR (struct WNCAN_Device * pDev);
/************************************************************************
*
* mpc5121eCan_cfg - Configure MSCAN device specific data
*
* RETURNS: OR or ERROR
*
* ERRNO: N/A
*/
LOCAL STATUS mpc5121eCan_cfg
(
mpc5121e_mscan_instance * pMSCANboardCfg,
UINT ctrlNdx
)
{
STATUS status = OK;
struct WNCAN_Device * pDev;
struct WNCAN_Controller * pCtrlr;
MSCAN_DEV * pMSCANdev;
#if MSCAN_DRV_DEBUG
logMsg("mpc5121eCan_cfg ctrlNdx %d, MSCAN %d, intNum %d, freq %d, Reg Base 0x%08x\n",
ctrlNdx,
pMSCANboardCfg[ctrlNdx].MSCANcontrollerId,
pMSCANboardCfg[ctrlNdx].intNum,
pMSCANboardCfg[ctrlNdx].freq,
(int)pMSCANboardCfg[ctrlNdx].pDevBaseAddr,
0);
#endif
pDev = mpc5121e_cfgGet_canDevicePtr (BRD_NDX, ctrlNdx);
pCtrlr = mpc5121e_cfgGet_canControllerPtr (BRD_NDX, ctrlNdx);
pMSCANdev = (MSCAN_DEV *)pCtrlr->csData;
pMSCANdev->pMSCANregs = pMSCANboardCfg[ctrlNdx].pDevBaseAddr;
pMSCANdev->intNum = pMSCANboardCfg[ctrlNdx].intNum;
pMSCANdev->freq = pMSCANboardCfg[ctrlNdx].freq;
switch (pMSCANboardCfg[ctrlNdx].MSCANcontrollerId)
{
case MSCAN1_CTRL:
/*
* Example calculation for CAN bit timing:-
* Input clock freq: 66MHz
* Required CAN bit rate: 250kbps
*
* Time Quanta Frequency = 66MHz / 22 = 3MHz
*
* Number of time quanta = 12
*
* CAN Bit Rate = 3MHz / 12 = 250kbps
*
* 12 time quanta = 1 + TSEG1 + TSEG2
*
* CAN sample point = 10 Time quanta
*/
pDev->pCtrl->brp = 22; /* Baud rate prescale = 22 */
pDev->pCtrl->sjw = 0;
pDev->pCtrl->tseg1 = 9; /* 9 time quanta in TSEG1 */
pDev->pCtrl->tseg2 = 2; /* 2 time quanta in TSEG2 */
pDev->pCtrl->samples = FALSE; /* FALSE means one sample per bit */
/*
* Configure CANCTL0 register, bits CSWAI, TIME, WUPE
* values only (the other bits are controlled by the driver).
*/
pMSCANdev->CANCTL0value = (CR0_RXFRM | CR0_WUPE);
/*
* Configure CANCTL1 register, bits CLKSRC, LOOPB, LISTEN,
* WUPE values only (the other bits are controlled by the driver).
*/
pMSCANdev->CANCTL1value = CR1_WUPM;
if (pMSCANboardCfg[ctrlNdx].clockSource > 0)
{
pMSCANdev->CANCTL1value |= CR1_CLKSRC;
}
/*
* Configure CANIDAC, IDAM bits only (the other bits are
* controlled by the driver).
* Use:
* IDAM_2_32BIT_FILTERS, IDAM_4_16BIT_FILTERS,
* IDAM_8_08BIT_FILTERS or IDAM_FILTER_CLOSED.
*/
pMSCANdev->CANIDACvalue = IDAM_2_32BIT_FILTERS;
/*
* Configure CANRIER register, RSTATE1, RSTATE0, TSTATE1, TSTATE0
* bits only (the other bits are controlled by the driver).
* Use:
* RX_RX_STATUS_CHANGE_0_ENB
* RX_RX_STATUS_CHANGE_1_ENB
* RX_RX_STATUS_CHANGE_2_ENB
* RX_RX_STATUS_CHANGE_3_ENB
* RX_TX_STATUS_CHANGE_0_ENB
* RX_TX_STATUS_CHANGE_1_ENB
* RX_TX_STATUS_CHANGE_2_ENB
* RX_TX_STATUS_CHANGE_3_ENB
*/
pMSCANdev->CANRIERvalue = (RX_RX_STATUS_CHANGE_1_ENB | RX_TX_STATUS_CHANGE_1_ENB);
break;
case MSCAN2_CTRL:
/*
* Example calculation for CAN bit timing:-
* Input clock freq: 66MHz
* Required CAN bit rate: 250kbps
*
* Time Quanta Frequency = 66MHz / 22 = 3MHz
*
* Number of time quanta = 12
*
* CAN Bit Rate = 3MHz / 12 = 250kbps
*
* 12 time quanta = 1 + TSEG1 + TSEG2
*
* CAN sample point = 10 Time quanta
*/
pDev->pCtrl->brp = 22; /* Baud rate prescale = 22 */
pDev->pCtrl->sjw = 0;
pDev->pCtrl->tseg1 = 9; /* 9 time quanta in TSEG1 */
pDev->pCtrl->tseg2 = 2; /* 2 time quanta in TSEG2 */
pDev->pCtrl->samples = FALSE; /* FALSE means one sample per bit */
/*
* Configure CANCTL0 register, bits RXFRM, CSWAI, TIME, WUPE
* values only (the other bits are controlled by the driver).
*/
pMSCANdev->CANCTL0value = (CR0_RXFRM | CR0_WUPE);
/*
* Configure CANCTL1 register, bits CLKSRC, LOOPB, LISTEN,
* WUPE values only (the other bits are controlled by the driver).
*/
pMSCANdev->CANCTL1value = CR1_WUPM;
if (pMSCANboardCfg[ctrlNdx].clockSource > 0)
{
pMSCANdev->CANCTL1value |= CR1_CLKSRC;
}
/*
* Configure CANIDAC, IDAM bits only (the other bits are
* controlled by the driver).
* Use:
* IDAM_2_32BIT_FILTERS, IDAM_4_16BIT_FILTERS,
* IDAM_8_08BIT_FILTERS or IDAM_FILTER_CLOSED.
*/
pMSCANdev->CANIDACvalue = IDAM_2_32BIT_FILTERS;
/*
* Configure CANRIER register, RSTATE1, RSTATE0, TSTATE1, TSTATE0
* bits only (the other bits are controlled by the driver).
* Use:
* RX_RX_STATUS_CHANGE_0_ENB
* RX_RX_STATUS_CHANGE_1_ENB
* RX_RX_STATUS_CHANGE_2_ENB
* RX_RX_STATUS_CHANGE_3_ENB
* RX_TX_STATUS_CHANGE_0_ENB
* RX_TX_STATUS_CHANGE_1_ENB
* RX_TX_STATUS_CHANGE_2_ENB
* RX_TX_STATUS_CHANGE_3_ENB
*/
pMSCANdev->CANRIERvalue = (RX_RX_STATUS_CHANGE_1_ENB | RX_TX_STATUS_CHANGE_1_ENB);
break;
default:
#if MSCAN_DRV_DEBUG
logMsg ("mpc5121eCan_cfg error: Id %d\n", pMSCANboardCfg[ctrlNdx].MSCANcontrollerId,2,3,4,5,6);
#endif
status = ERROR;
break;
}
/* Connect the interrupt to the controller */
if (status != ERROR)
{
if ((status = intConnect (pMSCANboardCfg[ctrlNdx].pIntVec,
(VOIDFUNCPTR) MOTMSCAN_ISR, (int)pDev) ) != OK)
{
#if MSCAN_DRV_DEBUG
logMsg("mpc5121eCan_init intConnect failed %d, %d\n", status,ctrlNdx,0,0,0,0);
#endif
status = ERROR;
}
}
return (status);
}
/************************************************************************
*
* mpc5121eCan_init - install driver for MPC5200 board
*
* This initialization routine is called the driver configlet code.
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_out_of_memory
* S_can_illegal_channel_no
*/
STATUS mpc5121eCan_init
(
mpc5121e_mscan_instance * pMSCANboardCfg
)
{
STATUS status = OK;
int i;
struct WNCAN_Board * pBrd;
struct WNCAN_Device * pDev;
struct WNCAN_Controller * pCtrlr;
#if MSCAN_DRV_DEBUG
logMsg("mpc5121eCan_init()\n",1,2,3,4,5,6);
#endif
/* Check if driver instance is already in use */
if (mpc5121e_cfgGet_inUse (BRD_NDX) == TRUE)
{
errnoSet (S_can_out_of_memory);
status = ERROR;
goto exit;
}
else
{
/* Set board as in use. */
mpc5121e_cfgSet_inUse (BRD_NDX, TRUE);
}
/* Configure the WNCAN_Board data */
pBrd = mpc5121e_cfgGet_canBoardPtr (BRD_NDX);
pBrd->xtalFreq = 0; /* Not used at board level, each controller can have different freq */
pBrd->irq = 0; /* Not used */
pBrd->ioAddress = 0; /* Not used */
pBrd->bar0 = 0; /* Not used */
pBrd->bar1 = 0; /* Not used */
pBrd->bar2 = 0; /* Not used */
/* Initialize each controller on the board */
for (i = 0; i < mpc5121e_cfgGet_NumControllers(); i++)
{
pDev = mpc5121e_cfgGet_canDevicePtr (BRD_NDX, i);
pCtrlr = mpc5121e_cfgGet_canControllerPtr (BRD_NDX, i);
/* Configure the WNCAN_Device data */
pDev->deviceName = mpc5121eCan_deviceName;
pDev->deviceId = i; /* Note, board number is always 0 for this device */
pDev->pCtrl = pCtrlr; /* Back pointer to WNCAN_Controller */
pDev->pBrd = mpc5121e_cfgGet_canBoardPtr (BRD_NDX); /* back pointer to board */
pDev->userData = NULL;
/* Configure the WNCAN_Controller data */
pCtrlr->ctrlID = (UCHAR)i;
pCtrlr->pDev = pDev; /* Backward pointer to WNCAN_Device */
pCtrlr->chnType = &g_MSCANchnType[0];
pCtrlr->numChn = MOTMSCAN_MAX_MSG_OBJ;
pCtrlr->chnMode = mpc5121e_cfgGet_chModePtr (BRD_NDX, i);
/* MSCAN pointer to driver specific data */
pCtrlr->csData = mpc5121e_cfgGet_mscanDevPtr (BRD_NDX, i);
/* Configure device specific data */
if ((status = mpc5121eCan_cfg (pMSCANboardCfg, i)) != OK)
{
#if MSCAN_DRV_DEBUG
logMsg ("mpc5121eCan_cfg failed: status %d, i %d\n", status,i,3,4,5,6);
#endif
status = ERROR;
break;
}
/* Establish WNCAN links */
if ((status = CAN_DEVICE_establishLinks (pDev, WNCAN_MPC5121E, WNCAN_MOTMSCAN)) == ERROR)
{
#if MSCAN_DRV_DEBUG
logMsg ("mpc5121eCan_init CAN_DEVICE_establishLinks failed, errno %d %d, pDev %08x, i %d\n",
(0xffff0000 & errnoGet ()) >> 16,
0x0000ffff & errnoGet (),
(int)pDev,i,0,0);
#endif
status = ERROR;
break;
}
}
exit:
return (status);
}
/************************************************************************
*
* mpc5121eCan_establishLinks - set up function pointers
*
* Set up function pointers for driver
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_illegal_config
*/
STATUS mpc5121eCan_establishLinks
(
struct WNCAN_Device *pDev
)
{
STATUS retCode = OK;
/* Initialize the WNCAN_Board struct */
pDev->pBrd->onEnterISR = NULL;
pDev->pBrd->onLeaveISR = NULL;
pDev->pBrd->enableIrq = NULL;
pDev->pBrd->disableIrq = NULL;
if (pDev->pCtrl->ctrlType == WNCAN_MOTMSCAN)
{
pDev->pBrd->canInByte = NULL;
pDev->pBrd->canOutByte = NULL;
}
else
{
errnoSet(S_can_illegal_config);
retCode = ERROR;
}
return (retCode);
}
/************************************************************************
*
* mpc5121eCan_open - open a CAN device
*
* RETURNS: pointer to a WNCAN_Device structure or NULL if error
*
* ERRNO: S_can_illegal_board_no
* S_can_illegal_ctrl_no
* S_can_busy
*/
struct WNCAN_Device * mpc5121eCan_open
(
UINT brdNdx,
UINT ctrlNdx
)
{
struct WNCAN_Device *pRet = NULL;
if ((brdNdx >= MAX_NUM_MPC5121E_CAN_BOARDS) || (mpc5121e_cfgGet_inUse (brdNdx) == FALSE))
{
errnoSet (S_can_illegal_board_no);
}
else if (ctrlNdx >= mpc5121e_cfgGet_NumControllers())
{
errnoSet (S_can_illegal_ctrl_no);
}
else if (mpc5121e_cfgGet_allocated (BRD_NDX, ctrlNdx) == TRUE)
{
errnoSet (S_can_busy);
}
else
{
mpc5121e_cfgSet_allocated (BRD_NDX, ctrlNdx, TRUE);
pRet = mpc5121e_cfgGet_canDevicePtr (BRD_NDX, ctrlNdx);
}
return (pRet);
}
/************************************************************************
*
* mpc5121eCan_close - close the CAN device
*
* RETURNS: OK
*
* ERRNO: N/A
*/
STATUS mpc5121eCan_close
(
struct WNCAN_Device * pDev
)
{
UINT ctrlNdx;
#if MSCAN_DRV_DEBUG
logMsg("mpc5121eCan_close() deviceId: %d\n", pDev->deviceId,0,0,0,0,0);
#endif
if(pDev != NULL)
{
ctrlNdx = (pDev->deviceId) & 0xFF;
mpc5121e_cfgSet_allocated (BRD_NDX, ctrlNdx, FALSE);
}
return (OK);
}
+495
View File
@@ -0,0 +1,495 @@
/* mpc5200Can.c - implementation of Board Interface for the MPC5200 */
/* Copyright 1984-2004 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01b,25jun04,bjn Change name of MPC5200CAN_DEBUG to MSCAN_DRV_DEBUG
01a,23oct03,bjn written
*/
/*
DESCRIPTION
This file contains the functions that provide a board-level interface
to the MPC5200 microcontroller.
*/
/* log message debugging */
#if 0
#define MSCAN_DRV_DEBUG 1
#endif
/* includes */
#include <vxWorks.h>
#include <errnoLib.h>
#include <intLib.h>
#include <iv.h>
#include <sysLib.h>
#if MSCAN_DRV_DEBUG
#include <logLib.h>
#endif
#include "CAN/wnCAN.h"
#include "CAN/canController.h"
#include "CAN/canBoard.h"
#include "CAN/motMsCan.h"
#include "CAN/motMsCanOffsets.h"
#include "CAN/private/mpc5200Can.h"
IMPORT void MOTMSCAN_ISR (struct WNCAN_Device *);
/* globals */
LOCAL const char mpc5200Can_deviceName[] ="Motorola-MPC5200 MSCAN";
/* external reference */
IMPORT STATUS CAN_DEVICE_establishLinks (WNCAN_DEVICE * pDev,
WNCAN_BoardType brdType,
WNCAN_ControllerType ctrlType);
IMPORT void MOTMSCAN_ISR (struct WNCAN_Device * pDev);
/************************************************************************
*
* mpc5200Can_cfg - Configure MSCAN device specific data
*
* RETURNS: OR or ERROR
*
* ERRNO: N/A
*/
LOCAL STATUS mpc5200Can_cfg
(
mpc5200_mscan_instance * pMSCANboardCfg,
UINT ctrlNdx
)
{
STATUS status = OK;
struct WNCAN_Device * pDev;
struct WNCAN_Controller * pCtrlr;
MSCAN_DEV * pMSCANdev;
#if MSCAN_DRV_DEBUG
logMsg("mpc5200Can_cfg ctrlNdx %d, MSCAN %d, intNum %d, freq %d, Reg Base 0x%08x\n",
ctrlNdx,
pMSCANboardCfg[ctrlNdx].MSCANcontrollerId,
pMSCANboardCfg[ctrlNdx].intNum,
pMSCANboardCfg[ctrlNdx].freq,
(int)pMSCANboardCfg[ctrlNdx].pDevBaseAddr,
0);
#endif
pDev = mpc5200_cfgGet_canDevicePtr (BRD_NDX, ctrlNdx);
pCtrlr = mpc5200_cfgGet_canControllerPtr (BRD_NDX, ctrlNdx);
pMSCANdev = (MSCAN_DEV *)pCtrlr->csData;
pMSCANdev->pMSCANregs = pMSCANboardCfg[ctrlNdx].pDevBaseAddr;
pMSCANdev->intNum = pMSCANboardCfg[ctrlNdx].intNum;
pMSCANdev->freq = pMSCANboardCfg[ctrlNdx].freq;
switch (pMSCANboardCfg[ctrlNdx].MSCANcontrollerId)
{
case MSCAN1_CTRL:
/*
* Example calculation for CAN bit timing:-
* Input clock freq: 66MHz
* Required CAN bit rate: 250kbps
*
* Time Quanta Frequency = 66MHz / 22 = 3MHz
*
* Number of time quanta = 12
*
* CAN Bit Rate = 3MHz / 12 = 250kbps
*
* 12 time quanta = 1 + TSEG1 + TSEG2
*
* CAN sample point = 10 Time quanta
*/
pDev->pCtrl->brp = 22; /* Baud rate prescale = 22 */
pDev->pCtrl->sjw = 0;
pDev->pCtrl->tseg1 = 9; /* 9 time quanta in TSEG1 */
pDev->pCtrl->tseg2 = 2; /* 2 time quanta in TSEG2 */
pDev->pCtrl->samples = FALSE; /* FALSE means one sample per bit */
/*
* Configure CANCTL0 register, bits CSWAI, TIME, WUPE
* values only (the other bits are controlled by the driver).
*/
pMSCANdev->CANCTL0value = (CR0_RXFRM | CR0_WUPE);
/*
* Configure CANCTL1 register, bits CLKSRC, LOOPB, LISTEN,
* WUPE values only (the other bits are controlled by the driver).
*/
pMSCANdev->CANCTL1value = CR1_WUPM;
if (pMSCANboardCfg[ctrlNdx].clockSource > 0)
{
pMSCANdev->CANCTL1value |= CR1_CLKSRC;
}
/*
* Configure CANIDAC, IDAM bits only (the other bits are
* controlled by the driver).
* Use:
* IDAM_2_32BIT_FILTERS, IDAM_4_16BIT_FILTERS,
* IDAM_8_08BIT_FILTERS or IDAM_FILTER_CLOSED.
*/
pMSCANdev->CANIDACvalue = IDAM_2_32BIT_FILTERS;
/*
* Configure CANRIER register, RSTATE1, RSTATE0, TSTATE1, TSTATE0
* bits only (the other bits are controlled by the driver).
* Use:
* RX_RX_STATUS_CHANGE_0_ENB
* RX_RX_STATUS_CHANGE_1_ENB
* RX_RX_STATUS_CHANGE_2_ENB
* RX_RX_STATUS_CHANGE_3_ENB
* RX_TX_STATUS_CHANGE_0_ENB
* RX_TX_STATUS_CHANGE_1_ENB
* RX_TX_STATUS_CHANGE_2_ENB
* RX_TX_STATUS_CHANGE_3_ENB
*/
pMSCANdev->CANRIERvalue = (RX_RX_STATUS_CHANGE_1_ENB | RX_TX_STATUS_CHANGE_1_ENB);
break;
case MSCAN2_CTRL:
/*
* Example calculation for CAN bit timing:-
* Input clock freq: 66MHz
* Required CAN bit rate: 250kbps
*
* Time Quanta Frequency = 66MHz / 22 = 3MHz
*
* Number of time quanta = 12
*
* CAN Bit Rate = 3MHz / 12 = 250kbps
*
* 12 time quanta = 1 + TSEG1 + TSEG2
*
* CAN sample point = 10 Time quanta
*/
pDev->pCtrl->brp = 22; /* Baud rate prescale = 22 */
pDev->pCtrl->sjw = 0;
pDev->pCtrl->tseg1 = 9; /* 9 time quanta in TSEG1 */
pDev->pCtrl->tseg2 = 2; /* 2 time quanta in TSEG2 */
pDev->pCtrl->samples = FALSE; /* FALSE means one sample per bit */
/*
* Configure CANCTL0 register, bits RXFRM, CSWAI, TIME, WUPE
* values only (the other bits are controlled by the driver).
*/
pMSCANdev->CANCTL0value = (CR0_RXFRM | CR0_WUPE);
/*
* Configure CANCTL1 register, bits CLKSRC, LOOPB, LISTEN,
* WUPE values only (the other bits are controlled by the driver).
*/
pMSCANdev->CANCTL1value = CR1_WUPM;
if (pMSCANboardCfg[ctrlNdx].clockSource > 0)
{
pMSCANdev->CANCTL1value |= CR1_CLKSRC;
}
/*
* Configure CANIDAC, IDAM bits only (the other bits are
* controlled by the driver).
* Use:
* IDAM_2_32BIT_FILTERS, IDAM_4_16BIT_FILTERS,
* IDAM_8_08BIT_FILTERS or IDAM_FILTER_CLOSED.
*/
pMSCANdev->CANIDACvalue = IDAM_2_32BIT_FILTERS;
/*
* Configure CANRIER register, RSTATE1, RSTATE0, TSTATE1, TSTATE0
* bits only (the other bits are controlled by the driver).
* Use:
* RX_RX_STATUS_CHANGE_0_ENB
* RX_RX_STATUS_CHANGE_1_ENB
* RX_RX_STATUS_CHANGE_2_ENB
* RX_RX_STATUS_CHANGE_3_ENB
* RX_TX_STATUS_CHANGE_0_ENB
* RX_TX_STATUS_CHANGE_1_ENB
* RX_TX_STATUS_CHANGE_2_ENB
* RX_TX_STATUS_CHANGE_3_ENB
*/
pMSCANdev->CANRIERvalue = (RX_RX_STATUS_CHANGE_1_ENB | RX_TX_STATUS_CHANGE_1_ENB);
break;
default:
#if MSCAN_DRV_DEBUG
logMsg ("mpc5200Can_cfg error: Id %d\n", pMSCANboardCfg[ctrlNdx].MSCANcontrollerId,2,3,4,5,6);
#endif
status = ERROR;
break;
}
/* Connect the interrupt to the controller */
if (status != ERROR)
{
if ((status = intConnect (pMSCANboardCfg[ctrlNdx].pIntVec,
(VOIDFUNCPTR) MOTMSCAN_ISR, (int)pDev) ) != OK)
{
#if MSCAN_DRV_DEBUG
logMsg("mpc5200Can_init intConnect failed %d, %d\n", status,ctrlNdx,0,0,0,0);
#endif
status = ERROR;
}
}
return (status);
}
/************************************************************************
*
* mpc5200Can_init - install driver for MPC5200 board
*
* This initialization routine is called the driver configlet code.
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_out_of_memory
* S_can_illegal_channel_no
*/
STATUS mpc5200Can_init
(
mpc5200_mscan_instance * pMSCANboardCfg
)
{
STATUS status = OK;
int i;
struct WNCAN_Board * pBrd;
struct WNCAN_Device * pDev;
struct WNCAN_Controller * pCtrlr;
#if MSCAN_DRV_DEBUG
logMsg("mpc5200Can_init()\n",1,2,3,4,5,6);
#endif
/* Check if driver instance is already in use */
if (mpc5200_cfgGet_inUse (BRD_NDX) == TRUE)
{
errnoSet (S_can_out_of_memory);
status = ERROR;
goto exit;
}
else
{
/* Set board as in use. */
mpc5200_cfgSet_inUse (BRD_NDX, TRUE);
}
/* Configure the WNCAN_Board data */
pBrd = mpc5200_cfgGet_canBoardPtr (BRD_NDX);
pBrd->xtalFreq = 0; /* Not used at board level, each controller can have different freq */
pBrd->irq = 0; /* Not used */
pBrd->ioAddress = 0; /* Not used */
pBrd->bar0 = 0; /* Not used */
pBrd->bar1 = 0; /* Not used */
pBrd->bar2 = 0; /* Not used */
/* Initialize each controller on the board */
for (i = 0; i < mpc5200_cfgGet_NumControllers(); i++)
{
pDev = mpc5200_cfgGet_canDevicePtr (BRD_NDX, i);
pCtrlr = mpc5200_cfgGet_canControllerPtr (BRD_NDX, i);
/* Configure the WNCAN_Device data */
pDev->deviceName = mpc5200Can_deviceName;
pDev->deviceId = i; /* Note, board number is always 0 for this device */
pDev->pCtrl = pCtrlr; /* Back pointer to WNCAN_Controller */
pDev->pBrd = mpc5200_cfgGet_canBoardPtr (BRD_NDX); /* back pointer to board */
pDev->userData = NULL;
/* Configure the WNCAN_Controller data */
pCtrlr->ctrlID = (UCHAR)i;
pCtrlr->pDev = pDev; /* Backward pointer to WNCAN_Device */
pCtrlr->chnType = &g_MSCANchnType[0];
pCtrlr->numChn = MOTMSCAN_MAX_MSG_OBJ;
pCtrlr->chnMode = mpc5200_cfgGet_chModePtr (BRD_NDX, i);
/* MSCAN pointer to driver specific data */
pCtrlr->csData = mpc5200_cfgGet_mscanDevPtr (BRD_NDX, i);
/* Configure device specific data */
if ((status = mpc5200Can_cfg (pMSCANboardCfg, i)) != OK)
{
#if MSCAN_DRV_DEBUG
logMsg ("mpc5200Can_cfg failed: status %d, i %d\n", status,i,3,4,5,6);
#endif
status = ERROR;
break;
}
/* Establish WNCAN links */
if ((status = CAN_DEVICE_establishLinks (pDev, WNCAN_MPC5200, WNCAN_MOTMSCAN)) == ERROR)
{
#if MSCAN_DRV_DEBUG
logMsg ("mpc5200Can_init CAN_DEVICE_establishLinks failed, errno %d %d, pDev %08x, i %d\n",
(0xffff0000 & errnoGet ()) >> 16,
0x0000ffff & errnoGet (),
(int)pDev,i,0,0);
#endif
status = ERROR;
break;
}
}
exit:
return (status);
}
/************************************************************************
*
* mpc5200Can_establishLinks - set up function pointers
*
* Set up function pointers for driver
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_illegal_config
*/
STATUS mpc5200Can_establishLinks
(
struct WNCAN_Device *pDev
)
{
STATUS retCode = OK;
/* Initialize the WNCAN_Board struct */
pDev->pBrd->onEnterISR = NULL;
pDev->pBrd->onLeaveISR = NULL;
pDev->pBrd->enableIrq = NULL;
pDev->pBrd->disableIrq = NULL;
if (pDev->pCtrl->ctrlType == WNCAN_MOTMSCAN)
{
pDev->pBrd->canInByte = NULL;
pDev->pBrd->canOutByte = NULL;
}
else
{
errnoSet(S_can_illegal_config);
retCode = ERROR;
}
return (retCode);
}
/************************************************************************
*
* mpc5200Can_open - open a CAN device
*
* RETURNS: pointer to a WNCAN_Device structure or NULL if error
*
* ERRNO: S_can_illegal_board_no
* S_can_illegal_ctrl_no
* S_can_busy
*/
struct WNCAN_Device * mpc5200Can_open
(
UINT brdNdx,
UINT ctrlNdx
)
{
struct WNCAN_Device *pRet = NULL;
#if MSCAN_DRV_DEBUG
logMsg("mpc5200Can_open() brdNdx: %d ctrlNdx %d\n",
brdNdx, ctrlNdx, 0,0,0,0);
#endif
if ((brdNdx >= MAX_NUM_MPC5200CAN_BOARDS) || (mpc5200_cfgGet_inUse (brdNdx) == FALSE))
{
errnoSet (S_can_illegal_board_no);
}
else if (ctrlNdx >= mpc5200_cfgGet_NumControllers())
{
errnoSet (S_can_illegal_ctrl_no);
}
else if (mpc5200_cfgGet_allocated (BRD_NDX, ctrlNdx) == TRUE)
{
errnoSet (S_can_busy);
}
else
{
mpc5200_cfgSet_allocated (BRD_NDX, ctrlNdx, TRUE);
pRet = mpc5200_cfgGet_canDevicePtr (BRD_NDX, ctrlNdx);
}
return (pRet);
}
/************************************************************************
*
* mpc5200Can_close - close the CAN device
*
* RETURNS: OK
*
* ERRNO: N/A
*/
STATUS mpc5200Can_close
(
struct WNCAN_Device * pDev
)
{
UINT ctrlNdx;
#if MSCAN_DRV_DEBUG
logMsg("mpc5200Can_close() deviceId: %d\n", pDev->deviceId,0,0,0,0,0);
#endif
if(pDev != NULL)
{
ctrlNdx = (pDev->deviceId) & 0xFF;
mpc5200_cfgSet_allocated (BRD_NDX, ctrlNdx, FALSE);
}
return (OK);
}
+346
View File
@@ -0,0 +1,346 @@
/* msmcan.c - implementation of Board Interface for MSM CAN PC104 */
/* Copyright 2001, 2013 Wind River Systems, Inc. */
/*
modification history
--------------------
01b,09sep13,xms fix CHECKED_RETURN error. (WIND00414265)
01a,03sep04,??? set default baud rate to 125 Kbps
14dec01,dnb written
*/
/*
DESCRIPTION
This file contains the functions that provide a board-level interface
to the MSM CAN PC104 card.
*/
/* includes */
#include <vxWorks.h>
#include <errnoLib.h>
#include <intLib.h>
#include <iv.h>
#include <sysLib.h>
#include <string.h> /* for strtok_r */
#include <CAN/wnCAN.h>
#include <CAN/canController.h>
#include <CAN/canBoard.h>
#include <CAN/i82527.h>
#include <CAN/private/msmcan.h>
#if (CPU != SH7750)
static const char deviceName[] ="MSMCAN PC104";
struct MSMCAN_PC104_DeviceEntry *msmcan_pc104_DeviceArray;
UINT max_msmcan_pc104_boards;
/* external reference */
STATUS CAN_DEVICE_establishLinks(WNCAN_DEVICE *pDev, WNCAN_BoardType brdType,
WNCAN_ControllerType ctrlType);
/************************************************************************
*
* msmcan_pc104_isr - board-level isr
*
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
static void msmcan_pc104_isr
(
ULONG param
)
{
struct MSMCAN_PC104_DeviceEntry *pDE;
pDE = (struct MSMCAN_PC104_DeviceEntry *)param;
if(pDE->allocated)
{
i82527ISR((ULONG)&pDE->canDevice);
}
return;
}
/************************************************************************
*
* msmcan_pc104_enableIrq - enable irq on board
*
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
static void msmcan_pc104_enableIrq
(
struct WNCAN_Device *pDev
)
{
return;
}
/************************************************************************
*
* msmcan_pc104_disableIrq - disable irq on board
*
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
static void msmcan_pc104_disableIrq
(
struct WNCAN_Device *pDev
)
{
return;
}
/************************************************************************
*
* msmcan_pc104_200_new - install driver for pc104 board
*
*
* RETURNS: OK or ERROR
*
* ERRNO: N/A
*
*/
STATUS msmcan_pc104_new
(
ULONG ioAddress,
UINT irq
)
{
UINT i;
UINT brdNdx=0xff;
int oldLevel;
STATUS retCode;
VOIDFUNCPTR* irqVec = 0;
struct WNCAN_Device *pDev;
struct MSMCAN_PC104_DeviceEntry *pDeviceEntry;
retCode = ERROR; /* pessimistic */
pDeviceEntry = 0;
/* find a free device data structure */
for(i = 0 ; i < max_msmcan_pc104_boards; i++)
{
if(msmcan_pc104_DeviceArray[i].inUse == 0)
{
msmcan_pc104_DeviceArray[i].inUse = 1;
pDeviceEntry = &msmcan_pc104_DeviceArray[i];
brdNdx = i;
break;
}
}
if(!pDeviceEntry)
{
errnoSet(S_can_out_of_memory);
goto exit;
}
/* setup data structures */
pDev = &pDeviceEntry->canDevice;
pDev->pCtrl = &pDeviceEntry->canController;
pDev->pBrd = &pDeviceEntry->canBoard;
pDev->deviceName = deviceName;
pDev->pBrd->irq = irq;
pDev->pBrd->ioAddress = ioAddress;
pDev->pBrd->xtalFreq = _16MHZ;
/* set default baud rate to 125 Kbits/sec */
pDev->pCtrl->brp = 3;
pDev->pCtrl->sjw = 0;
pDev->pCtrl->tseg1 = 0xc;
pDev->pCtrl->tseg2 = 0x1;
pDev->pCtrl->samples = 0;
pDev->pCtrl->chnType = g_i82527chnType;
pDev->pCtrl->chnMode = &pDeviceEntry->i82527chnMode[0];
pDev->pCtrl->numChn = I82527_MAX_MSG_OBJ;
pDev->pCtrl->csData = &pDeviceEntry->can82527;
if(CAN_DEVICE_establishLinks(pDev, WNCAN_MSMCAN, WNCAN_I82527) == ERROR)
{
pDev = 0;
goto exit;
}
pDev->deviceId = brdNdx; /* index into deviceEntry array */
/* connect to isr */
oldLevel = intLock();
#if CPU_FAMILY == I80X86
irqVec = INUM_TO_IVEC(irq+0x20);
#elif CPU_FAMILY == PPC
irqVec = INUM_TO_IVEC(irq+0x40);
#else
#warning irqVec not defined
#endif
/* don't need return from function call */
(void) intConnect(irqVec,msmcan_pc104_isr, (ULONG)pDeviceEntry);
/* activate interrupt at board and cpu level */
#if (CPU_FAMILY == I80X86)
sysIntEnablePIC(pDev->pBrd->irq);
#elif CPU_FAMILY == PPC
intEnable(pDev->pBrd->irq+0x40);
#else
#warning interrupts cannot be enabled
#endif
intUnlock(oldLevel);
pDeviceEntry->ioAddress = ioAddress;
pDeviceEntry->irq = irq;
retCode = OK;
exit:
return retCode;
}
/************************************************************************
*
* msmcan_pc104_canInByte
*
*
* RETURNS:
*
* ERRNO:
*
*/
static UCHAR msmcan_pc104_canInByte
(
struct WNCAN_Device *pDev,
unsigned int offset
)
{
sysOutByte(pDev->pBrd->ioAddress + 1,offset);
return sysInByte(pDev->pBrd->ioAddress);
}
/************************************************************************
*
* msmcan_pc104_canOutByte
*
*
* RETURNS:
*
* ERRNO:
*
*/
static void msmcan_pc104_canOutByte
(
struct WNCAN_Device *pDev,
unsigned int offset,
UCHAR value
)
{
sysOutByte(pDev->pBrd->ioAddress + 1,offset);
sysOutByte(pDev->pBrd->ioAddress, value);
}
/************************************************************************
*
* msmcan_pc104_establishLinks - set up function pointers
*
*
* RETURNS: OK always
*
* ERRNO: N/A
*
*/
STATUS msmcan_pc104_establishLinks(struct WNCAN_Device *pDev)
{
pDev->pBrd->onEnterISR = 0;
pDev->pBrd->onLeaveISR = 0;
pDev->pBrd->enableIrq = msmcan_pc104_enableIrq;
pDev->pBrd->disableIrq = msmcan_pc104_disableIrq;
pDev->pBrd->canInByte = msmcan_pc104_canInByte;
pDev->pBrd->canOutByte = msmcan_pc104_canOutByte;
return OK;
}
/************************************************************************
*
* msmcan_pc104_open - open a CAN device
*
* RETURNS: pointer to a WNCAN_Device structure or 0 if error
*
* ERRNO: S_can_illegal_board_no
* S_can_illegal_ctrl_no
* S_can_busy
*
*/
struct WNCAN_Device *msmcan_pc104_open(UINT brdNdx, UINT ctrlNdx)
{
struct WNCAN_Device *pRet = 0; /* pessimistic */
if((brdNdx >= max_msmcan_pc104_boards) ||
(msmcan_pc104_DeviceArray[brdNdx].inUse == 0))
{
errnoSet(S_can_illegal_board_no);
}
else if(msmcan_pc104_DeviceArray[brdNdx].allocated == 1)
{
errnoSet(S_can_busy);
}
else if(ctrlNdx >= MSMCAN_PC104_MAX_CONTROLLERS)
{
errnoSet(S_can_illegal_ctrl_no);
}
else
{
msmcan_pc104_DeviceArray[brdNdx].allocated = 1;
pRet = &msmcan_pc104_DeviceArray[brdNdx].canDevice;
}
return pRet;
}
/************************************************************************
*
* msmcan_pc104_close - close the specified CAN device
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
void msmcan_pc104_close(struct WNCAN_Device *pDev)
{
UINT brdNdx;
if (pDev != 0)
{
brdNdx = pDev->deviceId;
msmcan_pc104_DeviceArray[brdNdx].allocated = 0;
}
return;
}
#endif
File diff suppressed because it is too large Load Diff
+602
View File
@@ -0,0 +1,602 @@
/* wnCAN.c - implementation of Windnet CAN Interface */
/* Copyright 2001 Wind River Systems, Inc. */
/*
modification history
--------------------
01a,06oct05,lsg fix warning
09nov01,dnb modified for integration into Tornado
12jul01,jac written
*/
/*
DESCRIPTION
This file contains the functions that implement the interface defined in the
wnCAN.h header file.
*/
/* includes */
#include <vxWorks.h>
#include <errnoLib.h>
#include <CAN/wnCAN.h>
#include <CAN/canBoard.h>
#include <CAN/canController.h>
#include <CAN/canFixedLL.h>
/* global variables */
const static WNCAN_VersionInfo info = {1,3};
/************************************************************************
*
* WNCAN_GetVersion - return current major and minor revision
*
*
* RETURNS:pointer to WNCAN_VersionInfo
*
* ERRNO: N/A
*
*/
const WNCAN_VersionInfo *WNCAN_GetVersion(void)
{
return &info;
}
/************************************************************************
*
* defaultISRCallBack - do nothing but return
*
* The default ISR callback serves as a placeholder and does nothing
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
static void defaultISRCallback
(
WNCAN_DEVICE *pDev,
WNCAN_IntType stat,
UCHAR chnNum)
{
return;
}
/************************************************************************
*
* establishLinks - initialize function pointers in the Device structure
*
* This routine connects the function pointers in the CAN_Device
* data structure to the appropriate routines.
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_invalid_parameter
*
*/
STATUS CAN_DEVICE_establishLinks
(
WNCAN_DEVICE *pDev,
WNCAN_BoardType brdType,
WNCAN_ControllerType ctrlType
)
{
STATUS retCode = OK;
/* check for null pointer */
if(pDev == 0)
{
errnoSet(S_can_invalid_parameter);
retCode = ERROR;
}
else
{
/* save board and controller types */
pDev->pCtrl->ctrlType = ctrlType;
pDev->pBrd->brdType = brdType;
/* establish controller links */
retCode = WNCAN_Controller_establishLinks(pDev, ctrlType);
/* establish board links */
retCode = WNCAN_Board_establishLinks(pDev, brdType);
/* set default isr callback */
pDev->pISRCallback = defaultISRCallback;
}
return retCode;
}
/************************************************************************
*
* CAN_InstallISRCallback - initialize ISR callback
*
* RETURNS: OK or ERROR
*
* ERRNO: S_can_invalid_parameter
*
*/
STATUS CAN_InstallISRCallback
(
struct WNCAN_Device *pDev,
void (*pFun)(struct WNCAN_Device *pDev2,WNCAN_IntType
intStatus, UCHAR channelNum)
)
{
if(!pDev || !pFun)
{
errnoSet(S_can_invalid_parameter);
return ERROR;
}
else
pDev->pISRCallback = pFun;
return OK;
}
/************************************************************************
*
* WNCAN_Open - return a handle to the requested WNCAN_DEVICE
*
* RETURNS: pointer to valid WNCAN_DEVICE, or 0 if an error occurred
*
* ERRNO: N/A
*
*/
struct WNCAN_Device *WNCAN_Open
(
unsigned int brdType,
unsigned int brdNdx,
unsigned int ctrlNdx
)
{
return WNCAN_Board_Open(brdType, brdNdx, ctrlNdx);
}
/************************************************************************
*
* WNCAN_Close - close the handle to the requested WNCAN_DEVICE
*
* RETURNS: N/A
*
* ERRNO: N/A
*
*/
void WNCAN_Close
(
struct WNCAN_Device *pDev
)
{
if(pDev != NULL)
WNCAN_Board_Close(pDev);
return;
}
/************************************************************************
*
* WNCAN_GetMode - get the channel mode
*
* This routine returns the mode of the channel.
*
* RETURNS: the channel mode
*
* ERRNO: N/A
*
*/
WNCAN_ChannelMode WNCAN_GetMode(struct WNCAN_Device *pDev, UCHAR chn)
{
WNCAN_ChannelMode cm = WNCAN_CHN_INVALID;
if(chn < pDev->pCtrl->numChn)
cm = pDev->pCtrl->chnMode[chn];
return cm;
}
/************************************************************************
* WNCAN_SetMode - set the mode of the channel.
*
* This function sets the mode of the channel to one of five values:
* WNCAN_CHN_TRANSMIT, WNCAN_CHN_RECEIVE, WNCAN_CHN_INACTIVE,
* and in addition for advanced controllers,
* WNCAN_CHN_RTR_REQUESTER, or WNCAN_CHN_RTR_RESPONDER.
* All available channels can be configured to be WNCAN_CHN_INACTIVE.
* The channels available for transmitting or receiving messages are
* determined by the device hardware, and therefore ,may or may not be
* configurable with this function call. If an attempt is made to set the mode
* of a channel to WNCAN_CHN_RTR_RESPONDER or WNCAN_CHN_RTR_REQUESTER for a
* simple CAN controller such as SJA1000, WNCAN_CHN_INVALID is returned and an
* and errorno is set to reflect the error.
* The preferred approach is to allow the device driver to manage the channels
* internally using the CAN_GetTxChannel(), CAN_GetRxChannel(),
* CAN_GetRTRRequesterChannel(), CAN_GetRTRResponderChannel() and
* CAN_FreeChannel() function calls.
*
* WNCAN_SetMode, does not affect channel setting in hardware.
*
* RETURNS: ERROR if the requested channel number is out of range,
* OK otherwise
*
* ERRNO: S_can_illegal_channel_no
*
*/
STATUS WNCAN_SetMode(struct WNCAN_Device *pDev, UCHAR channelNum,
WNCAN_ChannelMode mode)
{
STATUS retCode = OK;
if(channelNum >= pDev->pCtrl->numChn)
{
errnoSet(S_can_illegal_channel_no);
retCode = ERROR;
}
else
{
switch(mode)
{
case WNCAN_CHN_TRANSMIT:
if((pDev->pCtrl->chnType[channelNum] == WNCAN_CHN_TRANSMIT) ||
(pDev->pCtrl->chnType[channelNum] == WNCAN_CHN_TRANSMIT_RECEIVE))
{
pDev->pCtrl->chnMode[channelNum] = WNCAN_CHN_TRANSMIT;
}
else
{
errnoSet(S_can_illegal_config);
retCode = ERROR;
}
break;
case WNCAN_CHN_RECEIVE:
if((pDev->pCtrl->chnType[channelNum] == WNCAN_CHN_RECEIVE) ||
(pDev->pCtrl->chnType[channelNum] == WNCAN_CHN_TRANSMIT_RECEIVE))
{
pDev->pCtrl->chnMode[channelNum] = WNCAN_CHN_RECEIVE;
}
else
{
errnoSet(S_can_illegal_config);
retCode = ERROR;
}
break;
case WNCAN_CHN_RTR_REQUESTER:
/* The hardware type of the channel will be transmit and receive only
in advanced controllers such as TouCAN and I82527 */
if(pDev->pCtrl->chnType[channelNum] == WNCAN_CHN_TRANSMIT_RECEIVE)
{
pDev->pCtrl->chnMode[channelNum] = WNCAN_CHN_RTR_REQUESTER;
}
else
{
errnoSet(S_can_rtr_mode_not_supported);
retCode = ERROR;
}
break;
case WNCAN_CHN_RTR_RESPONDER:
/* The hardware type of the channel will be transmit and receive only
in advanced controllers such as TouCAN and I82527 */
if(pDev->pCtrl->chnType[channelNum] == WNCAN_CHN_TRANSMIT_RECEIVE)
{
pDev->pCtrl->chnMode[channelNum] = WNCAN_CHN_RTR_RESPONDER;
}
else
{
errnoSet(S_can_rtr_mode_not_supported);
retCode = ERROR;
}
break;
case WNCAN_CHN_INVALID:
pDev->pCtrl->chnMode[channelNum] = WNCAN_CHN_INVALID;
break;
case WNCAN_CHN_INACTIVE:
pDev->pCtrl->chnMode[channelNum] = WNCAN_CHN_INACTIVE;
break;
default:
errnoSet(S_can_illegal_config);
retCode = ERROR;
break;
}
}
return retCode;
}
/************************************************************************
*
* WNCAN_GetTxChannel - get a free transmit channel
*
* This function returns a free channel uniquely identified by the output
* argument "channelNum". The mode of the assigned channel is WNCAN_CHN_TRANSMIT,
* A subsequent call to CAN_GetTxChannel() assigns the next available channel
* with a different channel number.
* The channel number remains unavailable to subsequent CAN_GetXXChannel()
* calls until a CAN_FreeChannel() call is invoked on the channel.
* CAN_FreeChannel() makes the channel available and resets the mode to
* WNCAN_CHN_INVALID. After the CAN_GetTxChannel() call, the mode of
* the channel can be changed by the CAN_SetMode(..) function call.
*
* By default, channel is disabled. User must call CAN_EnableChannel, to make the
* channel valid in hardware and enable channel interrupts
*
* RETURNS: ERROR if no channels are available, OK otherwise.
*
* ERRNO: S_can_no_available_channels, S_can_chn_in_use
*
*/
STATUS WNCAN_GetTxChannel(struct WNCAN_Device *pDev, UCHAR *channelNum)
{
UCHAR i;
STATUS retCode = ERROR; /* assume failure */
for(i = 0; i < pDev->pCtrl->numChn; i++)
{
if(pDev->pCtrl->chnMode[i] == WNCAN_CHN_INVALID)
{
if(WNCAN_SetMode(pDev,i,WNCAN_CHN_TRANSMIT) == OK)
{
*channelNum = i;
retCode = OK;
return retCode;
}
}
}
errnoSet(S_can_no_available_channels);
return retCode;
}
/************************************************************************
* WNCAN_GetRxChannel - get a free receive channel.
*
* Gets a free receive channel uniquely identified by the output argument
* "channelNum". The mode of the assigned channel is WNCAN_CHN_RECEIVE,
* A subsequent call to CAN_GetRxChannel() assigns the next available receive
* channel with a different number.
* The channel number remains unavailable to subsequent CAN_GetXXChannel()
* calls until a CAN_FreeChannel() call is invoked on the channel.
* CAN_FreeChannel() makes the channel available and resets the mode to
* WNCAN_CHN_INVALID. After the CAN_GetRxChannel() call, the mode of
* the channel can be changed by the CAN_SetMode() function call.
*
* By default, channel is disabled. User must call CAN_EnableChannel, to make the
* channel valid in hardware and enable channel interrupts
*
* RETURNS: ERROR if no channel is available, OK otherwise.
*
* ERRNO: S_can_no_available_channels
*
*/
STATUS WNCAN_GetRxChannel(struct WNCAN_Device *pDev, UCHAR *channelNum)
{
UCHAR i;
STATUS retCode = ERROR; /* assume failure */
for(i = 0; i < pDev->pCtrl->numChn; i++)
{
if(pDev->pCtrl->chnMode[i] == WNCAN_CHN_INVALID)
{
if(WNCAN_SetMode(pDev,i,WNCAN_CHN_RECEIVE) == OK)
{
*channelNum = i;
retCode = OK;
return retCode;
}
}
}
errnoSet(S_can_no_available_channels);
return retCode;
}
/************************************************************************
* WNCAN_GetRTRResponderChannel - get a free channel for programming an automatic
* response to an incoming remote request
*
* This function is relevant to advanced controllers only. Advanced controllers,
* are controllers such as TouCAN whose channels have the capability in
* hardware to both transmit and receive a message in the same channel.
* An WNCAN_CHN_RTR_RESPONDER channel, can be programmed with data and id.
* If a matching remote request is received in the channel, the hardware will
* automatically respond with the programmed data
*
* This function will return an error and set an error number, for simple
* controllers such as the SJA1000. In case of simple controllers, the channels
* do not have the capability to both transmit and receive messages in the same
* channel. The channel has a fixed property of either transmitting or
* receiving a message.
*
* This function returns a free transmit-receive channel uniquely identified by
* the output argument "channelNum". The mode assigned to the channel is
* WNCAN_CHN_RTR_RESPONDER. A subsequent call to CAN_GetRTRResponderChannel()
* assigns the next available channel with a different channel number.
* The channel number remains unavailable to subsequent CAN_GetXXChannel() and
* calls until a CAN_FreeChannel() call is invoked on the channel.
* CAN_FreeChannel() makes the channel available and resets the mode to
* WNCAN_CHN_INVALID. After the CAN_GetRTRResponderChannel() call, the mode of
* the channel can be changed by the CAN_SetMode(..) function call.
*
* By default, channel is disabled. User must call CAN_EnableChannel, to make the
* channel valid in hardware and enable channel interrupts
*
* RETURNS: for advanced controllers such as the TouCAN and I82527:
* ERROR if no channels are available, OK otherwise.
*
* for simple controllers such as the SJA1000:
* ERROR since this mode cannot be assigned.
*
* ERRNO: for advanced controllers such as the TouCAN and I82527:
* S_can_no_available_channels
*
* for simple controllers such as the SJA1000:
* S_can_rtr_mode_not_supported
*
*/
STATUS WNCAN_GetRTRResponderChannel(struct WNCAN_Device *pDev, UCHAR *channelNum)
{
UCHAR i;
BOOL notSupported = FALSE;
for(i = 0; i < pDev->pCtrl->numChn; i++)
{
if(pDev->pCtrl->chnMode[i] == WNCAN_CHN_INVALID) {
if(pDev->pCtrl->chnType[i] == WNCAN_CHN_TRANSMIT_RECEIVE) {
pDev->pCtrl->chnMode[i] = WNCAN_CHN_RTR_RESPONDER;
*channelNum = i;
return OK;
}
else
notSupported = TRUE;
}
}
/* if we fall thru, channel not allocated, return
** appropriate error
*/
errnoSet( (notSupported ? S_can_rtr_mode_not_supported
: S_can_no_available_channels) );
return ERROR;
}
/************************************************************************
* WNCAN_GetRTRRequesterChannel - get a free channel for sending an RTR request
* and receiving the response in the same channel
*
* This function is relevant to advanced controllers only. Advanced controllers,
* are controllers such as TouCAN that, have channels with the capability in
* hardware to both transmit and receive a message in the same channel.
* When a remote request is sent out from a particular channel, the reply
* will be received in the same channel. This function will return an error
* and set an error number, for simple controllers such as the SJA1000.
* In case of simple controllers, the channels do not have the capability to
* both transmit and receive messages in the same channel. The channel has a
* fixed property of either transmitting or receiving a message.
*
* This function returns a free channel uniquely identified by the output argument
* "channelNum". The mode of the channel is assigned WNCAN_CHN_RTR_REQUESTER.
* A subsequent call to CAN_GetRTRRequesterChannel() assigns the next available
* channel with a different channel number.
* The channel number remains unavailable to subsequent CAN_GetXXChannel()
* calls until a CAN_FreeChannel() call is invoked on the channel.
* CAN_FreeChannel() makes the channel available and resets the mode to
* WNCAN_CHN_INVALID. After the CAN_GetRTRRequesterChannel() call, the mode of
* the channel can be changed by the CAN_SetMode(..) function call.
*
* By default, channel is disabled. User must call CAN_EnableChannel, to make the
* channel valid in hardware and enable channel interrupts
*
* RETURNS: for advanced controllers such as the TouCAN and I82527:
* ERROR if no channels are available, OK otherwise.
*
* for simple controllers such as the SJA1000:
* ERROR since this mode cannot be assigned.
*
* ERRNO: for advanced controllers such as the TouCAN and I82527:
* S_can_no_available_channels
*
* for simple controllers such as the SJA1000:
* S_can_rtr_mode_not_supported
*/
STATUS WNCAN_GetRTRRequesterChannel(struct WNCAN_Device *pDev, UCHAR *channelNum)
{
UCHAR i;
BOOL notSupported = FALSE;
for(i = 0; i < pDev->pCtrl->numChn; i++)
{
if(pDev->pCtrl->chnMode[i] == WNCAN_CHN_INVALID) {
if(pDev->pCtrl->chnType[i] == WNCAN_CHN_TRANSMIT_RECEIVE)
{
pDev->pCtrl->chnMode[i] = WNCAN_CHN_RTR_REQUESTER;
*channelNum = i;
return OK;
}
else
notSupported = TRUE;
}
}
/* if we fall thru, channel not allocated, return
** appropriate error
*/
errnoSet( (notSupported ? S_can_rtr_mode_not_supported
: S_can_no_available_channels) );
return ERROR;
}
/************************************************************************
*
* WNCAN_FreeChannel - free the channel
*
* This routine frees the channel such that a WNCAN_GetTxChannel() or
* WNCAN_GetRxChannel() call can use the channel number. The mode of the
* channel is set to WNCAN_CHN_INVALID.
*
* RETURNS: OK, or ERROR
*
* ERRNO: S_can_illegal_channel_no
*
*/
STATUS WNCAN_FreeChannel(struct WNCAN_Device *pDev, UCHAR channelNum)
{
STATUS retCode = ERROR; /* assume failure */
if(channelNum >= pDev->pCtrl->numChn)
{
errnoSet(S_can_illegal_channel_no);
return retCode;
}
pDev->pCtrl->chnMode[channelNum] = WNCAN_CHN_INVALID;
retCode =OK;
return retCode;
}
/************************************************************************
*
* WNCAN_core_init - initialize persistent data structures
*
* This routine initializes any persistent data structures used
* by the WNCAN core library.
* It is called via component init routine and should occur
* before all other component init routines are called.
* RETURNS: none
*
*/
void wncan_core_init(void)
{
/* initialize the global linked lists for the boards and controllers */
BOARDLL_INIT();
CONTROLLERLL_INIT();
}
File diff suppressed because it is too large Load Diff
+84
View File
@@ -0,0 +1,84 @@
# Makefile - makefile for target/src/drv
#
# Copyright (c) 1996, 1998, 2001, 2003-2005, 2007-2010, 2012 Wind River Systems, Inc.
#
# The right to copy, distribute, modify or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
# modification history
# --------------------
# 01u,10oct12,x_z added mtd directory.
# 01u,04dec12,kch Exclude end subdir if _WRS_CONFIG_NO_IP is defined.
# 01t,18feb10,pch small footprint
# 01s,29dec09,h_k removed unsupported module builds from LP64.
# 01r,05may09,l_z add usb2 for SMP
# 01q,23sep08,pee adding wlan for SMP, WIND00135265
# 01p,04jul08,jpb Edited SMP conditional.
# 01o,08oct07,mdo Need to add i2c
# 01n,02aug07,pmr add hdisk and dma for SMP
# 01m,11jul07,pch also include wdb and usb in SMP build
# 01l,10jul07,pch include erf in SMP build
# 01k,06jul07,pch don't build this subdirectory for SMP
# 01j,26aug05,ebh Eliminated reference to vxFusion
# 01i,15apr05,jlk Added Event Reporting Framework dir to make
# 01h,03feb05,rfr Added manager and xbd to directories compiled by the
# simulator
# 01g,14jun04,dgp add DOC_OPTS = -mg -nostrict -missingok
# 01f,03nov03,dat remove netif from vxsim build
# 01e,09nov01,jmp specified subdirs to build for simulators only.
# 01d,12oct01,tam added repackaging support
# 01c,04jun98,dat removed unnecessary EXTRA_INCLUDE, removed bspVersion.o
# 01b,06jan98,cym Changed -I to $(OPTION_INCLUDE_DIR) to decouple from GNU
# 01a,18jun96,yp created from 01f of MakeSkel
#
# DESCRIPTION
# This file contains the makefile rules for building the vx library
#
#*/
TGT_DIR=$(WIND_BASE)/target
LIB_BASE_NAME=drv
# Including defs.library to see if any pertinent _WRS_CONFIG* is defined.
# It must be after LIB_BASE_NAME
include $(TGT_DIR)/h/make/defs.library
OBJS=
DOC_OPTS = -mg -nostrict -missingok
#
# Cases which do not want to build everything:
# _WRS_CONFIG_MEM_ALLOT, which may as well not build anything requiring malloc;
# simulators, which do not need drivers for real hardware devices;
# SMP and LP64, which support only VxBus drivers for real hardware devices,
# but do require some utility functions from the end and usb subtrees.
#
ifdef _WRS_CONFIG_MEM_ALLOT
SUBDIRS=dma i2c sio timer
else
ifneq ($(subst SIM,,$(CPU)),$(CPU))
SUBDIRS=end erf wdb manager xbd mtd
else
ifdef _WRS_CONFIG_LP64
SUBDIRS=end erf wdb manager usb usb2 xbd $(wildcard wlan)
else
ifdef _WRS_CONFIG_SMP
SUBDIRS=end erf wdb manager usb usb2 xbd mtd hdisk dma i2c $(wildcard wlan)
endif
endif
endif
#
# Exclude 'end' subdir if vsb is configured with no networking support.
#
ifdef _WRS_CONFIG_NO_IP
EXCLUDE_SUBDIRS = end $(wildcard wlan)
endif
endif
include $(TGT_DIR)/h/make/rules.library
+31
View File
@@ -0,0 +1,31 @@
# Makefile - makefile for bsp/src/drv/dma
#
# modification history
# --------------------
# 01i,15aug05,kkz Updating doc values
# 01h,29jul05,dee add new target for PIIX4 dma support
# 01g,29apr05,kkz Updating for new doc directory
# 01f,27may04,dgp change output dir and TOC structure (DOC_CHAPTER & DOC_DIR)
# 01e,17feb04,pch remove PPC32 hack, no longer needed
# 01d,31jan03,pch Add PPC32 support
# 01c,12mar02,dat SPR 72518 Drivers docs in separate directory
# 01b,12oct01,tam added repackaging support
# 01a,18jun96,yp created from 01d of MakeSkel
#
# DESCRIPTION
# This file contains the makefile rules for building the vx library
#
#*/
TGT_DIR=$(WIND_BASE)/target
LIB_BASE_NAME=drv
EXTRA_INCLUDE=-I$(WIND_BASE)/target/h/
OBJS= l64853Dma.o i8237Dma.o iPIIX4Dma.o
include $(TGT_DIR)/h/make/rules.library
CC_OPTIM=$(CC_OPTIM_DRIVER)
include $(TGT_DIR)/h/make/defs.drivers
+132
View File
@@ -0,0 +1,132 @@
/* i8237Dma.c - i8237 dma device driver */
/*
* Copyright (c) 1993, 1995, 2010 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01c,09mar10,cwl correct the number of transactions. (WIND00045562)
01b,14jun95,hdn removed function declarations defined in sysLib.h
01a,28sep93,hdn written.
*/
/*
DESCRIPTION
SEE ALSO:
.pG "I/O System"
*/
#include "vxWorks.h"
#include "memLib.h"
#include "stdlib.h"
#include "errnoLib.h"
#include "stdio.h"
#include "sysLib.h"
#include "ioLib.h"
#include "cacheLib.h"
#include "sys/fcntlcom.h"
#include "drv/dma/i8237Dma.h"
/* global */
int dmaDebug = 0;
/* local */
LOCAL int dma1PageReg[] = {0x87, 0x83, 0x81, 0x82};
LOCAL int dma2PageReg[] = {0x8b, 0x89, 0x8a, 0x8f};
/* function prototypes */
int dmaSetup (int direction, void *pBuf, UINT nBytes, UINT chan);
/* setup DMA controller */
STATUS dmaSetup
(
int direction,
void *pBuf,
UINT nBytes,
UINT chan
)
{
char modeReg;
if ((chan > 7) || (nBytes > (1 << 16)))
{
printf ("dmaSetup: impossible request\n");
(void) errnoSet (S_ioLib_DEVICE_ERROR);
return (ERROR);
}
if (direction == O_RDONLY)
modeReg = DMA_MODE_SINGLE | DMA_MODE_READ | (chan & 0x03);
else
modeReg = DMA_MODE_SINGLE | DMA_MODE_WRITE | (chan & 0x03);
if (dmaDebug)
{
printf ("dir=0x%x pBuf=0x%x nBytes=%d chan=%d mode=0x%x\n",
direction, (int)pBuf, nBytes, chan, modeReg);
}
if ((chan & 4) == 0)
{
cacheInvalidate (DATA_CACHE, pBuf, nBytes);
sysOutByte (DMA1_MASK_SINGLE, DMA_MASK_SET | (chan & 0x03));
sysDelay ();
sysOutByte (DMA1_MODE, modeReg);
sysDelay ();
sysOutByte (DMA1_CLEAR_FF, 0);
sysDelay ();
sysOutByte (DMA1_ADDR(chan), (int)pBuf & 0x000000ff);
sysDelay ();
sysOutByte (DMA1_ADDR(chan), ((int)pBuf & 0x0000ff00) >> 8);
sysDelay ();
sysOutByte (dma1PageReg[chan & 0x03], ((int)pBuf & 0x00ff0000) >> 16);
sysDelay ();
sysOutByte (DMA1_COUNT(chan), --nBytes & 0x000000ff);
sysDelay ();
sysOutByte (DMA1_COUNT(chan), (nBytes & 0x0000ff00) >> 8);
sysDelay ();
sysOutByte (DMA1_MASK_SINGLE, DMA_MASK_RESET | (chan & 0x03));
sysDelay ();
}
else
{
cacheFlush (DATA_CACHE, pBuf, nBytes);
sysOutByte (DMA2_MASK_SINGLE, DMA_MASK_SET | (chan & 0x03));
sysDelay ();
sysOutByte (DMA2_MODE, modeReg);
sysDelay ();
sysOutByte (DMA2_CLEAR_FF, 0);
sysDelay ();
sysOutByte (DMA2_ADDR(chan), ((int)pBuf & 0x000001fe) >> 1);
sysDelay ();
sysOutByte (DMA2_ADDR(chan), ((int)pBuf & 0x0001fe00) >> 9);
sysDelay ();
sysOutByte (dma2PageReg[chan & 0x03], ((int)pBuf & 0x00ff0000) >> 16);
sysDelay ();
nBytes >>= 1;
sysOutByte (DMA2_COUNT(chan), --nBytes & 0x000000ff);
sysDelay ();
sysOutByte (DMA2_COUNT(chan), (nBytes & 0x0000ff00) >> 8);
sysDelay ();
sysOutByte (DMA2_MASK_SINGLE, DMA_MASK_RESET | (chan & 0x03));
sysDelay ();
}
return (OK);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+241
View File
@@ -0,0 +1,241 @@
/* m5200Sdma.c - m5200 SDMA driver support */
/*
* Copyright (c) 2003-2005, 2010 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01f,04jan10,wqi Omit the OR conjunction.(WIND00141923)
01e,18mar05,j_b code cleanup (apigen)
01d,24feb05,j_b add function header blocks
01c,27dec04,k_p fixed diab compilation error, changed the macro
#define MBAR_VALUE (vxMBarGet()) to
#define MBAR_VALUE ((unsigned long)vxMBarGet()).
01b,05mar04,bjn Modified to build as driver source rather than from sysLib.c
01a,17Jul03,pkr written
*/
/*
DESCRIPTION
Provide support for SDMA Bestcomm API.
*/
/*
change log details
------------------
01b * Building m5200Sdma.c from the BSP file sysLib.c caused the Tornado
project creation to fail when building dependencies for the Diab
toolchain. Since this file does not depend a great deal on the BSP
configuration files, it can be built as a standalone driver and the
BSP just links agains the object code.
* Variable: MBarGlobal also defined in bestcomm_api.c - removed duplicate
from this file.
* Variable: sysSDMA - moved this global to sysLib.c.
*/
#include "vxWorks.h"
#include "logLib.h"
#include "iv.h"
#include "intLib.h"
#include "drv/intrCtl/m5200Intr.h"
#include "drv/dma/m5200Sdma.h"
#include "bestcomm_api.h"
#include "task_api/bestcomm_cntrl.h"
#include "task_api/bestcomm_api_mem.h"
extern FUNCPTR _func_sdmaIntEnableRtn;
extern FUNCPTR _func_sdmaIntDisableRtn;
extern FUNCPTR _func_sdmaIntSetLevelRtn;
extern void m5200SdmaIntTrigger(int intNum);
extern void * vxMBarGet (void);
#define MBAR_VALUE ((unsigned long)vxMBarGet())
/*******************************************************************************
*
* sdmaIntSetLevel - set SDMA interrupt level
*
* This routine sets the SDMA interrupt level.
*
* RETURNS: OK always
*/
LOCAL STATUS sdmaIntSetLevel
(
int intNum,
int level
)
{
/* TBD */
return OK;
}
/*******************************************************************************
*
* sdmaDemuxInt - handle SDMA interrupt
*
* This routine determines and calls the proper SDMA interrupt handler.
*
* RETURNS: N/A
*/
LOCAL void sdmaDemuxInt
(
int arg
)
{
int pend = sysSDMA->IntPend & ~(sysSDMA->IntMask);
int intNum = -1;
int i, msk;
if (pend & 0x10000000)
intNum = INUM_SDMA_TEA;
else
for (i = INUM_SDMA_TASK0, msk=1; i <= INUM_SDMA_TASK15; i++, msk<<=1)
{
if ((pend & msk) != 0)
{
sysSDMA->IntPend = msk; /* clear pending int */
intNum = i;
break;
}
}
if (intNum >= 0)
m5200SdmaIntTrigger(intNum);
}
/*******************************************************************************
*
* sdmaTeaInt - handle TEA interrupt
*
* This routine clears and logs the a TEA interrupt.
*
* RETURNS: N/A
*/
LOCAL void sdmaTeaInt
(
int arg
)
{
int taskNum = ((sysSDMA->IntPend)>>24)&0xF;
sysSDMA->IntPend |= 0x10000000; /* clear the event */
logMsg("SDMA: TEA detected in task %d\n",taskNum,2,3,4,5,6);
}
LOCAL STATUS sdmaIntEnable(int intNum);
LOCAL STATUS sdmaIntDisable(int intNum);
/*******************************************************************************
*
* sysSdmaInit - initialize BestComm SDMA support
*
* This routine sets up the SmartDMA module and BestComm API.
*
* RETURNS: OK always
*/
STATUS sysSdmaInit
(
)
{
sysSDMA->taskBar = (unsigned long)SRAM_BASE_ADRS;
/* set up SDMA interrupt support */
sysSDMA->IntMask = 0xffffffff;
sysSDMA->IntPend = 0xffffffff;
_func_sdmaIntEnableRtn = sdmaIntEnable;
_func_sdmaIntDisableRtn = sdmaIntDisable;
_func_sdmaIntSetLevelRtn = sdmaIntSetLevel;
intConnect (IV_BESTCOMM, sdmaDemuxInt, 0);
intEnable(INUM_BESTCOMM);
intConnect (IV_SDMA_TEA, sdmaTeaInt, 0);
intEnable(INUM_SDMA_TEA);
/* set up BestComm support */
TasksInitAPI ((void *)MBAR_VALUE);
TasksLoadImage (sysSDMA);
sysSDMA->IPR[0] = 7;
#ifdef UN_USED_CODE
/*
* Set core and BestComm XLB priority the same.
*/
*XLB_MPER |= 0x5;
*XLB_MPR = 0x77777171;
#endif /* UN_USED_CODE */
/*
* Turn off COMM bus prefetch. This affects all data movements on
* the COMM bus. (Yes, _PE -- prefetch enable -- should probably be
* named _PD.)
*/
sysSDMA->PtdCntrl |= SDMA_PTDCNTRL_PE;
return OK;
}
/*******************************************************************************
*
* sdmaIntEnable - enable SDMA interrupt
*
* This routine enables the given SDMA interrupt.
*
* RETURNS: OK always
*/
LOCAL STATUS sdmaIntEnable
(
int intNum
)
{
/* range is checked in caller */
if (intNum == INUM_SDMA_TEA)
sysSDMA->IntMask &= 0xEFFFFFFF;
else
SDMA_INT_ENABLE( SDMA_INT_MASK, (intNum-INUM_SDMA_TASK0));
return OK;
}
/*******************************************************************************
*
* sdmaIntDisable - disable SDMA interrupt
*
* This routine disables the given SDMA interrupt.
*
* RETURNS: OK always
*/
LOCAL STATUS sdmaIntDisable
(
int intNum
)
{
/* range is checked in caller */
if (intNum == INUM_SDMA_TEA)
sysSDMA->IntMask |= 0x10000000;
else
SDMA_INT_DISABLE( SDMA_INT_MASK, (intNum-INUM_SDMA_TASK0));
return OK;
}
File diff suppressed because it is too large Load Diff
+208
View File
@@ -0,0 +1,208 @@
# Makefile - makefile for target/src/drv/end
#
# Copyright (c) 1996-2011 Wind River Systems, Inc.
#
# The right to copy, distribute, modify or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
# modification history
# --------------------
# 03j,19sep11,rlg remove bcm1250 elements
# 03i,29dec09,h_k removed unsupported module builds from LP64.
# 03h,12nov08,dlk Compile endCommon.o and endEtherHdr.o with CC_OPTIM_NORMAL.
# Turn off -fvolatile/-Xpointers-volatile for endCommon.o,
# endEtherHdr.o, endLib.o, and miiLib.o.
# 03g,07jul08,jpb Changed SMP conditional.
# 03f,21may08,dlk Add endCommon.o for simulators. Add endEtherHdr.o.
# 03e,14mar08,dlk MUX2 redesign.
# 03d,11apr07,rec add support for M5200
# 03c,06jul07,pch For SMP, build only endLib and miiLib
# 03b,26jun07,mze Only build smEnd.o smEndShow.o if not SMP
# 03a,09mar07,pes Update for new MIPS library structure.
# 02z,01jun06,wap Compile non-driver files with full optimization
# 02y,18nov05,j_b add motFecEnd for MCF5400
# 02x,12sep05,pch add amd8111LanEnd driver for maple BSP
# 02w,15aug05,kkz Updating doc values
# 02v,29apr05,kkz Updating for new doc directory
# 02u,31jan05,dtr Add in compilation of TSEC driver.
# 02t,07dec04,h_k removed sh7615End.
# 02s,15sep04,jln removed endNetBufLib.o
# 02r,21jun04,rcs removed ln7990End.o and ntEnd.o from OBJS_COMMON
# 02q,21jun04,mdo Remove deprecated motFccEnd.c.
# 02p,14jun04,h_k added wancomEnd for PPC604 and MIPS64.
# 02o,08jun04,jeg added smEnd support for simulators
# 02n,27may04,dgp change output dir and TOC structure (DOC_CHAPTER & DOC_DIR)
# 02n,04may04,pch SPR 94932: remove PPC32 special case
# 02m,01mar04,jln add smEnd/smEndShow
# 02l,04feb04,pch PPC32 floating-point adjustments
# 02k,10dec03,pch restored emacEnd, motCpmEnd, motFcc2End, motFccEnd,
# nicEvbEnd which are still used
# 02j,05dec03,rcs removed unsupported files from DOC_FILES and OBJS_COMMON
# 02i,14jul03,jln add emacEnd.c
# 02h,14apr03,pch Add PPC32 support
# 02g,21mar03,rcs Added endNetBufLib.o to OBJS_COMMON SPR# 87039
# 02f,03feb03,m_h Shorten list of IPv6 supported drivers
# 02e,14jan03,m_h IPv6 support
# 02e,14jan03,gjc SPR#85164 and SPR#85093
# Adding motFcc2End.c and m8260SccEnd.c
# 02d,20jun02,pgh Add bcm1250MacEnd.c.
# 02c,17may02,zmm Global au1000 name changes. SPR 77333.
# 02b,12mar02,dat SPR 72518 Drivers docs in separate directory
# 02a,16nov01,dgp remove ntEnd.c from doc build
# 01z,09nov01,jmp only build endLib.o for simulators.
# 01y,12oct01,tam added repackaging support
# 01x,14jun01,rcs added gei82543End
# 01w,17sep99,ms_ add motFccEnd
# 01v,14apr99,cn added miiLib
# 01w,01jun01,mem Added au1000End.c
# 01v,14apr99,cn added miiLib
# 01z,11oct00,zl build sh7615End.o for SH7600 only
# 01y,29aug00,rsh add sh7615End device to build list
# 01x,17may00,zl corrected DOC_FILES for ns83902
# 01w,10apr00,zl renamed nicEnd to ns83902End
# 01v,07apr00,zl added nicEnd support
# 01u,16mar99,dat nicEvb is only for PPC403. mbcEnd only for 68302
# 01t,13mar99,db added mbcEnd support.
# 01s,12mar99,cn added el3c90xEnd support (SPR# 25327).
# 01r,12mar99,ms_ add elt3c509End.o to OBJS_COMMON
# 01q,11mar99,db added mb86960End support.
# 01p,08mar99,sbs added ultraEnd support.
# 01o,04mar99,cn added motFecEnd support (SPR# 23153).
# 01n,17feb99,sut added nicEvbEnd support.
# 01m,01feb99,jkf added ln97xEnd support.
# 01l,26jan99,dat merge from 1_0_x. (added motCpmEnd.c, ne2000End.c)
# 01k,01jun98,dat fixed EXTRA_INCLUDES to use TGT_DIR, added fei and olicom
# drivers.
# 01j,13mar98,cn added fei82557End to OBJS_COMMON and DOC_FILES.
# 01i,04may98,cym added ntEnd (Windows ULIP driver.)
# 01h,02apr98,jpd added iOlicomEnd driver to DOC_FILES
# 01g,06dec97,tam added dec21x4xEnd and removed dec21x40End.
# 01f,25aug97,vin deleted the sonic driver for the beta2 patch.
# 01e,03May97,sal restored sonic driver to DOC_FILES
# 01d,30apr97,jag deleted the sonic driver from the DOC_FILES due to man page
# errors.
# 01c,24apr97,map added dec21x40End
# 01b,18apr97,sal added the sn83932End.c
# 01a,28feb97,vin created from 01d of MakeSkel
#
# DESCRIPTION
# This file contains the makefile rules for building ENDs (Enhanced
# Network Drivers) into the VxWorks library.
#
# Old style network drivers (i.e. BSD style) are contained in src/drv/netif.
#
TGT_DIR=$(WIND_BASE)/target
LIB_BASE_NAME=drv
# Including defs.library to see if _WRS_CONFIG_SMP or _WRS_CONFIG_LP64 is
# defined.
# It must be after LIB_BASE_NAME
include $(TGT_DIR)/h/make/defs.library
DOC_FILES= emacEnd.c endCommon.c endLib.c endEtherHdr.c \
ne2000End.c dec21x40End.c \
fei82557End.c gei82543End.c iOlicomEnd.c elt3c509End.c \
ln97xEnd.c motFecEnd.c el3c90xEnd.c miiLib.c ns83902End.c \
auEnd.c motFcc2End.c m8260SccEnd.c \
smEnd.c smEndShow.c wancomEnd.c amd8111LanEnd.c
EXTRA_INCLUDE=-I$(TGT_DIR)/h/
OBJS_COMMON = endCommon.o endLib.o endEtherHdr.o \
ne2000End.o dec21x40End.o \
fei82557End.o gei82543End.o iOlicomEnd.o ln97xEnd.o \
elt3c509End.o el3c90xEnd.o miiLib.o ns83902End.o \
smEnd.o smEndShow.o
OBJS_MCF5400 = motFecEnd.o
OBJS_MIPSI32 = auEnd.o
OBJS_MIPSI64 = wancomEnd.o
OBJS_PPC403 = nicEvbEnd.o
OBJS_PPC405 = emacEnd.o
OBJS_PPC440 = emacEnd.o
OBJS_PPC603 = motFcc2End.o m8260SccEnd.o
OBJS_PPC604 = wancomEnd.o
OBJS_PPC860 = motCpmEnd.o motFecEnd.o
OBJS_PPC32 = emacEnd.o nicEvbEnd.o motFcc2End.o m8260SccEnd.o \
motCpmEnd.o motFecEnd.o wancomEnd.o motTsecEnd.o \
amd8111LanEnd.o
ifdef _WRS_CONFIG_LP64
OBJS = endCommon.o endLib.o endEtherHdr.o
else
ifdef _WRS_CONFIG_SMP
OBJS = endCommon.o endLib.o endEtherHdr.o miiLib.o
else
OBJS = $(OBJS_COMMON) $(OBJS_$(CPU))
endif
endif
#
# redefine OBJS for simulators since only endLib.o need to be built
#
ifneq ($(subst SIM,,$(CPU)),$(CPU))
OBJS = endCommon.o endLib.o endEtherHdr.o smEnd.o smEndShow.o
endif
IPV6_OBJS_COMMON = endLib.o ne2000End.o dec21x40End.o \
fei82557End.o gei82543End.o iOlicomEnd.o ln97xEnd.o \
elt3c509End.o el3c90xEnd.o miiLib.o
# Suppress local build of generic drivers for all PPC except generic PPC32.
ifeq ($(VX_CPU_FAMILY),ppc)
ifneq ($(CPU),PPC32)
IPV6_OBJS_COMMON=
endif
endif
IPV6_OBJS_MCF5200 =
IPV6_OBJS_MCF5400 = motFecEnd.o
IPV6_OBJS_MIPSI32 = auEnd.o
IPV6_OBJS_MIPSI64 = wancomEnd.o
IPV6_OBJS_PPC403 = nicEvbEnd.o
IPV6_OBJS_PPC405 = emacEnd.o
IPV6_OBJS_PPC440 = emacEnd.o
IPV6_OBJS_PPC603 = motFcc2End.o m8260SccEnd.o
IPV6_OBJS_PPC604 = wancomEnd.o
IPV6_OBJS_PPC860 = motCpmEnd.o motFecEnd.o
IPV6_OBJS_PPC32 = emacEnd.o nicEvbEnd.o motFcc2End.o \
m8260SccEnd.o motCpmEnd.o motFecEnd.o wancomEnd.o \
amd8111LanEnd.o
ifdef _WRS_CONFIG_LP64
IPV6_OBJS = endLib.o
else
ifdef _WRS_CONFIG_SMP
IPV6_OBJS = endLib.o miiLib.o
else
IPV6_OBJS = $(IPV6_OBJS_COMMON) $(IPV6_OBJS_$(CPU))
endif
endif
ifneq ($(BUILD_IPV6),)
OBJS = $(IPV6_OBJS)
EXTRA_DEFINE += -DWR_IPV6
endif
# Unfortunately, adding $(CC_OPTIM_NORMAL) doesn't
# turn off -fvolatile or -Xpointers-volatile, so do it
# manually. Also, turn of -Xsize-opt=0 for diab.
ifeq ($(findstring gnu, $(TOOL)), gnu)
CFLAGS_endCommon.o = $(CC_OPTIM_NORMAL) -fno-volatile
CFLAGS_endEtherHdr.o = $(CC_OPTIM_NORMAL) -fno-volatile
CFLAGS_endLib.o = $(CC_OPTIM_NORMAL) -fno-volatile
CFLAGS_miiLib.o = $(CC_OPTIM_NORMAL) -fno-volatile
else
CFLAGS_endCommon.o = $(CC_OPTIM_NORMAL) -Xpointers-volatile=0 -Xsize-opt=0
CFLAGS_endEtherHdr.o = $(CC_OPTIM_NORMAL) -Xpointers-volatile=0 -Xsize-opt=0
CFLAGS_endLib.o = $(CC_OPTIM_NORMAL) -Xpointers-volatile=0 -Xsize-opt=0
CFLAGS_miiLib.o = $(CC_OPTIM_NORMAL) -Xpointers-volatile=0 -Xsize-opt=0
endif
include $(TGT_DIR)/h/make/rules.library
CC_OPTIM=$(CC_OPTIM_DRIVER)
include $(TGT_DIR)/h/make/defs.drivers
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+957
View File
@@ -0,0 +1,957 @@
/* endCommon.c - common support for END2/END/NPT style network drivers */
/*
* Copyright (c) 2008-2009, 2013 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use of this
* software may be licensed only pursuant to the terms of an applicable Wind
* River license agreement.
*/
/*
modification history
--------------------
01l,04sep13,xms fix CHECKED_RETURN error. (WIND00414265)
01k,04may09,cww Updated wdStart parameter types
01j,29apr09,h_k updated for LP64 support.
01i,24nov08,dlk Go to new scalable semaphore APIs to avoid inlining
causing code size increase.
01h,27aug08,dlk Move from deprecated 'minimal' semaphore API to 'inline' API.
Use inline semaphores for both UP and SMP.
01g,12jun08,dlk Initialize pEndObj->pMib2Tbl in endM2Init().
01f,03jun08,dlk Move MCACHE stuff to endLib.c also.
01e,21may08,dlk Move the endPool infrastructure to endLib.c.
01d,12may08,dlk Move _func_end2VxBusConnect here from ipcom_end2.c for
scalability.
01c,11may08,dlk Small documentation correction.
01b,26mar08,dlk Move end8023AddressForm(), endEtherAddressForm(),
endEtherPacketDataGet(), and endEtherPacketAddrGet()
from here to endLib.c.
01a,14mar08,dlk Written. Copied most contents from endLib.c.
*/
/*
DESCRIPTION
This library contains support routines common to all styles of VxWorks
network driver (END2, END, and NPT).
Support routines for END2-style drivers only are found in end2Lib.
Support routines for END-style drivers only are found in endLib.
Support routines for NPT-style drivers only are found in nptLib.
Routines specific to particular drivers belong in the drivers themselves.
This library does contains some routines specific to particular classes
of drivers (e.g. ethernet drivers).
To use this feature, include the following component:
INCLUDE_END_COMMON
INCLUDE FILES: endLib.h
*/
/* includes */
#include <vxWorks.h>
#include <endLib.h>
#include <muxLib.h>
#include <string.h>
#include <private/muxLibP.h>
#include <memLib.h>
#include <stdlib.h>
#include <memPartLib.h>
#include <netBufLib.h> /* FIXME */
#include <etherMultiLib.h>
#include <netinet/if_ether.h>
#include <netLib.h>
#include <wdLib.h>
#include <m2IfLib.h>
#include <intLib.h>
#include <spinLockLib.h>
/* defines */
/* typedefs */
/* forward declarations */
STATUS _endM2Packet_1213 (END_OBJ *, M_BLK_ID, UINT);
STATUS _endM2Packet_2233 (END_OBJ *, M_BLK_ID, UINT);
/* globals */
MIB_ROUTINES * pMibRtn; /* structure to hold MIB-II callback pointers */
FUNCPTR endM2Packet = _endM2Packet_1213; /* default. can be set to 2233 */
u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
M_BLK_ID (*_func_endEtherAddressForm) ();
M_BLK_ID (*_func_end8023AddressForm) ();
STATUS (*_func_endEtherPacketDataGet) ();
STATUS (*_func_endEtherPacketAddrGet) (M_BLK_ID, M_BLK_ID,
M_BLK_ID, M_BLK_ID, M_BLK_ID);
VOIDFUNCPTR _func_end2VxBusConnect;
/* locals */
LOCAL void endPollStatsJobQueue (END_IFDRVCONF *);
LOCAL void endPollStatsPoll (END_IFDRVCONF *);
void endTxSemTake
(
END_OBJ* pEnd,
int tmout
)
{
#ifdef END_TX_SEM_INLINE
(void)semMTake_inline (pEnd->txSem, tmout, END_TXSEM_INLINE_OPTS);
#elif defined (END_TX_SEM_SCALABLE)
(void)semMTakeScalable (pEnd->txSem, tmout, END_TXSEM_SCALABLE_OPTS);
#else
(void)semTake(pEnd->txSem,tmout);
#endif
}
void endTxSemGive
(
END_OBJ* pEnd
)
{
#ifdef END_TX_SEM_INLINE
(void)semMGive_inline (pEnd->txSem, END_TXSEM_INLINE_OPTS);
#elif defined (END_TX_SEM_SCALABLE)
(void)semMGiveScalable (pEnd->txSem, END_TXSEM_SCALABLE_OPTS);
#else
(void)semGive (pEnd->txSem);
#endif
}
void endFlagsClr
(
END_OBJ* pEnd,
int clrBits
)
{
pEnd->flags &= ~clrBits;
}
void endFlagsSet
(
END_OBJ* pEnd,
int setBits
)
{
pEnd->flags |= (setBits);
}
int endFlagsGet
(
END_OBJ* pEnd
)
{
return(pEnd->flags);
}
int endMultiLstCnt
(
END_OBJ* pEnd
)
{
return(lstCount(&pEnd->multiList));
}
ETHER_MULTI* endMultiLstFirst
(
END_OBJ *pEnd
)
{
return((ETHER_MULTI *)(lstFirst(&pEnd->multiList)));
}
ETHER_MULTI* endMultiLstNext
(
ETHER_MULTI* pCurrent
)
{
return((ETHER_MULTI *)(lstNext(&pCurrent->node)));
}
char* endDevName
(
END_OBJ* pEnd
)
{
return(pEnd->devObject.name);
}
void endObjectUnload
(
END_OBJ* pEnd
)
{
if (pEnd->txSem != NULL)
semDelete (pEnd->txSem);
lstFree (&pEnd->multiList);
if (pEnd->pSnarf != NULL)
{
KHEAP_FREE (pEnd->pSnarf);
}
pEnd->devObject.dummyBinding = NULL;
pEnd->pSnarf = NULL;
pEnd->pTyped = NULL;
pEnd->pPromisc = NULL;
pEnd->pStop = NULL;
pEnd->nProtoSlots = 0;
}
/******************************************************************************
*
* endM2Init - Initialize MIB-II agnostically (1213 or 2233)
*
* This routine encapsulates and generalizes mib2Init and endObjFlagSet
*
* RETURNS: OK or ERROR.
*
* ERRNO
*
* \NOMANUAL
*/
STATUS endM2Init
(
END_OBJ * pEndObj, /* object to be initialized */
long ifType, /* ifType from m2Lib.h */
UCHAR * phyAddr, /* MAC/PHY address */
int addrLength, /* MAC/PHY address length */
int mtuSize, /* MTU size */
int speed, /* interface speed */
UINT flags /* flags to set in the pEndObj */
)
{
M2_INTERFACETBL *pM2Int; /* 1213 struct to be initialized */
int status;
pEndObj->pMib2Tbl = NULL;
if (pMibRtn == NULL) /* 1213? */
{
pM2Int = &(pEndObj->mib2Tbl);
status = mib2Init (pM2Int, ifType, phyAddr,
addrLength, mtuSize, speed);
}
else /* 2233? */
{
status = (pMibRtn->mibTblInit) (&pEndObj->end_m2Id, ifType,
phyAddr, addrLength,
mtuSize, speed,
pEndObj->devObject.name,
pEndObj->devObject.unit);
if (status == OK)
{
pEndObj->pMib2Tbl = &pEndObj->end_m2Id;
endM2Packet = _endM2Packet_2233;
flags |= END_MIB_2233;
}
}
endObjFlagSet (pEndObj, flags);
return status;
}
/******************************************************************************
*
* endM2Free - Frees what endM2Init allocates
*
* This routine determines what endM2Init created, and frees it
*
* RETURNS: OK or ERROR.
*
* ERRNO
*
* \NOMANUAL
*/
STATUS endM2Free
(
END_OBJ * pEndObj /* object where m2 data lives */
)
{
if (pEndObj->pMib2Tbl != &pEndObj->end_m2Id &&
pEndObj->pMib2Tbl != NULL)
return (pMibRtn->mibFree) (pEndObj->pMib2Tbl);
return OK;
}
/******************************************************************************
*
* endM2Ioctl - generic ioctl
*
* This routine handles the EIOCGMIB2 and EIOCGMIB2233 ioctls.
*
* RETURNS: OK or ERROR.
*
* ERRNO: EINVAL
*
* \NOMANUAL
*/
int endM2Ioctl
(
END_OBJ * pEndObj, /* object where m2 data lives */
UINT32 cmd, /* command to process */
caddr_t data /* pointer to data */
)
{
int error = OK;
switch (cmd)
{
case EIOCGMIB2:
if (data == NULL)
error=EINVAL;
else
bcopy ((char *) &pEndObj->mib2Tbl, (char *) data,
sizeof (pEndObj->mib2Tbl));
break;
case EIOCGMIB2233:
if ((data == NULL) || (pEndObj->pMib2Tbl == NULL))
error = EINVAL;
else
*((M2_ID **)data) = pEndObj->pMib2Tbl;
break;
default:
error = EINVAL;
break;
}
return (error);
}
/******************************************************************************
*
* _endM2Packet_1213 - count a packet assuming 1213
*
* This routine counts a packet in the absence of 2233.
*
* RETURNS: OK or ERROR.
*
* ERRNO
*
* \NOMANUAL
*/
STATUS _endM2Packet_1213
(
END_OBJ * pEndObj, /* object where counter lives */
M_BLK_ID pMblk, /* packet to count */
UINT ctrl /* M2_PACKET_IN OUT, etc. */
)
{
M2_INTERFACETBL *pMib = &(pEndObj->mib2Tbl); /* struct to be updated */
BOOL isNUcast = 0; /* is the packet non-unicast? */
int status = OK;
int nMACOffset = 0;
/* we know that the destination address is the first byte in the frame */
if (pMblk != NULL)
{
/*
* Special handling for 802.4 and 802.5. In 802.4,
* the destination address is preceded by a single
* frame control byte. In 802.5, the destination
* address is preceded by an access control byte
* and a frame control byte.
*/
if (pMib->ifType == M2_ifType_iso88024_tokenBus)
nMACOffset = 1;
if (pMib->ifType == M2_ifType_iso88025_tokenRing)
nMACOffset = 2;
isNUcast = (pMblk->mBlkHdr.mData[nMACOffset] & (UINT8) 0x01);
}
else
/* Don't go on */
return (ERROR);
switch (ctrl)
{
case M2_PACKET_IN_ERROR:
pMib->ifInErrors++;
break;
case M2_PACKET_IN:
if (isNUcast)
pMib->ifInNUcastPkts++;
else
pMib->ifInUcastPkts++;
pMib->ifInOctets += pMblk->mBlkPktHdr.len;
break;
case M2_PACKET_OUT_ERROR:
pMib->ifOutErrors++;
break;
case M2_PACKET_OUT:
if (isNUcast)
pMib->ifOutNUcastPkts++;
else
pMib->ifOutUcastPkts++;
pMib->ifOutOctets += pMblk->mBlkHdr.mLen;
break;
case M2_PACKET_IN_DISCARD:
pMib->ifInDiscards++;
break;
case M2_PACKET_OUT_DISCARD:
pMib->ifOutDiscards++;
break;
default:
status = ERROR;
break;
}
return status;
}
/******************************************************************************
*
* _endM2Packet_2233 - count a packet assuming 2233
*
* This routine counts a packet in the presence of 2233.
*
* RETURNS: OK or ERROR.
*
* ERRNO
*
* \NOMANUAL
*/
STATUS _endM2Packet_2233
(
END_OBJ * pEndObj, /* object where counter lives */
M_BLK_ID pMblk, /* packet to count */
UINT ctrl /* M2_PACKET_IN OUT, etc. */
)
{
int status = OK;
M2_ID * pMib2Tbl; /* RFC 2233 MIB objects */
pMib2Tbl = pEndObj->pMib2Tbl;
switch (ctrl)
{
case M2_PACKET_IN_ERROR:
status = (pMib2Tbl->m2CtrUpdateRtn) (pMib2Tbl,
M2_ctrId_ifInErrors, 1);
break;
case M2_PACKET_IN:
case M2_PACKET_OUT:
status = (pMib2Tbl->m2PktCountRtn) (pMib2Tbl, ctrl,
(UCHAR *) pMblk->m_data,
(size_t) pMblk->m_pkthdr.len);
break;
case M2_PACKET_OUT_ERROR:
status = (pMib2Tbl->m2CtrUpdateRtn) (pMib2Tbl,
M2_ctrId_ifOutErrors, 1);
break;
case M2_PACKET_IN_DISCARD:
status = (pMib2Tbl->m2CtrUpdateRtn) (pMib2Tbl,
M2_ctrId_ifInDiscards, 1);
break;
case M2_PACKET_OUT_DISCARD:
status = (pMib2Tbl->m2CtrUpdateRtn) (pMib2Tbl,
M2_ctrId_ifOutDiscards, 1);
break;
default:
status = ERROR;
break;
}
return status;
}
/******************************************************************************
*
* endMibIfInit - Initialize the MIB-II callback pointers
*
* This routine initializes the MIB-II pointers used by the callback macros.
*
* RETURNS: OK or ERROR.
*
* ERRNO
*
* \NOMANUAL
*/
STATUS endMibIfInit
(
FUNCPTR pMibTblInitRtn,
FUNCPTR pMibAllocRtn,
FUNCPTR pMibFreeRtn,
FUNCPTR pMibCtrUpdate,
FUNCPTR pMibVarUpdate
)
{
if ((pMibTblInitRtn != NULL) &&
(pMibAllocRtn != NULL) && (pMibFreeRtn != NULL) &&
(pMibCtrUpdate != NULL) && (pMibVarUpdate != NULL))
{
if (pMibRtn == NULL)
{
if ((pMibRtn =
(MIB_ROUTINES *) KHEAP_ALLOC (sizeof (MIB_ROUTINES))) == NULL)
{
return(ERROR);
}
}
pMibRtn->mibTblInit = pMibTblInitRtn;
pMibRtn->mibAlloc = pMibAllocRtn; /* deprecate */
pMibRtn->mibFree = pMibFreeRtn; /* deprecate */
pMibRtn->mibCntUpdate = pMibCtrUpdate;
pMibRtn->mibVarUpdate = pMibVarUpdate;
return(OK);
}
else
{
return(ERROR);
}
}
/******************************************************************************
*
* mib2Init - initialize a MIB-II structure
*
* Initialize a MIB-II structure. Set all error counts to zero. Assume
* a 10Mbps Ethernet device.
*
* RETURNS: OK or ERROR.
*
* ERRNO
*/
STATUS mib2Init
(
M2_INTERFACETBL *pMib, /* struct to be initialized */
long ifType, /* ifType from m2Lib.h */
UCHAR * phyAddr, /* MAC/PHY address */
int addrLength, /* MAC/PHY address length */
int mtuSize, /* MTU size */
int speed /* interface speed */
)
{
/* Clear out our statistics. */
bzero ((char *)pMib, sizeof (*pMib));
pMib->ifPhysAddress.addrLength = addrLength;
/* Obtain our Ethernet address and save it */
bcopy ((char *) phyAddr, (char *)pMib->ifPhysAddress.phyAddress,
pMib->ifPhysAddress.addrLength);
/* Set static statistics. assume ethernet */
pMib->ifType = ifType;
pMib->ifMtu = mtuSize;
pMib->ifSpeed = speed;
return OK;
}
/******************************************************************************
*
* mib2ErrorAdd - change a MIB-II error count
*
* This function adds a specified value to one of the MIB-II error counters in a
* MIB-II interface table. The counter to be altered is specified by the
* errCode argument. errCode can be MIB2_IN_ERRS, MIB2_IN_UCAST, MIB2_OUT_ERRS
* or MIB2_OUT_UCAST. Specifying a negative value reduces the error count, a
* positive value increases the error count.
*
* RETURNS: OK
*
* ERRNO
*/
STATUS mib2ErrorAdd
(
M2_INTERFACETBL * pMib,
int errCode,
int value
)
{
switch (errCode)
{
default:
case MIB2_IN_ERRS:
pMib->ifInErrors += value;
break;
case MIB2_IN_UCAST:
pMib->ifInUcastPkts += value;
break;
case MIB2_OUT_ERRS:
pMib->ifOutErrors += value;
break;
case MIB2_OUT_UCAST:
pMib->ifOutUcastPkts += value;
break;
}
return OK;
}
/*******************************************************************************
*
* endObjInit - initialize an END_OBJ structure
*
* This routine initializes an END_OBJ structure and fills it with data from
* the argument list. It also creates and initializes semaphores and
* protocol list.
*
* RETURNS: OK or ERROR.
*
* ERRNO
*/
STATUS endObjInit
(
END_OBJ * pEndObj, /* object to be initialized */
DEV_OBJ* pDevice, /* ptr to device struct */
char * pBaseName, /* device base name, for example, "ln" */
int unit, /* unit number */
NET_FUNCS * pFuncTable, /* END device functions */
char* pDescription
)
{
size_t maxLen;
pEndObj->devObject.pDevice = pDevice;
/* Create the transmit semaphore. */
#ifdef END_TX_SEM_INLINE
pEndObj->txSem = semMCreate (END_TXSEM_INLINE_OPTS & SEM_MUT_OPTIONS_MASK);
#elif defined (END_TX_SEM_SCALABLE)
pEndObj->txSem = semMCreate (END_TXSEM_SCALABLE_OPTS & SEM_MUT_OPTIONS_MASK);
#else
pEndObj->txSem = semMCreate ( SEM_Q_PRIORITY |
SEM_DELETE_SAFE |
SEM_INVERSION_SAFE);
#endif
if (pEndObj->txSem == NULL)
{
return (ERROR);
}
/* Install data and functions into the network node. */
pEndObj->flags = 0;
/* initialize protocol table (empty) */
pEndObj->pSnarf = NULL;
pEndObj->pTyped = NULL;
pEndObj->pPromisc = NULL;
pEndObj->pStop = NULL;
pEndObj->nProtoSlots = 0;
/* Don't modify the strings passed as arguments! */
maxLen = sizeof(pEndObj->devObject.name) - 1;
strncpy (pEndObj->devObject.name, pBaseName, maxLen);
pEndObj->devObject.name [maxLen] = EOS;
maxLen = sizeof(pEndObj->devObject.description) - 1;
strncpy (pEndObj->devObject.description, pDescription, maxLen);
pEndObj->devObject.description [maxLen] = EOS;
pEndObj->devObject.unit = unit;
pEndObj->pFuncTable = pFuncTable;
/* Clear multicast info. */
lstInit (&pEndObj->multiList);
pEndObj->nMulti = 0;
pEndObj->devObject.dummyBinding = pEndObj;
return OK;
}
/*******************************************************************************
*
* endObjFlagSet - set the `flags' member of an END_OBJ structure
*
* As input, this routine expects a pointer to an END_OBJ structure
* (the <pEnd> parameter) and a flags value (the <flags> parameter).
* This routine sets the 'flags' member of the END_OBJ structure
* to the value of the <flags> parameter.
*
* Because this routine assumes that the driver interface is now up,
* this routine also sets the 'attached' member of the referenced END_OBJ
* structure to TRUE.
*
* RETURNS: OK
*
* ERRNO
*/
STATUS endObjFlagSet
(
END_OBJ * pEnd,
UINT flags
)
{
pEnd->attached = TRUE;
pEnd->flags = flags;
return OK;
}
/******************************************************************************
*
* endPollStatsPoll - poll an interface's information
*
* This routine calls the endPollStatsIfPoll() routine to gather
* information from a particular interface, then re-arms the interface's
* polling watchdog timer.
*
* RETURNS: N/A
*
* ERRNO
*/
LOCAL void endPollStatsPoll
(
END_IFDRVCONF *pDrvConf
)
{
if (pDrvConf == NULL)
return;
/* Gather the stats */
pDrvConf->ifPollRtn (pDrvConf);
/*
* Reload the watchdog.
* don't need return from function call
*/
(void) wdStart(pDrvConf->ifWatchdog, pDrvConf->ifPollInterval,
(WD_RTN) endPollStatsJobQueue, (_Vx_usr_arg_t) pDrvConf);
return;
}
/******************************************************************************
*
* endPollStatsJobQueue - polling stats counter scheduler routine
*
* This routine is an intermediary function necessitated by the fact
* that wdStart() only takes two arguments: we need to pass it three
* (netJobAdd(), plus two others). This routine just invokes netJobAdd()
* to call the endPollStatsIfPoll() routine and passes it a pointer to
* the END_IFDRVCONF structure being polled. We must use netJobAdd()
* here to avoid executing the rest of the polling code at interrupt
* context.
*
* RETURNS: N/A
*
* ERRNO
*/
LOCAL void endPollStatsJobQueue
(
END_IFDRVCONF *pDrvConf
)
{
if (netJobAdd ((FUNCPTR) endPollStatsPoll, (_Vx_usr_arg_t) pDrvConf, 0, 0, 0, 0)
!= OK)
{
/* Reload the watchdog. */
(void) wdStart(pDrvConf->ifWatchdog, pDrvConf->ifPollInterval,
(WD_RTN) endPollStatsJobQueue, (_Vx_usr_arg_t) pDrvConf);
}
return;
}
/******************************************************************************
*
* endPollStatsInit - initialize polling statistics updates
*
* This routine is used to begin polling of the interface specified by
* pCookie and will periodically call out to the pIfPollRtn function, which
* will collect the interface statistics. If the driver supports polling
* updates, this routine will start a watchdog that will invoke the
* pIfPollRtn routine periodically. The watchdog will automatically
* re-arm itself. The pIfPollRtn will be passed a pointer to the driver's
* END_IFDRVCONF structure as an argument.
*
* RETURNS: ERROR if the driver doesn't support polling, otherwise OK.
*
* ERRNO
*/
STATUS endPollStatsInit
(
void * pCookie,
FUNCPTR pIfPollRtn
)
{
END_IFDRVCONF * pDrvConf;
int error;
PROTOCOL_BINDING tmpBinding;
/* Sanity check */
if (pCookie == NULL || pIfPollRtn == NULL)
return (ERROR);
tmpBinding.pEnd = PDEVCOOKIE_TO_ENDOBJ(pCookie);
if (tmpBinding.pEnd == NULL)
return (ERROR);
/* Get this driver's configuration info */
error = muxIoctl ((void *)&tmpBinding, EIOCGPOLLCONF,
(caddr_t) &pDrvConf);
/* Return error if driver doesn't support stats polling. */
if (error)
return (error);
/* Create the watchdog. */
pDrvConf->ifWatchdog = wdCreate ();
if (pDrvConf->ifWatchdog == NULL)
return (ERROR);
pDrvConf->ifEndObj = NULL;
pDrvConf->ifMuxCookie = pCookie;
pDrvConf->ifPollRtn = pIfPollRtn;
/* Kick off the watchdog. */
return wdStart (pDrvConf->ifWatchdog, pDrvConf->ifPollInterval,
(WD_RTN) endPollStatsJobQueue, (_Vx_usr_arg_t) pDrvConf);
}
/******************************************************************************
*
* endEtherCrc32BeGet - calculate a big-endian CRC-32 checksum
*
* This routine performs a big endian CRC 32 calculation over an
* arbitrary block of data. Many ethernet controllers implement multicast
* filtering using a hash table where a CRC-32 checksum of the multicast
* group address is used as the table index. This function is provided
* as a convenience so that each driver doesn't need its own private copy.
*
* RETURNS: the 32-bit checksum of the supplied buffer
*
* ERRNO: N/A
*/
UINT32 endEtherCrc32BeGet
(
const UINT8 *pBuf,
size_t len
)
{
size_t i;
UINT32 crc, carry;
int bit;
UINT8 data;
crc = 0xffffffff; /* initial value */
for (i = 0; i < len; i++)
{
for (data = *pBuf++, bit = 0; bit < 8; bit++, data >>= 1)
{
carry = ((crc & 0x80000000) ? 1 : 0) ^ (data & 0x01);
crc <<= 1;
if (carry)
crc = (crc ^ ETHER_CRC_POLY_BE) | carry;
}
}
return (crc);
}
/******************************************************************************
*
* endEtherCrc32LeGet - calculate a little-endian CRC-32 checksum
*
* This routine performs a little endian CRC 32 calculation over an
* arbitrary block of data. Many ethernet controllers implement multicast
* filtering using a hash table where a CRC-32 checksum of the multicast
* group address is used as the table index. This function is provided
* as a convenience so that each driver doesn't need its own private copy.
*
* RETURNS: the 32-bit checksum of the supplied buffer
*
* ERRNO: N/A
*/
UINT32 endEtherCrc32LeGet
(
const UINT8 *pBuf,
size_t len
)
{
static const UINT32 crcTab[] =
{
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
size_t i;
UINT32 crc;
crc = 0xffffffff; /* initial value */
for (i = 0; i < len; i++)
{
crc ^= pBuf[i];
crc = (crc >> 4) ^ crcTab[crc & 0xf];
crc = (crc >> 4) ^ crcTab[crc & 0xf];
}
return (crc);
}
@@ -0,0 +1,403 @@
/* endEtherHdr.c - legacy mux/muxTk ethernet/802.3 header forming routines */
/*
* Copyright (c) 2008, 2013-2014 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use of this
* software may be licensed only pursuant to the terms of an applicable Wind
* River license agreement.
*/
/*
modification history
--------------------
12jun14,p_x check parameters of endEtherAddressForm(). (VXW6-82932)
01c,22sep13,xms fix NULL_RETURNS error. (WIND00414265)
01b,24nov08,dlk Add string.h header.
01a,21may08,dlk Written. Moved routines here from endLib.c.
*/
/*
DESCRIPTION
This library contains M_BLK-oriented routines used to construct and parse
Ethernet II or 802.3 link headers. These routines are referenced
by most END-style network drivers, but are also used by legacy M_BLK-
oriented protocols, even in the case that only END2 drivers are in
the system.
To use this feature, include the following component:
INCLUDE_END_ETHER_HDR
INCLUDE FILES: endLib.h
*/
#include <vxWorks.h>
#include <endLib.h>
#include <muxLib.h>
#include <string.h>
/* #include <private/muxLibP.h> */
#include <net/mbuf.h>
#include <netinet/if_ether.h>
#define LLC_SNAP_FRAMELEN 8
void endEtherHdrInit (void)
{
/*
* Function pointers used for scalability -- so that
* END2 drivers need not reference these routines
* directly to provide them when available for legacy
* protocols.
*/
_func_endEtherPacketDataGet = endEtherPacketDataGet;
_func_endEtherPacketAddrGet = endEtherPacketAddrGet;
_func_end8023AddressForm = end8023AddressForm;
_func_endEtherAddressForm = endEtherAddressForm;
}
/******************************************************************************
*
* end8023AddressForm - form an 802.3 address into a packet
*
* This routine accepts the source and destination addressing information
* through <pSrcAddr> and <pDstAddr> mBlks and returns an M_BLK_ID to the
* assembled link level header. If the <bcastFlag> argument is TRUE, it
* sets the destination address to the link-level broadcast address and
* ignores the <pDstAddr> contents. This routine prepends the link level header
* into <pMblk> if there is enough space available or it allocates a new
* mBlk/clBlk/cluster and prepends the new mBlk to the mBlk chain passed in
* <pMblk>. This routine returns a pointer to an mBlk which contains the
* link level header information.
*
* RETURNS: M_BLK_ID or NULL.
*
* ERRNO
*
* \NOMANUAL
*/
M_BLK_ID end8023AddressForm
(
M_BLK_ID pMblk,
M_BLK_ID pSrcAddr,
M_BLK_ID pDstAddr,
BOOL bcastFlag
)
{
short dataLen; /* length of data including LLC */
USHORT *pSrc;
USHORT *pDst;
struct llc * pLlc; /* link layer control header */
dataLen = pMblk->mBlkPktHdr.len + LLC_SNAP_FRAMELEN;
dataLen = htons (dataLen);
M_PREPEND(pMblk, SIZEOF_ETHERHEADER + LLC_SNAP_FRAMELEN, M_DONTWAIT);
if (pMblk != NULL)
{
CSUM_IPHDR_OFFSET(pMblk) = SIZEOF_ETHERHEADER + LLC_SNAP_FRAMELEN;
/* Fill in destination address */
pDst = (USHORT *)pMblk->m_data;
if (bcastFlag)
{
pDst[0] = 0xFFFF;
pDst[1] = 0xFFFF;
pDst[2] = 0xFFFF;
}
else
{
pSrc = (USHORT *)pDstAddr->m_data;
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
}
/* Fill in source address */
pDst += 3;
pSrc = (USHORT *)pSrcAddr->m_data;
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
/* Fill in length */
pDst += 3;
pDst[0] = dataLen;
/* Fill in LLC using SNAP values */
pDst++;
pLlc = (struct llc *) pDst;
pLlc->llc_dsap = LLC_SNAP_LSAP;
pLlc->llc_ssap = LLC_SNAP_LSAP;
pLlc->llc_un.type_snap.control = LLC_UI;
pLlc->llc_un.type_snap.org_code[0] =
pLlc->llc_un.type_snap.org_code[1] =
pLlc->llc_un.type_snap.org_code[2] = 0;
/* Enter ethernet network type code into the LLC snap field */
pLlc->llc_un.type_snap.ether_type = pDstAddr->mBlkHdr.reserved;
}
return(pMblk);
}
/******************************************************************************
*
* endEtherAddressForm - form an Ethernet address into a packet
*
* This routine accepts the source and destination addressing information
* through <pSrcAddr> and <pDstAddr> and returns an 'M_BLK_ID' that points
* to the assembled link-level header. To do this, this routine prepends
* the link-level header into the cluster associated with <pMblk> if there
* is enough space available in the cluster. It then returns a pointer to
* the pointer referenced in <pMblk>. However, if there is not enough space
* in the cluster associated with <pMblk>, this routine reserves a
* new 'mBlk'-'clBlk'-cluster construct for the header information.
* It then prepends the new 'mBlk' to the 'mBlk' passed in <pMblk>. As the
* function value, this routine then returns a pointer to the new 'mBlk',
* which the head of a chain of 'mBlk' structures. The second element of this
* chain is the 'mBlk' referenced in <pMblk>.
*
* RETURNS: M_BLK_ID or NULL.
*
* ERRNO
*/
M_BLK_ID endEtherAddressForm
(
M_BLK_ID pMblk, /* pointer to packet mBlk */
M_BLK_ID pSrcAddr, /* pointer to source address */
M_BLK_ID pDstAddr, /* pointer to destination address */
BOOL bcastFlag /* use link-level broadcast? */
)
{
USHORT *pDst;
USHORT *pSrc;
/* validate parameters */
if ((pMblk == NULL) || (pSrcAddr == NULL) || (pDstAddr == NULL))
return (NULL);
M_PREPEND(pMblk, SIZEOF_ETHERHEADER, M_DONTWAIT);
/*
* This routine has been optimized somewhat in order to avoid
* the use of bcopy(). On some architectures, a bcopy() could
* result in a call into (allegedly) optimized architecture-
* specific routines. This may be fine for copying large chunks
* of data, but we're only copying 6 bytes. It's simpler just
* to open code some 16-bit assignments. The compiler would be
* hard-pressed to produce sub-optimal code for this, and it
* avoids at least one function call (possibly several).
*/
if (pMblk != NULL)
{
CSUM_IPHDR_OFFSET(pMblk) = SIZEOF_ETHERHEADER;
pDst = (USHORT *)pMblk->m_data;
if (bcastFlag)
{
pDst[0] = 0xFFFF;
pDst[1] = 0xFFFF;
pDst[2] = 0xFFFF;
}
else
{
pSrc = (USHORT *)pDstAddr->m_data;
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
}
/* Advance to the source address field, fill it in. */
pDst += 3;
pSrc = (USHORT *)pSrcAddr->m_data;
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
((struct ether_header *)pMblk->m_data)->ether_type =
pDstAddr->mBlkHdr.reserved;
}
return(pMblk);
}
/******************************************************************************
*
* endEtherPacketDataGet - return the beginning of the packet data
*
* This routine fills the given <pLinkHdrInfo> with the appropriate offsets.
*
* RETURNS: OK or ERROR.
*
* ERRNO
*/
STATUS endEtherPacketDataGet
(
M_BLK_ID pMblk,
LL_HDR_INFO * pLinkHdrInfo
)
{
struct ether_header * pEnetHdr;
struct ether_header enetHdr;
struct llc * pLLCHdr;
struct llc llcHdr;
USHORT etherType;
pLinkHdrInfo->destAddrOffset = 0;
pLinkHdrInfo->destSize = 6;
pLinkHdrInfo->srcAddrOffset = 6;
pLinkHdrInfo->srcSize = 6;
/* Try for RFC 894 first as it's the most common. */
/*
* make sure entire ether_header is in first M_BLK
* if not then copy the data to a temporary buffer
*/
if (pMblk->mBlkHdr.mLen < SIZEOF_ETHERHEADER)
{
pEnetHdr = &enetHdr;
if (netMblkOffsetToBufCopy (pMblk, 0, (char *) pEnetHdr,
SIZEOF_ETHERHEADER, (FUNCPTR) bcopy)
< SIZEOF_ETHERHEADER)
{
return(ERROR);
}
}
else
pEnetHdr = (struct ether_header *)pMblk->mBlkHdr.mData;
etherType = ntohs(pEnetHdr->ether_type);
/* Deal with 802.3 addressing. */
/* Here is the algorithm. */
/* If the etherType is less than or equal to the MTU then we know that */
/* this is an 802.x address from RFC 1700. */
if (etherType <= ETHERMTU)
{
/*
* make sure entire ether_header + llc_hdr is in first M_BLK
* if not then copy the data to a temporary buffer
*/
if (pMblk->mBlkHdr.mLen < SIZEOF_ETHERHEADER + LLC_SNAP_FRAMELEN)
{
pLLCHdr = &llcHdr;
if (netMblkOffsetToBufCopy (pMblk, SIZEOF_ETHERHEADER,
(char *) pLLCHdr, LLC_SNAP_FRAMELEN,
(FUNCPTR) bcopy)
< LLC_SNAP_FRAMELEN)
{
return(ERROR);
}
}
else
pLLCHdr = (struct llc *)((char *)pEnetHdr + SIZEOF_ETHERHEADER);
/* Now it may be IP over 802.x so we check to see if the */
/* destination SAP is IP, if so we snag the ethertype from the */
/* proper place. */
/* Now if it's NOT IP over 802.x then we just used the DSAP as */
/* the etherType. */
if (pLLCHdr->llc_dsap == LLC_SNAP_LSAP)
{
etherType = ntohs(pLLCHdr->llc_un.type_snap.ether_type);
pLinkHdrInfo->dataOffset = SIZEOF_ETHERHEADER + 8;
}
else
{ /* no SNAP header */
pLinkHdrInfo->dataOffset = SIZEOF_ETHERHEADER + 3;
etherType = pLLCHdr->llc_dsap;
}
}
else
{
pLinkHdrInfo->dataOffset = SIZEOF_ETHERHEADER;
}
pLinkHdrInfo->pktType = etherType;
return(OK);
}
/******************************************************************************
*
* endEtherPacketAddrGet - locate the addresses in a packet
*
* This routine takes a 'M_BLK_ID', locates the address information, and
* adjusts the M_BLK_ID structures referenced in <pSrc>, <pDst>, <pESrc>,
* and <pEDst> so that their pData members point to the addressing
* information in the packet. The addressing information is not copied.
* All 'mBlk' structures share the same cluster.
*
* RETURNS: OK
*
* ERRNO
*/
STATUS endEtherPacketAddrGet
(
M_BLK_ID pMblk, /* pointer to packet */
M_BLK_ID pSrc, /* pointer to local source address */
M_BLK_ID pDst, /* pointer to local destination address */
M_BLK_ID pESrc, /* pointer to remote source address (if any) */
M_BLK_ID pEDst /* pointer to remote destination address (if any) */
)
{
if (pSrc != NULL)
{
pSrc = netMblkDup (pMblk, pSrc);
if (pSrc == NULL)
return (ERROR);
pSrc->mBlkHdr.mData += 6;
pSrc->mBlkHdr.mLen = 6;
}
if (pDst != NULL)
{
pDst = netMblkDup (pMblk, pDst);
if (pDst == NULL)
return (ERROR);
pDst->mBlkHdr.mLen = 6;
}
if (pESrc != NULL)
{
pESrc = netMblkDup (pMblk, pESrc);
if (pESrc == NULL)
return (ERROR);
pESrc->mBlkHdr.mData += 6;
pESrc->mBlkHdr.mLen = 6;
}
if (pEDst != NULL)
{
pEDst = netMblkDup (pMblk, pEDst);
if (pEDst == NULL)
return (ERROR);
pEDst->mBlkHdr.mLen = 6;
}
return (OK);
}
+593
View File
@@ -0,0 +1,593 @@
/* endLib.c - support library for END-based drivers */
/*
* Copyright (c) 2008, 2013 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use of this
* software may be licensed only pursuant to the terms of an applicable Wind
* River license agreement.
*/
/*
modification history
--------------------
01f,04sep13,xms fix CHECKED_RETURN error. (WIND00414265)
01e,24nov08,dlk Add string.h header.
01d,03jun08,dlk Move (disabled) END MCACHE code here.
01c,21may08,dlk Move end8023AddressForm(), endEtherAddressForm() to
endEtherAddr.c for better scalability.
01b,26mar08,dlk Move end8023AddressForm(), endEtherAddressForm(),
endEtherPacketDataGet(), and endEtherPacketAddrGet()
here from endCommon.c
01a,14mar08,dlk Written. Most former contents moved to endCommon.c.
*/
/*
DESCRIPTION
This library contains support routines for END-style network drivers.
These routines are common to all END-style drivers. Specialized routines
should only appear in the drivers themselves. Routines shared by all styles
of drivers (END2, END, NPT) are found in endCommon.
To use this feature, include the following component:
INCLUDE_END
INCLUDE FILES: endLib.h
*/
/* includes */
#include <vxWorks.h>
#include <endLib.h>
#include <muxLib.h>
#include <string.h>
#include <private/muxLibP.h>
#include <net/mbuf.h>
#include <netinet/if_ether.h>
#define LLC_SNAP_FRAMELEN 8
int endPoolClSize = END_MCACHE_CLSIZE;
int endPoolJumboClSize = END_JUMBO_CLSIZE;
LOCAL STATUS endPoolInternalCreate (int, NET_POOL_ID *, int);
#ifdef END_POOL_MCACHE
LOCAL M_BLK_ID endCache[END_MCACHE_SIZE];
LOCAL UINT32 endCacheCnt = 0;
LOCAL UINT32 endCacheHead = 0;
LOCAL UINT32 endCacheTail = 0;
LOCAL spinlockIsr_t endCacheLock;
LOCAL BOOL endCacheInit = FALSE;
#endif
void endLibInit (void)
{
MUX_END_STYLE_INFO * style = &muxEndStyles[END_STYLE_END];
style->rxRtn = muxReceive;
}
void endRcvRtnCall
(
END_OBJ* pEnd,
M_BLK_ID pData
)
{
if (pEnd->receiveRtn)
{
pEnd->receiveRtn ((pEnd), pData);
}
else
netMblkClChainFree (pData);
}
/*****************************************************************************
*
* muxReceive - handle a packet from a device driver
*
* An END calls this routine to transfer a packet to one or more bound
* services.
*
* NOTE: The stack receive routine installed by a protocol must not alter
* the packet if it returns FALSE. This restriction is not currently stated
* in the manual.
*
* RETURNS: OK or ERROR.
*
* ERRNO: S_muxLib_NO_DEVICE
*
* NOMANUAL
*/
STATUS muxReceive
(
void * pCookie, /* device identifier from driver's load routine */
M_BLK_ID pMblk /* buffer containing received frame */
)
{
PROTO_ENTRY * pProto;
END_OBJ * pEnd;
long type;
LL_HDR_INFO llHdrInfo;
pEnd = (END_OBJ *)pCookie;
#ifdef DEBUG_CHECKS
if (pEnd == NULL || pMblk == NULL)
goto err;
#endif
if (pEnd->pFuncTable->packetDataGet == NULL ||
pEnd->pFuncTable->packetDataGet (pMblk, &llHdrInfo, pEnd) != OK)
{
goto err_data_get;
}
type = llHdrInfo.pktType;
/*
* Loop through the protocol list.
* If a service's receive routine returns TRUE, it has consumed the
* packet. The receive routine must return FALSE for other services
* to see the packet.
*
* The order of services in the list (established during the bind)
* determines their priority. SNARF services have the priority over
* every other service type. PROMISC services have the lowest priority.
* If multiple SNARF or PROMISC services exist, the order is first-come,
* first-served, which could prevent some services from seeing matching
* data if an earlier entry consumes it.
*/
for (pProto = pEnd->pSnarf; pProto < pEnd->pStop; pProto++)
{
if (pProto->rr.endRcv == NULL)
continue;
if (type == pProto->type ||
pProto->type == MUX_PROTO_SNARF ||
pProto->type == MUX_PROTO_PROMISC)
{
if (pProto->rr.endRcv (pProto->pBinding, type, pMblk,
&llHdrInfo, pProto->recvRtnArg))
goto out;
}
}
/* Unknown service. Free the packet. */
if (pEnd->flags & END_MIB_2233)
{
/* RFC 2233 type of MIB variables supported */
MIB_CNT_UPDATE(pEnd->pMib2Tbl, M2_ctrId_ifInUnknownProtos, 1, NULL);
}
else /* RFC 1213 style MIB */
{
pEnd->mib2Tbl.ifInUnknownProtos++;
}
/* if the flow comes here then free the mBlk */
netMblkClChainFree (pMblk);
out:
return OK;
err_data_get:
if (pEnd->flags & END_MIB_2233)
{
MIB_CNT_UPDATE(pEnd->pMib2Tbl, M2_ctrId_ifInErrors, 1, NULL);
}
else /* 1213-style MIB */
{
pEnd->mib2Tbl.ifInErrors++;
}
#ifdef DEBUG_CHECKS
err:
#endif
if (pMblk)
netMblkClChainFree (pMblk);
return (ERROR);
}
/******************************************************************************
*
* endPoolCreate - create a buffer pool for an END driver
*
* This function is a helper routine for END drivers to simplify the creation
* of a driver-private buffer pool. The caller need only specify the number of
* tuples in the pool. The resulting pool will have an equal number of
* mBlks, cluster blocks and clusters (this is the typical requirement for
* driver usage). The clusters in the pool will always be the same size,
* governed by the endPoolClSize global variable. The default size is
* 1536 bytes.
*
* Note that clusters will be allocated from cached storage. This may
* be unsuitable for some drivers, however this is not an issue for
* drivers that are VxBus-compliant: cache coherence issues should be
* handled internally by the vxbDmaBuf API.
*
* RETURNS: OK if pool is successfully created, otherwise ERROR
*
* ERRNO: N/A
*/
STATUS endPoolCreate
(
int tupleCnt,
NET_POOL_ID * ppNetPool
)
{
return (endPoolInternalCreate (tupleCnt, ppNetPool, endPoolClSize));
}
/******************************************************************************
*
* endPoolJumboCreate - create a jumbo buffer pool for an END driver
*
* This function is a helper routine for END drivers to simplify the creation
* of a driver-private buffer pool. It's similar to the endPoolCreate()
* function, except that it creates a pool of 9K jumbo buffers for drivers
* that support jumbo frames.
*
* RETURNS: OK if pool is successfully created, otherwise ERROR
*
* ERRNO: N/A
*/
STATUS endPoolJumboCreate
(
int tupleCnt,
NET_POOL_ID * ppNetPool
)
{
return (endPoolInternalCreate (tupleCnt, ppNetPool, endPoolJumboClSize));
}
/******************************************************************************
*
* endPoolInternalCreate - internal pool creation function
*
* This function contains common code used by the endPoolCreate() and
* endPoolJumboCreate() functions.
*
* RETURNS: OK if pool is successfully created, otherwise ERROR
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS endPoolInternalCreate
(
int tupleCnt,
NET_POOL_ID * ppNetPool,
int size
)
{
NETBUF_CFG netBufCfg;
NETBUF_CL_DESC clDescTbl;
NET_POOL_ID pPool;
if (ppNetPool == NULL || tupleCnt == 0)
return (ERROR);
bzero ((char *)&netBufCfg, sizeof(netBufCfg));
bzero ((char *)&clDescTbl, sizeof(clDescTbl));
netBufCfg.pName = NULL;
netBufCfg.attributes = ATTR_AC_SH_ISR;
netBufCfg.ctrlNumber = tupleCnt;
netBufCfg.ctrlPartId = NULL;
netBufCfg.bMemExtraSize = 0;
netBufCfg.pClDescTbl = &clDescTbl;
netBufCfg.pClDescTbl->clNum = tupleCnt;
netBufCfg.pClDescTbl->clSize = size;
netBufCfg.clDescTblNumEnt = 1;
pPool = netPoolCreate (&netBufCfg, _pLinkPoolFuncTbl);
if (pPool == NULL)
return (ERROR);
*ppNetPool = pPool;
#ifdef END_POOL_MCACHE
if (endCacheInit == FALSE)
{
endCacheInit = TRUE;
SPIN_LOCK_ISR_INIT(&endCacheLock, 0);
}
#endif
return (OK);
}
/******************************************************************************
*
* endPoolDestroy - destroy a pool created with endPoolCreate()
*
* This function is used to release a buffer pool created with the
* endPoolCreate() function. All memory allocated for use by the pool
* will be returned.
*
* RETURNS: OK if pool is successfully destroyed, otherwise ERROR
*
* ERRNO: N/A
*/
STATUS endPoolDestroy
(
NET_POOL_ID pNetPool
)
{
/* don't need return from function call */
(void) netPoolRelease (pNetPool, NET_REL_IN_CONTEXT);
return(OK);
}
#ifdef END_POOL_MCACHE
/******************************************************************************
*
* endPoolTupleGet - allocate an mBlk tuple for an END driver
*
* This function allocate an mBlk tuple from a pool created with the
* endPoolCreate() routine. It works in conjunction with the mBlk
* recycle cache to optimize performance when allocating buffers in
* the transmit and receive paths in END drivers. If an mBlk tuple
* is available in the cache, the buffer will be allocated from it
* directly. Otherwise, a tuple will be allocated from the pool.
*
* Buffers allocated with endPoolTupleAlloc() should always be
* released with endPoolTupleFree().
*
* RETURNS: a pointer to an mBlk, otherwise NULL if none are available
*
* ERRNO: N/A
*/
M_BLK_ID endPoolTupleGet
(
NET_POOL_ID pNetPool
)
{
M_BLK_ID pMblk;
/* Try to allocate from the mBlk recycle cache first. */
SPIN_LOCK_ISR_TAKE(&endCacheLock);
pMblk = endCache[endCacheTail];
if (endCacheCnt == 0 || pMblk->m_extSize != pNetPool->clTbl[0]->clSize)
{
SPIN_LOCK_ISR_GIVE(&endCacheLock);
goto alloc;
}
pMblk = endCache[endCacheTail];
END_MCACHE_INC(endCacheTail);
endCacheCnt--;
SPIN_LOCK_ISR_GIVE(&endCacheLock);
return (pMblk);
alloc:
/*
* Cache is empty, allocate tuple from the pool.
* Since it's a linkBufPool, we use mBlkGet() for speed.
*/
pMblk = mBlkGet (pNetPool, M_DONTWAIT, MT_DATA);
if (pMblk != NULL)
{
/* Tag this mBlk so we know to cache it later. Also set
* the lengths, needed by vxbDmaBufMapMblkLoad.
*/
pMblk->m_len =
pMblk->m_pkthdr.len = pMblk->m_extSize - pNetPool->clOffset;
pMblk->m_extArg3 = END_MCACHE_TAG;
}
return (pMblk);
}
/******************************************************************************
*
* endPoolTupleFree - free an mBlk tuple for an END driver
*
* This function releases an mBlk tuple from a pool created with the
* endPoolCreate() routine. It works in conjunction with the mBlk
* recycle cache to optimize performance when allocating buffers in
* the transmit and receive paths in END drivers. If the buffer was
* allocated using endPoolTupleAlloc(), it will be put back into
* the mBlk recycle cache, assuming there's room for it. If not,
* it will be released back to its original pool.
*
* For buffers not allocated using endPoolTupleFree(), this routine
* is equivalent to netMblkClChainFree().
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
void endPoolTupleFree
(
M_BLK_ID pMblk
)
{
int clOffset;
if (pMblk->m_next != NULL ||
pMblk->m_extRefCnt != 1 ||
pMblk->m_extArg3 != END_MCACHE_TAG ||
pMblk->m_ext->pNetPool->mBlkFree == 0)
goto release;
clOffset = pMblk->m_ext->pNetPool->clOffset;
SPIN_LOCK_ISR_TAKE(&endCacheLock);
if (endCacheCnt == END_MCACHE_SIZE)
{
SPIN_LOCK_ISR_GIVE(&endCacheLock);
goto release;
}
pMblk->pClBlk->clFreeArg3 = 0;
pMblk->m_data = pMblk->m_extBuf + clOffset;
pMblk->m_len = pMblk->m_pkthdr.len = pMblk->m_extSize - clOffset;
pMblk->m_flags = M_EXT;
pMblk->m_pkthdr.csum_flags = 0;
endCache[endCacheHead] = pMblk;
END_MCACHE_INC(endCacheHead);
endCacheCnt++;
SPIN_LOCK_ISR_GIVE(&endCacheLock);
return;
release:
netMblkClChainFree (pMblk);
return;
}
/******************************************************************************
*
* endMcacheGet - allocate an mBlk tuple from the mBlk recycle cache
*
* This function obtains an mBlk tuple stored in a fast mBlk recycle cache.
*
* This cache is used to provide a performance boost for drivers used in
* devices designed for traffic forwarding or bridging. In this devices,
* buffers from the RX side of an inbound interface are often directly
* retransmitted via the TX side of an outbound interface, after which
* they are released back to the RX interface's mBlk pool. This may consume
* a lot of overhead depending on the pool implementation.
*
* Using the mBlk recycle cache may reduce this overhead. The cache is
* implemented as a simple 128-entry pointer array. When a tuple is to
* be released by the TX completion handler in a network driver, it can
* be put in the recycle cache instead of released with netMblkClChainFree().
* Whenever another interface needs a tuple to replenish its RX resources,
* it can allocate it from the pool instead of doing a netTupleGet().
* The cache only holds 128 tuple pointers, the cache get and put operations
* use a minimum of processing and are usually faster than the netTupleGet()
* and netMblkClChainFree() paths, which shaves some cycles off the time
* needed to process a given packet.
*
* RETURNS: a pointer to an mBlk tuple, or NULL if the cache is empty
*
* ERRNO: N/A
*/
M_BLK_ID endMcacheGet
(
void
)
{
M_BLK_ID pMblk;
SPIN_LOCK_ISR_TAKE(&endCacheLock);
if (endCacheCnt == 0)
{
pMblk = NULL;
goto out;
}
pMblk = endCache[endCacheTail];
END_MCACHE_INC(endCacheTail);
endCacheCnt--;
out:
SPIN_LOCK_ISR_GIVE(&endCacheLock);
return (pMblk);
}
/******************************************************************************
*
* endMcachePut - store an mBlk tuple in the mBlk recycle cache
*
* This function places a pointer to an mBlk tuple in the mBlk recycle
* cache, as long as there is room to store it. The cache only holds 128
* pointers, so storing the pointer will fail if the cache is full.
*
* RETURNS: OK of the tuple was successfully cached, otherwise ERROR
*
* ERRNO: N/A
*/
STATUS endMcachePut
(
M_BLK_ID pMblk
)
{
STATUS status;
SPIN_LOCK_ISR_TAKE(&endCacheLock);
if (endCacheCnt == END_MCACHE_SIZE)
{
status = ERROR;
goto out;
}
pMblk->m_data = pMblk->m_extBuf;
endCache[endCacheHead] = pMblk;
END_MCACHE_INC(endCacheHead);
endCacheCnt++;
status = OK;
out:
SPIN_LOCK_ISR_GIVE(&endCacheLock);
return (status);
}
/******************************************************************************
*
* endMcacheFlush - flush all tuples from the mBlk recycle cache
*
* This function removes all mBlk tuple pointers from the mBlk recycle
* cache and frees them with netMblkClChainFree(). This function must be
* called whenever any interface that uses the recycle cache is stopped
* so that cached buffers can be properly reclaimed.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
void endMcacheFlush
(
void
)
{
M_BLK_ID pMblk;
SPIN_LOCK_ISR_TAKE(&endCacheLock);
while (endCacheCnt)
{
pMblk = endCache[endCacheTail];
END_MCACHE_INC(endCacheTail);
endCacheCnt--;
SPIN_LOCK_ISR_GIVE(&endCacheLock);
netMblkClChainFree (pMblk);
SPIN_LOCK_ISR_TAKE(&endCacheLock);
}
SPIN_LOCK_ISR_GIVE(&endCacheLock);
return;
}
#endif /* END_POOL_MCACHE */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+774
View File
@@ -0,0 +1,774 @@
/* loopEnd.c - software loopback END */
/* Copyright 1984-2006 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/* $NetBSD: loopEnd.c,v 1.13 1994/10/30 21:48:50 cgd Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)loopEnd.c 8.1 (Berkeley) 6/10/93
*/
/*
modification history
--------------------
01m,05sep06,kch Removed unnecessary coreip header includes.
01l,31aug04,mdo Documentation fixes for apigen
01k,14jan99,sut prepended protocol information
01j,14jan99,sut moved to tor2_0_0, renamed to loopEnd.c
01i,14jan99,sut added routines loAddressForm, loPacketDataGet, loPacketAddrGet
01h,13jan99,sut revoved loPollStart and loPollEnd
01g,13jan99,sut put back again multicast support
01f,13jan99,sut added more documentation
01e,12jan99,sut removed ether address storage
01d,12jan99,sut added debug routines
01c,11jan99,sut removed multicast support
01b,11jan99,sut converted into END driver
01a,07jan99,sut started with netif/if_loop.c
*/
/*
DESCRIPTION
This module implements the software loopback Enhanced Network Driver (END).
The only external routine is loEndLoad(), which can only be called from mux
interface.
The driver does not support polled mode operations. Even though the polled
mode interfaces are exported to mux layer, just returns ERROR for polled mode
operations.
BOARD LAYOUT
This device is "software only." A jumpering diagram is not applicable.
EXTERNAL INTERFACE
The only external interface is the loEndLoad() routine, which expects
the <initString> parameter as input. At present this routine expects only
<unit> from this string. This parameter passes in a colon-delimited string of
the format:
<unit>
The loEndLoad() function uses strtok() to parse the string
TARGET-SPECIFIC PARAMETERS
\is
\i <unit>
A convenient holdover from the former model. This parameter is used only
in the string name for the driver.
\ie
SEE ALSO: ifLib
*/
#include "vxWorks.h"
#include "stdlib.h"
#include "end.h"
#include "endLib.h"
#include "lstLib.h"
#include "wdLib.h"
#include "iv.h"
#include "semLib.h"
#include "etherLib.h"
#include "logLib.h"
#include "netLib.h"
#include "stdio.h"
#include "sysLib.h"
#include "errno.h"
#include "errnoLib.h"
#include "memLib.h"
#include "iosLib.h"
#undef ETHER_MAP_IP_MULTICAST
#include "etherMultiLib.h" /* multicast stuff. */
#include "net/mbuf.h"
#include "sys/ioctl.h"
#include "sys/times.h"
/* maximum packet size */
#define LO_SPEED 10000000
#define LO_MIN_FBUF 0 /* Minimum size of the first buffer in a */
/* chain. */
#define LO_ADDR_LEN 0 /* address length */
#define LO_HDR_LEN 0 /* header length */
/* Naming items */
#define LO_DEV_NAME "lo"
#define LO_DEV_NAME_LEN 3
/* device states */
#define LO_ST_STOPPED 0x80
#define LO_IS_DEV_STOPPED(pDrvCtrl)\
((pDrvCtrl->state & LO_ST_STOPPED) == LO_ST_STOPPED)
#define LO_DEV_STOP(pDrvCtrl) (pDrvCtrl->state |= LO_ST_STOPPED)
#define LO_DEV_START(pDrvCtrl) (pDrvCtrl->state &= (!LO_ST_STOPPED))
#define LO_PROTOCOL_LEN sizeof(USHORT)
#undef DRV_DEBUG
#ifdef DRV_DEBUG
#define DRV_DEBUG_OFF 0x0000
#define DRV_DEBUG_POLL 0x0001
#define DRV_DEBUG_LOAD 0x0002
#define DRV_DEBUG_IOCTL 0x0004
#define DRV_DEBUG_LOG_NVRAM 0x0008
#ifdef LOCAL
#undef LOCAL
#endif /* LOCAL */
#define LOCAL ;
int loDebug = DRV_DEBUG_OFF; /* Turn it off initially. */
#include "nvLogLib.h"
#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \
if ((loDebug & FLG)&&(FLG & DRV_DEBUG_POLL)) \
nvLogMsg(X0, X1, X2, X3, X4, X5, X6); \
else if (loDebug & FLG) \
logMsg(X0, X1, X2, X3, X4, X5, X6);
#define DRV_PRINT(FLG,X) \
if (loDebug & FLG) printf X;
#else /*DRV_DEBUG*/
#define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
#define DRV_PRINT(DBG_SW,X)
#endif /*DRV_DEBUG*/
/* The definition of the driver control structure */
#define U16 unsigned short int
typedef struct lo_device
{
END_OBJ end; /* The class we inherit from. */
int unit; /* unit number */
U16 state;
u_short errorStat; /* error status */
} LOEND_DEVICE;
/* forward declarations */
/* This is the only externally visible interface. */
END_OBJ* loEndLoad (char* initString);
/* END interfaces */
LOCAL STATUS loUnload (LOEND_DEVICE* pDrvCtrl);
LOCAL STATUS loIoctl (LOEND_DEVICE* pDrvCtrl, int cmd, caddr_t data);
LOCAL STATUS loSend (LOEND_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
LOCAL STATUS loStart (LOEND_DEVICE* pDrvCtrl);
LOCAL STATUS loStop (LOEND_DEVICE* pDrvCtrl);
LOCAL STATUS loMCastAddrAdd (LOEND_DEVICE* pDrvCtrl, char* pAddress);
LOCAL STATUS loMCastAddrDel (LOEND_DEVICE* pDrvCtrl, char* pAddress);
LOCAL STATUS loMCastAddrGet (LOEND_DEVICE* pDrvCtrl,
MULTI_TABLE* pTable);
LOCAL STATUS loPollSend (LOEND_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
LOCAL STATUS loPollReceive (LOEND_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
M_BLK_ID loAddressForm (M_BLK_ID pMblk, M_BLK_ID pSrcAddr, M_BLK_ID pDstAddr);
STATUS loPacketDataGet (M_BLK_ID pMblk, LL_HDR_INFO* pLinkHdrInfo);
STATUS loPacketAddrGet (M_BLK_ID pMblk, M_BLK_ID pSrc, M_BLK_ID pDst,
M_BLK_ID pESrc, M_BLK_ID pEDst);
LOCAL STATUS loInitStringParse ();
/*
* Declare our function table. This is static across all driver
* instances.
*/
LOCAL NET_FUNCS loFuncTable =
{
(FUNCPTR)loStart, /* Function to start the device. */
(FUNCPTR)loStop, /* Function to stop the device. */
(FUNCPTR)loUnload, /* Unloading function for the driver. */
(FUNCPTR)loIoctl, /* Ioctl function for the driver. */
(FUNCPTR)loSend, /* Send function for the driver. */
(FUNCPTR)loMCastAddrAdd, /* Multicast address add */
(FUNCPTR)loMCastAddrDel, /* Multicast address delete */
(FUNCPTR)loMCastAddrGet, /* Multicast table retrieve */
(FUNCPTR)loPollSend, /* Polling send function for the driver. */
(FUNCPTR)loPollReceive, /* Polling receive function for the driver. */
loAddressForm, /* Put address info into a packet. */
loPacketDataGet, /* Get a pointer to packet data. */
loPacketAddrGet /* Get packet addresses. */
};
/******************************************************************************
*
* loEndLoad - initialize the driver and device
*
* This routine initializes the driver and the device to the operational state.
* All of the device-specific parameters are passed in <initString>, which
* expects a string of the following format:
*
* <unit>
*
* This routine can be called in two modes. If it is called with an empty but
* allocated string, it places the name of this device (that is, "lo") into
* the <initString> and returns 0.
*
* If the string is allocated and not empty, the routine attempts to load
* the driver using the values specified in the string.
*
* RETURNS: An END object pointer, or NULL on error, or 0 and the name of the
* device if the <initString> was NULL.
*/
END_OBJ* loEndLoad
(
char* initString /* string to be parse by the driver */
)
{
LOEND_DEVICE *pDrvCtrl;
DRV_LOG (DRV_DEBUG_LOAD, "Loading lo...\n", 1, 2, 3, 4, 5, 6);
if (initString == NULL)
return (NULL);
if (initString[0] == NULL)
{
bcopy((char *)LO_DEV_NAME, initString, LO_DEV_NAME_LEN);
return (0);
}
/* allocate the device structure */
pDrvCtrl = (LOEND_DEVICE *)calloc (sizeof (LOEND_DEVICE), 1);
if (pDrvCtrl == NULL)
goto errorExit;
/* parse the init string, filling in the device structure */
if (loInitStringParse (pDrvCtrl, initString) == ERROR)
goto errorExit;
/* initialize the END and MIB2 parts of the structure */
if (END_OBJ_INIT (&pDrvCtrl->end, (DEV_OBJ *)pDrvCtrl, LO_DEV_NAME,
pDrvCtrl->unit, &loFuncTable,
"Loopback Enhanced Network Driver") == ERROR
|| END_MIB_INIT (&pDrvCtrl->end, M2_ifType_softwareLoopback, NULL,
LO_ADDR_LEN, 0, LO_SPEED)
== ERROR)
goto errorExit;
/* set the flags to indicate readiness */
END_OBJ_READY (&pDrvCtrl->end,
IFF_UP | IFF_RUNNING | IFF_LOOPBACK | IFF_MULTICAST);
DRV_LOG (DRV_DEBUG_LOAD, "Done loading lo...\n", 1, 2, 3, 4, 5, 6);
return (&pDrvCtrl->end);
errorExit:
if (pDrvCtrl != NULL)
free ((char *)pDrvCtrl);
return NULL;
}
/******************************************************************************
*
* loUnload - unload a driver from the system
*
* This function first brings down the device, and then frees any
* stuff that was allocated by the driver in the load function.
*/
LOCAL STATUS loUnload
(
LOEND_DEVICE* pDrvCtrl
)
{
END_OBJECT_UNLOAD (&pDrvCtrl->end);
return (OK);
}
/*******************************************************************************
*
* loStart - start the device
*
* This function calls BSP functions to connect interrupts and start the
* device running in interrupt mode.
*
* RETURNS: OK or ERROR
*
*/
LOCAL STATUS loStart
(
LOEND_DEVICE *pDrvCtrl
)
{
LO_DEV_START(pDrvCtrl);
return OK;
}
/*******************************************************************************
*
* loStop - stop the device
*
* This function calls BSP functions to disconnect interrupts and stop
* the device from operating in interrupt mode.
*
* RETURNS: OK or ERROR
*/
LOCAL STATUS loStop
(
LOEND_DEVICE *pDrvCtrl
)
{
LO_DEV_STOP(pDrvCtrl);
return OK;
}
/*******************************************************************************
*
* loIoctl - the driver I/O control routine
*
* Process an ioctl request.
*/
LOCAL STATUS loIoctl
(
LOEND_DEVICE *pDrvCtrl,
int cmd,
caddr_t data
)
{
STATUS error = OK;
long value;
if (LO_IS_DEV_STOPPED(pDrvCtrl))
return ERROR;
switch (cmd)
{
case EIOCSADDR:
return (ERROR);
break;
case EIOCGADDR:
return (ERROR);
break;
case EIOCSFLAGS:
value = (long)data;
if (value < 0)
{
value = -value;
value--; /* HELP: WHY ??? */
END_FLAGS_CLR (&pDrvCtrl->end, value);
}
else
{
END_FLAGS_SET (&pDrvCtrl->end, value);
}
break;
case EIOCGFLAGS:
*(int *)data = END_FLAGS_GET(&pDrvCtrl->end);
break;
case EIOCPOLLSTART: /* fall through */
case EIOCPOLLSTOP:
error = ERROR;
break;
case EIOCGMIB2:
if (data == NULL)
return (EINVAL);
bcopy((char *)&pDrvCtrl->end.mib2Tbl, (char *)data,
sizeof(pDrvCtrl->end.mib2Tbl));
break;
case EIOCGFBUF:
if (data == NULL)
return (EINVAL);
*(int *)data = LO_MIN_FBUF;
break;
case EIOCGMWIDTH:
if (data == NULL)
return (EINVAL);
*(int *)data = 0;
break;
case EIOCGHDRLEN:
if (data == NULL)
return (EINVAL);
*(int *)data = LO_HDR_LEN;
break;
case EIOCMULTIADD:
case EIOCMULTIDEL:
case EIOCMULTIGET:
error = EINVAL;
break;
default:
error = EINVAL;
}
return (error);
}
/*******************************************************************************
*
* loSend - the driver send routine
*
* This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
* The buffer must already have the addressing information properly installed
* in it. This is done by a higher layer. The last arguments are a free
* routine to be called when the device is done with the buffer and a pointer
* to the argument to pass to the free routine.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS loSend
(
LOEND_DEVICE *pDrvCtrl, /* device ptr */
M_BLK_ID pMblk /* data to send */
)
{
STATUS retValue = OK;
if (LO_IS_DEV_STOPPED(pDrvCtrl))
retValue = ERROR;
else
{
/* Bump the statistic counter. */
END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);
/* Call the upper layer's receive routine. */
END_RCV_RTN_CALL(&pDrvCtrl->end, pMblk);
}
return (retValue);
}
/*******************************************************************************
*
* loInitStringParse - parse the initialization string
*
* Parse the input string. Fill in values in the driver control structure.
* The initialization string format is:
* <unit>
*
* \is
* \i <unit>
* Device unit number, a small integer.
* \ie
*
* RETURNS: OK, or ERROR if any arguments are invalid.
*/
STATUS loInitStringParse
(
LOEND_DEVICE* pDrvCtrl,
char* initString
)
{
char * tok;
char * pHolder = NULL;
/* Parse the initString */
/* Unit number. */
tok = strtok_r (initString, ":", &pHolder);
if (tok == NULL)
return ERROR;
pDrvCtrl->unit = atoi (tok);
return OK;
}
/*****************************************************************************
*
* loMCastAddrAdd - add a multicast address for the device
*
* This routine adds a multicast address to whatever the driver
* is already listening for. It then resets the address filter.
*
* RETURNS: OK, or ERROR if fails to add
*/
LOCAL STATUS loMCastAddrAdd
(
LOEND_DEVICE *pDrvCtrl,
char* pAddress
)
{
int error;
error = etherMultiAdd (&pDrvCtrl->end.multiList, pAddress);
return (error);
}
/*****************************************************************************
*
* loMCastAddrDel - delete a multicast address for the device
*
* This routine removes a multicast address from whatever the driver
* is listening for. It then resets the address filter.
*
* RETURNS: OK, or ERROR if fails to delete
*/
LOCAL STATUS loMCastAddrDel
(
LOEND_DEVICE* pDrvCtrl,
char* pAddress
)
{
int error;
error = etherMultiDel (&pDrvCtrl->end.multiList, pAddress);
return (error);
}
/*****************************************************************************
*
* loMCastAddrGet - get the multicast address list for the device
*
* This routine gets the multicast list of whatever the driver
* is already listening for.
*
* RETURNS: OK, or ERROR if fails to get
*
*/
LOCAL STATUS loMCastAddrGet
(
LOEND_DEVICE* pDrvCtrl,
MULTI_TABLE* pTable
)
{
int error;
error = etherMultiGet (&pDrvCtrl->end.multiList, pTable);
return (error);
}
/*******************************************************************************
*
* loPollSend - routine to send a packet in polled mode.
*
* This routine is called by a user to try and send a packet on the
* device.
*
* RETURNS: ERROR always
*/
LOCAL STATUS loPollSend
(
LOEND_DEVICE* pDrvCtrl,
M_BLK_ID pMblk
)
{
return ERROR;
}
/*******************************************************************************
*
* loPollReceive - routine to receive a packet in polled mode.
*
* This routine is called by a user to try and get a packet from the
* device.
*
* RETURNS: ERROR always
*/
LOCAL STATUS loPollReceive
(
LOEND_DEVICE *pDrvCtrl,
M_BLK_ID pMblk
)
{
return ERROR;
}
/******************************************************************************
*
* loAddressForm - form an Ethernet address into a packet
*
* This routine accepts the source and destination addressing information
* through <pSrcAddr> and <pDstAddr> and returns an 'M_BLK_ID' that points
* to the assembled link-level header. To do this, this routine prepends
* the link-level header into the cluster associated with <pMblk> if there
* is enough space available in the cluster. It then returns a pointer to
* the pointer referenced in <pMblk>. However, if there is not enough space
* in the cluster associated with <pMblk>, this routine reserves a
* new 'mBlk'-'clBlk'-cluster construct for the header information.
* It then prepends the new 'mBlk' to the 'mBlk' passed in <pMblk>. As the
* function value, this routine then returns a pointer to the new 'mBlk',
* which the head of a chain of 'mBlk' structures. The second element of this
* chain is the 'mBlk' referenced in <pMblk>.
*
* RETURNS: M_BLK_ID or NULL.
*/
M_BLK_ID loAddressForm
(
M_BLK_ID pMblk, /* pointer to packet mBlk */
M_BLK_ID pSrcAddr, /* pointer to source address */
M_BLK_ID pDstAddr /* pointer to destination address */
)
{
M_PREPEND(pMblk, LO_PROTOCOL_LEN, M_DONTWAIT);
if (pMblk != NULL)
bcopy ((char *)&pDstAddr->mBlkHdr.reserved,
pMblk->m_data, LO_PROTOCOL_LEN);
return (pMblk);
}
/******************************************************************************
*
* loPacketDataGet - return the beginning of the packet data
*
* This routine fills the given <pLinkHdrInfo> with the appropriate offsets.
*
* RETURNS: OK or ERROR.
*/
STATUS loPacketDataGet
(
M_BLK_ID pMblk,
LL_HDR_INFO * pLinkHdrInfo
)
{
pLinkHdrInfo->destAddrOffset = 0;
pLinkHdrInfo->destSize = 0;
pLinkHdrInfo->srcAddrOffset = 0;
pLinkHdrInfo->srcSize = 0;
pLinkHdrInfo->dataOffset = LO_PROTOCOL_LEN;
bcopy (pMblk->m_data, (char *)&pLinkHdrInfo->pktType, LO_PROTOCOL_LEN);
return (OK);
}
/******************************************************************************
*
* loPacketAddrGet - locate the addresses in a packet
*
* This routine takes a 'M_BLK_ID', locates the address information, and
* adjusts the M_BLK_ID structures referenced in <pSrc>, <pDst>, <pESrc>,
* and <pEDst> so that their pData members point to the addressing
* information in the packet. The addressing information is not copied.
* All 'mBlk' structures share the same cluster.
*
* RETURNS: OK or ERROR.
*/
STATUS loPacketAddrGet
(
M_BLK_ID pMblk, /* pointer to packet */
M_BLK_ID pSrc, /* pointer to local source address */
M_BLK_ID pDst, /* pointer to local destination address */
M_BLK_ID pESrc, /* pointer to remote source address (if any) */
M_BLK_ID pEDst /* pointer to remote destination address (if any) */
)
{
if (pSrc != NULL)
{
pSrc->mBlkHdr.mData = NULL;
pSrc->mBlkHdr.mLen = 0;
}
if (pDst != NULL)
{
pDst->mBlkHdr.mLen = 0;
}
if (pESrc != NULL)
{
pESrc->mBlkHdr.mData = NULL;
pESrc->mBlkHdr.mLen = 0;
}
if (pEDst != NULL)
{
pEDst->mBlkHdr.mLen = 0;
}
return (OK);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+324
View File
@@ -0,0 +1,324 @@
/* smEndShow.c - shared memory network END driver show routines */
/*
* Copyright (c) 1999, 2001, 2004, 2006, 2009-2010, 2013 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01j,14jun13,fao Fix Coverity Prevent warnings. (WIND00414265)
01i,04jun10,pch fix build warnings
01h,12may09,e_d add check unitTbl. (WIND00165866)
01g,11may06,dgp doc: fix NPG reference in lib
01f,31aug04,mdo Documentation fixes for apigen
01e,06feb04,jln ported to base6 and T221
01d,09apr01,mas made IP address string conversion endian agnostic (SPR 65709)
01c,26mar01,mas man page clean up (SPR 63976)
01b,04oct99,mas componentized.
01a,03mar99,mas Created from smNetShow.c rev 01c, 16sep92 (SPR 25573).
*/
/*
DESCRIPTION
This library provides show routines for the shared memory network interface
END driver.
The smNetShow() routine is provided as a diagnostic aid to show current
shared memory network status.
INCLUDE FILES: smPktLib.h
SEE ALSO:
the network stack programmer's guide.
*/
#include "vxWorks.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "smPktLib.h"
#include "vxLib.h"
#include "muxLib.h"
#include "netinet/in.h"
#include "inetLib.h"
#include "smLib.h"
#include "drv/end/smEnd.h"
/* shared memory device name and unit number */
LOCAL char dfltSmDevName[] = "sm";
LOCAL unsigned unit = 0;
/******************************************************************************
*
* smEndShowInit - routine to drag in and configure smNetShow routine
*
* This routine is called after the smEnd driver has started. It records the
* device name of the first shared memory device which is not known until BSP
* compile routine.
*
* \NOMANUAL
*/
void smEndShowInit (void)
{
FAST SM_END_DEV * pSmEndDev; /* END device pointer */
static BOOL initialized = FALSE;
if (!initialized)
{
if (unitTbl != NULL)
{
if (unitTbl[0] == NULL)
printf ("SM0 show init failed: SM0 not initialized.\n");
/* get pointer to first SM device and record its name/unit */
else
{
pSmEndDev = unitTbl[0];
strncpy (dfltSmDevName, pSmEndDev->devName, 2);
unit = pSmEndDev->unit;
initialized = TRUE;
}
}
else
printf ("SM show init failed: SM not initialized.\n");
}
return;
}
/******************************************************************************
*
* smNetShow - show information about a shared memory network
*
* This routine displays information about the different CPUs configured
* in a shared memory network specified by <endName>. It prints error
* statistics and zeros these fields if <zero> is set to TRUE.
*
* EXAMPLE
* \cs
* -> smNetShow
* Anchor Local Addr: 0x10000800, Hard TAS
* Sequential addressing enabled.
* Master IP address: 192.168.207.1 Local IP address: 192.168.207.2
*
* heartbeat = 56, header at 0x1071d5b4, free pkts = 29.
*
* cpu int type arg1 arg2 arg3 queued pkts
* --- -------- ---------- ---------- ---------- -----------
* 0 mbox-4 0xd 0x807ffffc 0 0
* 1 poll 0xd 0xfb001000 0x80 0
*
* PACKETS ERRORS
* Unicast Brdcast
* Input Output Input Output Input Output
* ======= ======= ======= ======= + ======= =======
* 3 2 0 2 | 0 0
* value = 0 = 0x0
* \ce
*
* RETURNS: OK, or ERROR if there is a hardware setup problem or the routine
* cannot be initialized.
*/
STATUS smNetShow
(
char * endName, /* shared memory device name (NULL = current)*/
BOOL zero /* TRUE = zero the totals */
)
{
FAST SM_END_DEV * pSmEndDev; /* END device pointer */
SM_ANCHOR * pAnchor; /* pointer to anchor */
FAST int cpuNum; /* cpu number */
struct in_addr masterAddr; /* master IP address */
struct in_addr localAddr; /* local IP address */
SM_PKT_MEM_HDR * pSmPktHdr; /* packet header */
SM_PKT_INFO smPktInfo; /* info structure */
SM_PKT_CPU_INFO cpuInfo; /* cpu info struct */
FAST SM_CPU_DESC * pCpuDesc; /* sm CPU descriptor */
FAST SM_HDR * pSmHdr;
unsigned len; /* length of sm device name */
int bogus; /* bogus space */
char mAddrStr [INET_ADDR_LEN];
char lAddrStr [INET_ADDR_LEN];
/* use default name and unit number if no interface name specified */
if ((endName == NULL) || (strlen (endName) < 1))
endName = dfltSmDevName;
/* else, derive name and unit # from input name */
else if ((len = strcspn (endName, "0123456789")) != 0)
{
unit = atoi (&endName[len]);
endName[len] = 0; /* leave just name remaining */
}
if ((pSmEndDev = (SM_END_DEV *)endFindByName (endName, unit)) == NULL)
{
printf ("Device %s%u not attached\n", endName, unit);
return (ERROR);
}
/* check validity of anchor */
pAnchor = pSmEndDev->pAnchor;
printf ("Anchor Local Addr: %p", (void *) pAnchor);
if (vxMemProbe ((char *) pAnchor, VX_READ, 4, (char *) &bogus) != OK)
{
printf (", UNREADABLE\n");
return (ERROR);
}
if (ntohl (pAnchor->readyValue) != SM_READY) /* check ready value */
{
printf (", UNINITIALIZED\n");
return (ERROR);
}
if (smIsAlive (pAnchor, &(pAnchor->smPktHeader),
pSmEndDev->smPktDesc.smDesc.base, 5, 0) == FALSE)
{
printf (", NO HEARTBEAT\n");
return (ERROR);
}
if (smPktInfoGet (&(pSmEndDev->smPktDesc), &smPktInfo) == ERROR)
{
printf (" CPU NOT ATTACHED\n");
return (ERROR);
}
if (smPktInfo.smInfo.tasType == SM_TAS_SOFT)
printf (", SOFT TAS\n");
else
printf (", Hard TAS\n");
pSmPktHdr = SM_OFFSET_TO_LOCAL (ntohl (pAnchor->smPktHeader),
pSmEndDev->smPktDesc.smDesc.base,
SM_PKT_MEM_HDR *);
pSmHdr = SM_OFFSET_TO_LOCAL (ntohl (pAnchor->smHeader), (unsigned)pAnchor,
SM_HDR *);
pCpuDesc = SM_OFFSET_TO_LOCAL (ntohl (pSmHdr->cpuTable), (unsigned)pAnchor,
SM_CPU_DESC *);
if (pSmPktHdr->reserved1 != 0)
{
localAddr.s_addr = htonl (pSmEndDev->startAddr);
masterAddr.s_addr = pSmPktHdr->reserved1;
printf ("Sequential addressing enabled.\n");
}
else
{
localAddr.s_addr = htonl (pSmEndDev->ipAddr);
masterAddr.s_addr = pCpuDesc->reserved1;
printf ("Sequential addressing disabled.\n");
}
inet_ntoa_b (masterAddr, mAddrStr);
inet_ntoa_b (localAddr, lAddrStr);
printf ("Master IP address: %s Local IP address: %s\n",
mAddrStr, lAddrStr);
printf ("\nheartbeat = %d, header at %p, free pkts = %d.\n\n",
ntohl (pSmPktHdr->heartBeat), (void *) pSmPktHdr,
smPktInfo.freePkts);
/* print out info for each CPU */
printf (
"cpu int type arg1 arg2 arg3 queued pkts\n");
printf (
"--- -------- ---------- ---------- ---------- -----------\n");
for (cpuNum = 0; cpuNum < smPktInfo.smInfo.maxCpus; ++cpuNum)
{
if (smPktCpuInfoGet (&(pSmEndDev->smPktDesc), cpuNum, &cpuInfo) == ERROR)
return (ERROR);
if (cpuInfo.status == SM_CPU_ATTACHED)
{
printf ("%2d ", cpuNum);
switch (cpuInfo.smCpuInfo.intType)
{
case SM_INT_NONE:
printf ("poll ");
break;
case SM_INT_MAILBOX_1:
printf ("mbox-1 ");
break;
case SM_INT_MAILBOX_2:
printf ("mbox-2 ");
break;
case SM_INT_MAILBOX_4:
printf ("mbox-4 ");
break;
case SM_INT_MAILBOX_R1:
printf ("mbox-1r ");
break;
case SM_INT_MAILBOX_R2:
printf ("mbox-2r ");
break;
case SM_INT_MAILBOX_R4:
printf ("mbox-4r ");
break;
case SM_INT_BUS:
printf ("bus-int ");
break;
case SM_INT_USER_1:
printf ("user 1 ");
break;
case SM_INT_USER_2:
printf ("user 2 ");
break;
default:
printf ("%#8x", cpuInfo.smCpuInfo.intType);
break;
}
printf (" %#10x %#10x %#10x", cpuInfo.smCpuInfo.intArg1,
cpuInfo.smCpuInfo.intArg2, cpuInfo.smCpuInfo.intArg3);
printf (" %3d\n", cpuInfo.inputPkts);
}
}
printf ("\n PACKETS ERRORS\n");
printf (" Unicast Brdcast\n");
printf (" Input Output Input Output Input Output\n");
printf ("======= ======= ======= ======= + ======= =======\n");
printf ("%7lu %7lu %7lu %7lu | %7lu %7lu\n",
pSmEndDev->end.mib2Tbl.ifInUcastPkts,
pSmEndDev->end.mib2Tbl.ifOutUcastPkts,
pSmEndDev->end.mib2Tbl.ifInNUcastPkts,
pSmEndDev->end.mib2Tbl.ifOutNUcastPkts,
pSmEndDev->end.mib2Tbl.ifInErrors,
pSmEndDev->end.mib2Tbl.ifOutErrors);
/* if requested, zero the interface statistics */
if (zero)
{
pSmEndDev->end.mib2Tbl.ifInUcastPkts = 0;
pSmEndDev->end.mib2Tbl.ifOutUcastPkts = 0;
pSmEndDev->end.mib2Tbl.ifInNUcastPkts = 0;
pSmEndDev->end.mib2Tbl.ifOutNUcastPkts = 0;
pSmEndDev->end.mib2Tbl.ifInErrors = 0;
pSmEndDev->end.mib2Tbl.ifOutErrors = 0;
}
return (OK);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
# Makefile - makefile for target/src/drv/erf
#
# Copyright 2005 Wind River Systems, Inc.
#
# modification history
# --------------------
# 01b,15aug05,kkz Updating doc values
# 01a,12apr05,jmt created
#
# DESCRIPTION
# This file contains the makefile rules for building the
# Event Reporting Framework library
#
TGT_DIR=$(WIND_BASE)/target
DOC_FILES= erfLib.c erfShow.c
LIB_BASE_NAME = erfLib
NODEPENDOBJS=
EXTRA_INCLUDE= -I$(TGT_DIR)/src/drv/erf
OBJS = erfLib.o erfShow.o
include $(TGT_DIR)/h/make/rules.library
include $(TGT_DIR)/h/make/defs.drivers
File diff suppressed because it is too large Load Diff
+192
View File
@@ -0,0 +1,192 @@
/* erfShow.c - Event Reporting Framework Library Show routines */
/*
* Copyright (c) 2005, 2010 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01c,29jan10,h_k LP64 adaptation.
01b,24jun05,jmt Allow multiple tasks and auto unregistration
01a,25mar05,jmt written
*/
/*
DESCRIPTION
This module provides a Show routine for the an Event Reporting Framework.
INCLUDE FILES: erfLib.h erfLibP.h vxWorks.h stdio.h stdlib.h errnoLib.h
*/
/* includes */
#include <vxWorks.h>
#include <semLib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <drv/erf/erfLib.h>
#include <drv/erf/erfLibP.h>
#include <drv/erf/erfShow.h>
/* defines */
/* typedefs */
/* globals */
extern UCHAR erfLibInitialized; /* set to TRUE when init complete */
extern struct eventHandlerStruct ** erfHandlerDb; /* Database of handlers */
extern struct eventHandlerStruct * erfUnusedHandlerStructs; /* garbage heap */
extern UINT16 erfHandlerAllocInc; /* Number of new records to allocate */
extern UINT16 erfMaxNumCat; /* Maximum number of Categories */
extern UINT16 erfMaxNumType; /* Maximum number of Types */
extern UINT16 erfMaxNumUserCat; /* Maximum number of User Categories */
extern UINT16 erfMaxNumUserType; /* Maximum number of User Types */
extern UINT16 erfNumUserCatDef; /* Number of Defined User Categories */
extern UINT16 * erfNumUserTypeDef; /* Number of Defined User Types */
extern SEM_ID erfDbSem; /* Database Semaphore */
extern struct erfQueueStruct * erfDefaultEventQueue; /* Queue for delayed events */
extern struct erfQueueStruct ** erfCatEventQueues; /* Cat Queues for delayed proc */
extern size_t erfEventQueueSize; /* Event Queue Size */
extern int erfEventTaskPriority; /* Default Event Task Priority */
extern int erfEventTaskOptions; /* Default Event Task Options */
extern size_t erfEventTaskStackSize; /* Default Event Task Stack Size */
/* locals */
/*******************************************************************************
*
* erfShow - Shows debug info for this library.
*
* RETURNS: Nothing
*
* ERRNO
*/
void erfShow
(
)
{
int Cat, Type;
/* display header */
printf("\nerfLib Status\n\n");
if (erfLibInitialized == FALSE)
{
printf("Library not initialized\n");
return;
}
/* display overall status */
printf("Max Number of Categories: %d\n", erfMaxNumCat);
printf("Max Number of Types: %d\n", erfMaxNumType);
printf("Max Number of User Categories: %d\n", erfMaxNumUserCat);
printf("Max Number of User Types: %d\n", erfMaxNumUserType);
printf("Number of defined User Cats: %d\n", erfNumUserCatDef);
/* display registered handlers */
printf("\nHandler Database:\n");
for (Cat=0; Cat<erfMaxNumCat; Cat++)
{
for (Type=0; Type<erfMaxNumType; Type++)
{
if (erfHandlerDb[(Cat * erfMaxNumType) + Type] != NULL)
{
struct eventHandlerStruct * pHandlerStruct =
erfHandlerDb[(Cat * erfMaxNumType) + Type];
while (pHandlerStruct != NULL)
{
/* display structure */
printf("Cat: %d, Type: %d, handler=%p, userData=%p\n",
Cat, Type, pHandlerStruct->pHandler,
pHandlerStruct->pUserData);
/* next */
pHandlerStruct = pHandlerStruct->next;
}
}
}
}
/* display event queue information */
printf("\nDefault Event Queue:\n");
/* display event queue status */
printf("Event Queue Address: %p\n", erfDefaultEventQueue);
printf("Event Queue Size: %d\n", erfEventQueueSize);
if (erfDefaultEventQueue != NULL)
{
printf("Event Queue List Size: %d\n", erfDefaultEventQueue->queueSize);
printf("Event Queue First Element: %d\n", erfDefaultEventQueue->firstElement);
printf("Event Queue First Free Element: %d\n", erfDefaultEventQueue->firstFreeElement);
printf("Event Queue Count Semaphore: %p\n", erfDefaultEventQueue->queueCount);
printf("Event Task Id: %p\n", erfDefaultEventQueue->eventTaskId);
printf(" Task Priority: 0x%x\n", erfEventTaskPriority);
printf(" Task Options: 0x%x\n", erfEventTaskOptions);
printf(" Task Stack Size: 0x%x\n", erfEventTaskStackSize);
}
printf("\n");
/* display registered handlers */
for (Cat=0; Cat<erfMaxNumCat; Cat++)
{
if (erfCatEventQueues[Cat] != NULL)
{
printf("Event Queue: Cat=%d\n", Cat);
}
}
}
/*******************************************************************************
*
* erfCategoriesAvailable - Get the maximum number of Categories.
*
* RETURNS: Number of categories
*
* ERRNO
*/
UINT16 erfMaxCategoriesGet (void)
{
return erfMaxNumCat;
}
/*******************************************************************************
*
* erfCategoriesAvailable - Get the maximum number of Types.
*
* RETURNS: Number of types
*
* ERRNO
*/
UINT16 erfMaxTypesGet (void)
{
return erfMaxNumType;
}
/*******************************************************************************
*
* erfDefaultQueueSizeGet - Get the size of the default queue.
*
* RETURNS: Number of elements that can be stored on the default queue.
*
* ERRNO
*/
UINT16 erfDefaultQueueSizeGet (void)
{
/* adjust the size. The number of elements stored = queueSize-1 */
return ((UINT16)((erfDefaultEventQueue == NULL) ? 0 : (erfDefaultEventQueue->queueSize-1)));
}
+34
View File
@@ -0,0 +1,34 @@
# Makefile - makefile for bsp/src/drv/hdisk
#
# modification history
# --------------------
# 01i,15aug05,kkz Updating doc values
# 01h,29apr05,kkz Updating for new doc directory
# 01g,27may04,dgp change output dir and TOC structure (DOC_CHAPTER & DOC_DIR)
# 01f,17feb04,pch remove PPC32 hack, no longer needed
# 01e,31jan03,pch Add PPC32 support
# 01d,12mar02,dat SPR 72518 Drivers docs in separate directory
# 01c,12oct01,tam added repackaging support
# 01b,01jun98,dat fixed EXTRA_INCLUDE to use TGT_DIR
# 01a,18jun96,yp created from 01b of MakeSkel
#
# DESCRIPTION
# This file contains the makefile rules for building the vx library
#
#*/
TGT_DIR=$(WIND_BASE)/target
DOC_FILES= nec765Fd.c
LIB_BASE_NAME=drv
EXTRA_INCLUDE=-I$(TGT_DIR)/h/
OBJS= nec765Fd.o
include $(TGT_DIR)/h/make/rules.library
CC_OPTIM=$(CC_OPTIM_DRIVER)
include $(TGT_DIR)/h/make/defs.drivers
File diff suppressed because it is too large Load Diff
+48
View File
@@ -0,0 +1,48 @@
# Makefile - makefile for bsp/src/drv/hdisk
#
# Copyright (c) 1996, 1998-2005, 2010 Wind River Systems, Inc.
#
# The right to copy, distribute, modify or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
# modification history
# --------------------
# 01n,25aug10,sye Remove ideDrv.o(WIND00225554)
# 01m,15aug05,kkz Updating doc values
# 01l,29apr05,kkz Updating for new doc directory
# 01k,27may04,dgp change output dir and TOC structure (DOC_CHAPTER & DOC_DIR)
# 01j,17feb04,pch remove PPC32 hack, no longer needed
# 01i,31jan03,pch Add PPC32 support
# 01h,12mar02,dat SPR 72518 Drivers docs in separate directory
# 01g,15jan02,jkf SPR#72617, removing 01d kludge.
# 01f,12oct01,tam added repackaging support
# 01e,21jun00,rsh upgrade to dosFs 2.0
# 01d,26oct99,jkf DOC_OPTS = $(DOC_OPTS_MAN) -category DOSFS2
# 01c,08oct99,jkf added a kludge to get this into the T2 component
# documentation directory "dosfs2". This change should be
# be removed for T3, since dosfs2 will no longer be a
# component release.
# 01b,01jun98,dat fixed EXTRA_INCLUDE to use TGT_DIR
# 01a,18jun96,yp created from 01c of MakeSkel
#
# DESCRIPTION
# This file contains the makefile rules for building the vx library
#
#*/
TGT_DIR=$(WIND_BASE)/target
DOC_FILES= ataDrv.c ataShow.c
LIB_BASE_NAME=drv
EXTRA_INCLUDE=-I$(TGT_DIR)/h/
OBJS= ataDrv.o ataShow.o
include $(TGT_DIR)/h/make/rules.library
CC_OPTIM=$(CC_OPTIM_DRIVER)
include $(TGT_DIR)/h/make/defs.drivers
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
# Makefile - makefile for target/src/drv/i2c
#
# modification history
# --------------------
# 01a,07oct09,mdo created
#
# DESCRIPTION
# This file contains the makefile rules for building the i2c library
#
TGT_DIR=$(WIND_BASE)/target
DOC_FILES= ixp400I2c.c
LIB_BASE_NAME= drv
EXTRA_INCLUDE= -I$(TGT_DIR)/h/
OBJS=
include $(TGT_DIR)/h/make/rules.library
CC_OPTIM=$(CC_OPTIM_DRIVER)
include $(TGT_DIR)/h/make/defs.drivers
+871
View File
@@ -0,0 +1,871 @@
/* i2cLib.c - support library for i2c master and slave drivers */
/* Copyright 1984 - 2003 Wind River Services */
/* Copyright 1984 - 2003 Wind River Systems, Inc. */
/*
modification history
--------------------
01d,05mar04,pdr Fixed warning.
01c,05nov03,e_c add comment for documentation.
01b,08apr03,e_c enable ISR call for i2cWrite and i2cRead.
01a,12jul01,a_n written.
*/
/*
DESCRIPTION
This library contains support routines for master and slave i2c drivers.
These routines are common to ALL master and slave drivers.
Specialized routines should only appear in the drivers themselves.
This framework presents the same mechanism used by the Mux layer with END drivers.
Each I2C driver is initialized using a load fonction passed to the i2cMasterDevLoad
function.
Slave device drivers will use this master device drivers when specifying
"<masterName>:<masterUnitNo>" in their load string.
After that slave device drivers can access the I2C bus with
the help of i2cRead/i2cWrite functions of the i2cLib.
Also the master will never be used directly by an application but only by slave drivers
through the i2cLib :
Application
------------------------------------------
I2C Slave driver
------------------------------------------
I2C Lib
------------------------------------------
I2C Master driver
------------------------------------------
I2C MG5200 Controller
An application will use directly slave device drivers APIs.
INCLUDE FILES:
*/
/* includes */
#include "vxWorks.h"
#include "memLib.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "intLib.h"
#include "logLib.h"
#include "errnoLib.h"
#include "drv/i2c/i2cLib.h"
#define I2CSTREQ(A, B) (strcmp(A, B) == 0 ? 1 : 0)
#define S_i2cLib_Master_LOAD_FAILED 0xFFFFAA55
#define S_i2cLib_Slave_LOAD_FAILED 0xFFFFAA56
/* defints */
/* typedefs */
/* globals */
int i2cDebug = 0;
int i2cSemAvailable = 0;
SEM_ID i2cLock = NULL;
LIST i2cMasterList;
LIST i2cSlaveList;
/* locals */
/* forward declarations */
void i2cAccessSemTake
(
I2C_MASTER_OBJ* pI2CMaster,
int tmout
)
{
semTake(pI2CMaster->accessSem,tmout);
}
void i2cAccessSemGive
(
I2C_MASTER_OBJ* pI2CMaster
)
{
semGive (pI2CMaster->accessSem);
}
void i2cMasterFlagsClr
(
I2C_MASTER_OBJ* pI2CMaster,
UINT32 clrBits
)
{
pI2CMaster->flags &= ~clrBits;
}
void i2cMasterFlagsSet
(
I2C_MASTER_OBJ* pI2CMaster,
UINT32 setBits
)
{
pI2CMaster->flags |= (setBits);
}
int i2cMasterFlagsGet
(
I2C_MASTER_OBJ* pI2CMaster
)
{
return(pI2CMaster->flags);
}
char* i2cMasterDevName
(
I2C_MASTER_OBJ* pI2CMaster
)
{
return(pI2CMaster->i2cDevObject.name);
}
void i2cSlaveAddrSet
(
I2C_SLAVE_OBJ* pI2CSlave,
UINT32 i2cAddr
)
{
pI2CSlave->i2cAddr = i2cAddr;
}
UINT32 i2cSlaveAddrGet
(
I2C_SLAVE_OBJ* pI2CSlave
)
{
return(pI2CSlave->i2cAddr);
}
/******************************************************************************
*
* i2cMasterFindByName - find a device using its string name
*
* This routine takes a string name and a unit number and finds the
* I2C Master device that has that name/unit combination.
*
* RETURNS: A pointer to an I2C_MASTER_OBJ or NULL (if the device is not found).
*
*/
I2C_MASTER_OBJ* i2cMasterFindByName
(
char* pName, /* device name to search for */
int unit
)
{
BOOL found = FALSE;
I2C_MASTER_TBL_ROW* pNode;
I2C_MASTER_OBJ* pMaster;
for (pNode = (I2C_MASTER_TBL_ROW *)lstFirst(&i2cMasterList); pNode != NULL;
pNode = (I2C_MASTER_TBL_ROW *)lstNext(&pNode->node))
{
if (I2CSTREQ(pNode->name, pName))
{
found = TRUE;
break;
}
}
if (found)
{
for (pMaster = (I2C_MASTER_OBJ *)lstFirst(&pNode->units); pMaster != NULL;
pMaster = (I2C_MASTER_OBJ *)lstNext(&pMaster->node))
{
if (pMaster->i2cDevObject.unit == unit)
{
return (pMaster);
}
}
}
return (NULL);
}
/******************************************************************************
*
* i2cSlaveFindByName - find a device using its string name
*
* This routine takes a string name and a unit number and finds the
* I2C Slave device that has that name/unit combination.
*
* RETURNS: A pointer to an I2C_SLAVE_OBJ or NULL (if the device is not found).
*
*/
I2C_SLAVE_OBJ* i2cSlaveFindByName
(
char* pName, /* device name to search for */
int unit
)
{
BOOL found = FALSE;
I2C_SLAVE_TBL_ROW* pNode;
I2C_SLAVE_OBJ* pSlave;
for (pNode = (I2C_SLAVE_TBL_ROW *)lstFirst(&i2cSlaveList); pNode != NULL;
pNode = (I2C_SLAVE_TBL_ROW *)lstNext(&pNode->node))
{
if (I2CSTREQ(pNode->name, pName))
{
found = TRUE;
break;
}
}
if (found)
{
for (pSlave = (I2C_SLAVE_OBJ *)lstFirst(&pNode->units); pSlave != NULL;
pSlave = (I2C_SLAVE_OBJ *)lstNext(&pSlave->node))
{
if (pSlave->i2cDevObject.unit == unit)
{
return (pSlave);
}
}
}
return (NULL);
}
/*******************************************************************************
*
* i2CLibInit - initialize global state for i2cLib
*
* This routine initializes all global state for i2cLib
*
* RETURNS: OK or ERROR.
*/
STATUS i2cLibInit (void)
{
STATUS status = OK;
if (i2cDebug)
logMsg ("start of muxLibInit\n", 0, 0, 0, 0, 0, 0);
if (i2cLock != NULL)
return (OK);
i2cLock = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
if (i2cLock == NULL)
return (ERROR);
/* initialize i2c Master list */
lstInit (&i2cMasterList);
if (i2cDebug)
logMsg ("End of muxLibInit\n", 0, 0, 0, 0, 0, 0);
return (status);
}
/******************************************************************************
*
* i2cMasterDevLoad - load an i2c Master device driver, if required
*
* The i2cMasterDevLoad() routine loads a i2c master interface driver. Internally,
* this routine calls the specified i2cDrvLoad() to initialize the software state
* of the device. After the device is initialized, i2cMasterDevStart() must be called
* to start the device.
* <unit> Expects the unit number of the device.
* <i2cDrvLoad> Expects a pointer to the driver's i2DrvLoad() entry point.
* <pInitString> Expects a pointer to an initialization string,
* typically a colon-delimited list of options. The i2cMasterDevLoad()
* routine passes this along blindly to the i2cDrvLoad() function.
*
*
*
*
* RETURNS: A pointer to the new device or NULL if an error occurred.
*
* ERRNO: S_i2cLib_Master_LOAD_FAILED
*/
I2C_MASTER_OBJ * i2cMasterDevLoad
(
int unit, /* unit number of device */
FUNCPTR i2cDrvLoad, /* load function of the driver */
char* pInitString /* init string for this driver */
)
{
I2C_MASTER_OBJ* pNew;
I2C_MASTER_TBL_ROW* pNode;
char initString [I2C_INIT_STR_MAX];
char devName [I2C_NAME_MAX];
BOOL found = FALSE;
if (i2cDebug)
logMsg ("Start of i2cMasterDevLoad\n", 0, 0, 0, 0, 0, 0);
bzero ( (char *)initString, I2C_INIT_STR_MAX);
bzero ( (char *)devName, I2C_NAME_MAX);
/* Let's mutually exclude here, wouldn't you say? */
semTake (i2cLock, WAIT_FOREVER);
/*
* Loading a device is a two pass algorithm.
*
* This is Pass 1.
*
* In the first pass we as the device what its name is. If that name
* exists in our table then we add the new node to the end of the
* already existing list. If not then we create a new row in the
* table, and place the new node as the zero'th (0) element in the node's
* list.
*/
if (i2cDrvLoad ( (char *)devName) != 0)
{
goto i2cMasterLoadErr;
}
if (i2cMasterFindByName ( (char *)devName, unit) != NULL)
{
goto i2cMasterLoadErr;
}
for (pNode = (I2C_MASTER_TBL_ROW *)lstFirst(&i2cMasterList); pNode != NULL;
pNode = (I2C_MASTER_TBL_ROW *)lstNext(&pNode->node))
{
if (I2CSTREQ (pNode->name, (char *)devName))
{
found = TRUE;
break;
}
}
/* If there is no row for this device then add it. */
if (!found)
{
pNode = (I2C_MASTER_TBL_ROW *) malloc(sizeof(I2C_MASTER_TBL_ROW));
if (pNode == NULL)
{
goto i2cMasterLoadErr;
}
bzero ((char *)pNode, sizeof(I2C_MASTER_TBL_ROW));
strncpy(pNode->name, devName, I2C_NAME_MAX - 1);
pNode->name [I2C_NAME_MAX - 1] = EOS;
lstAdd(&i2cMasterList, &pNode->node);
}
/*
* This is Pass 2.
*
* Now that we can determine a unique number we assign that number, to
* the device and actually load it.
*/
sprintf ( (char *)initString, "%d:%s", unit, pInitString);
pNew = (I2C_MASTER_OBJ *)i2cDrvLoad ( (char *)initString);
if (pNew == NULL)
{
goto i2cMasterLoadErr;
}
lstAdd(&pNode->units, &pNew->node);
semGive (i2cLock);
return (pNew);
i2cMasterLoadErr:
errnoSet (S_i2cLib_Master_LOAD_FAILED);
semGive (i2cLock);
return (NULL);
}
/******************************************************************************
*
* i2cSlaveDevLoad - load an i2c Slave device driver, if required
*
* The i2cSlaveDevLoad() routine loads a i2c slave interface driver. Internally,
* this routine calls the specified i2cDrvLoad() to initialize the software state
* of the device. After the device is initialized, i2cSlaveDevStart() must be called
* to start the device.
* <unit> 15
* Expects the unit number of the device.
* <i2cDrvLoad>
* Expects a pointer to the driver's i2DrvLoad() entry point.
* <pInitString>
* Expects a pointer to an initialization string, typically a colon-delimited
* list of options. The i2cSlaveDevLoad() routine passes this along blindly to
* the i2cDrvLoad() function.
*
* RETURNS: A pointer to the new device or NULL if an error occurred.
*
* ERRNO: S_i2cLib_Slave_LOAD_FAILED
*/
I2C_SLAVE_OBJ * i2cSlaveDevLoad
(
int unit, /* unit number of device */
FUNCPTR i2cDrvLoad, /* load function of the driver */
char* pInitString /* init string for this driver */
)
{
I2C_SLAVE_OBJ* pNew;
I2C_SLAVE_TBL_ROW* pNode;
char initString [I2C_INIT_STR_MAX];
char devName [I2C_NAME_MAX];
BOOL found = FALSE;
int nbytes = 0;
if (i2cDebug)
printf ("Start of i2cSlaveDevLoad\n");
bzero ( (char *)initString, I2C_INIT_STR_MAX);
bzero ( (char *)devName, I2C_NAME_MAX);
/* Let's mutually exclude here, wouldn't you say? */
semTake (i2cLock, WAIT_FOREVER);
/*
* Loading a device is a two pass algorithm.
*
* This is Pass 1.
*
* In the first pass we as the device what its name is. If that name
* exists in our table then we add the new node to the end of the
* already existing list. If not then we create a new row in the
* table, and place the new node as the zero'th (0) element in the node's
* list.
*/
if (i2cDrvLoad ( (char *)devName) != 0)
{
goto i2cSlaveLoadErr;
}
if (i2cSlaveFindByName ( (char *)devName, unit) != NULL)
{
goto i2cSlaveLoadErr;
}
for (pNode = (I2C_SLAVE_TBL_ROW *)lstFirst(&i2cSlaveList); pNode != NULL;
pNode = (I2C_SLAVE_TBL_ROW *)lstNext(&pNode->node))
{
if (I2CSTREQ (pNode->name, (char *)devName))
{
found = TRUE;
break;
}
}
/* If there is no row for this device then add it. */
if (!found)
{
pNode = (I2C_SLAVE_TBL_ROW*) malloc(sizeof(I2C_SLAVE_TBL_ROW));
if (pNode == NULL)
{
goto i2cSlaveLoadErr;
}
bzero ((char *)pNode, sizeof(I2C_SLAVE_TBL_ROW));
strncpy(pNode->name, devName, I2C_NAME_MAX - 1);
pNode->name [I2C_NAME_MAX - 1] = EOS;
lstAdd(&i2cSlaveList, &pNode->node);
}
/*
* This is Pass 2.
*
* Now that we can determine a unique number we assign that number, to
* the device and actually load it.
*/
nbytes = sprintf ( (char *)initString, "%d:%s", unit, pInitString);
if (i2cDebug)
printf ("i2cSlaveDevLoad : before i2cDrvLoad initString = %s, nbytes = %d\n", initString, nbytes);
pNew = (I2C_SLAVE_OBJ *)i2cDrvLoad ( (char *)initString);
if (pNew == NULL)
{
goto i2cSlaveLoadErr;
}
lstAdd(&pNode->units, &pNew->node);
semGive (i2cLock);
return (pNew);
i2cSlaveLoadErr:
errnoSet (S_i2cLib_Slave_LOAD_FAILED);
semGive (i2cLock);
return (NULL);
}
/*******************************************************************************
*
* i2cMasterObjInit - initialize an I2C_MASTER_OBJ structure
*
* This routine initializes an I2C_MASTER_OBJ structure and fills it with data from
* the argument list. It also creates and initializes semaphores.
*
* RETURNS: OK or ERROR.
*/
STATUS i2cMasterObjInit
(
I2C_MASTER_OBJ * pI2CMasterObj, /* object to be initialized */
char * pMasterBaseName, /* device base name, for example, "mpc8240_i2c" */
int masterUnitNo, /* unit number */
I2C_MASTER_FUNCS * pMasterFuncTable, /* master device functions */
char* pMasterDescription,
UINT32 masterFlags
)
{
/* Create the write semaphore. */
pI2CMasterObj->accessSem = semMCreate ( SEM_Q_PRIORITY |
SEM_DELETE_SAFE |
SEM_INVERSION_SAFE);
if (pI2CMasterObj->accessSem == NULL)
{
return (ERROR);
}
/* Install data and functions into the node. */
pI2CMasterObj->flags = masterFlags;
/* Check and control the length of the name string. */
if (strlen(pMasterBaseName) > sizeof(pI2CMasterObj->i2cDevObject.name))
pMasterBaseName[sizeof(pI2CMasterObj->i2cDevObject.name - 1)] = EOS;
strcpy (pI2CMasterObj->i2cDevObject.name, pMasterBaseName);
/* Check and control the length of the description string. */
if (strlen(pMasterDescription) > sizeof(pI2CMasterObj->i2cDevObject.description))
pMasterDescription[sizeof(pI2CMasterObj->i2cDevObject.description - 1)] = EOS;
strcpy (pI2CMasterObj->i2cDevObject.description, pMasterDescription);
pI2CMasterObj->i2cDevObject.unit = masterUnitNo;
pI2CMasterObj->pFuncTable = pMasterFuncTable;
return OK;
}
/*******************************************************************************
*
* i2cSlaveObjInit - initialize an I2C_SLAVE_OBJ structure
*
* This routine initializes an I2C_SLAVE_OBJ structure and fills it with data from
* the argument list. It also creates and initializes semaphores.
*
* RETURNS: OK or ERROR.
*/
STATUS i2cSlaveObjInit
(
I2C_SLAVE_OBJ * pI2CSlaveObj, /* object to be initialized */
char * pSlaveBaseName, /* device base name, for example, "mpc8240_i2c" */
int slaveUnitNo, /* unit number */
char* pSlaveDescription,
UINT32 slaveFlags,
UINT32 slaveI2CAddr,
char * pMasterBaseName, /* device base name, for example, "mpc8240_i2c" */
int masterUnitNo /* unit number */
)
{
I2C_MASTER_OBJ * pI2CMaster = NULL;
pI2CMaster = i2cMasterFindByName(pMasterBaseName, masterUnitNo);
if(pI2CMaster == NULL)
return(ERROR);
/* Check and control the length of the name string. */
if (strlen(pSlaveBaseName) > sizeof(pI2CSlaveObj->i2cDevObject.name))
pSlaveBaseName[sizeof(pI2CSlaveObj->i2cDevObject.name - 1)] = EOS;
strcpy (pI2CSlaveObj->i2cDevObject.name, pSlaveBaseName);
/* Check and control the length of the description string. */
if (strlen(pSlaveDescription) > sizeof(pI2CSlaveObj->i2cDevObject.description))
pSlaveDescription[sizeof(pI2CSlaveObj->i2cDevObject.description - 1)] = EOS;
strcpy (pI2CSlaveObj->i2cDevObject.description, pSlaveDescription);
pI2CSlaveObj->i2cDevObject.unit = slaveUnitNo;
pI2CSlaveObj->i2cAddr = slaveI2CAddr;
pI2CSlaveObj->flags = slaveFlags;
pI2CSlaveObj->i2cMaster = pI2CMaster;
return OK;
}
/*******************************************************************************
*
* i2cMasterObjFlagSet - set the `flags' member of an I2C_MASTER_OBJ structure
*
* As input, this routine expects a pointer to an I2C_MASTER_OBJ structure
* (the <pI2CMaster> parameter) and a flags value (the <flags> parameter).
* This routine sets the 'flags' member of the I2C_MASTER_OBJ structure
* to the value of the <flags> parameter.
*
* Because this routine assumes that the driver interface is now up,
* this routine also sets the 'attached' member of the referenced I2C_MASTER_OBJ
* structure to TRUE.
*
* RETURNS: OK
*/
STATUS i2cMasterObjFlagSet
(
I2C_MASTER_OBJ * pI2CMaster,
UINT32 flags
)
{
pI2CMaster->attached = TRUE;
pI2CMaster->flags = flags;
return OK;
}
/*****************************************************************************
*
* i2cWrite - write to an i2c slave device via a master i2c interface
*
* This routine writes to an i2c slave device via a master i2c interface
*
* <pCookie>
* Expects the pointer returned from i2cMasterBind(). This pointer
* identifies the binding between the i2c master and slave devices.
* <pBuff>
* Expects a pointer to the buffer that contains the data you want
* to send.
* <nBytes>
* Expects the number of bytes you want to send. Not including the address bytes.
* <options>
* Expects a bitmap of i2c options like I2C_OPT_NO_STOP
*
* RETURNS: OK, or ENO_I2C_BIND if <pCookie> does not represent a valid binding,
* or ERROR if the i2c master driver's i2cMasterWrite() routine fails.
*
*/
STATUS i2cWrite
(
I2C_SLAVE_OBJ * pI2CSlave, /* i2c slave device structure */
UINT8 * pBuff, /* data to be written */
UINT32 nBytes, /* number of bytes to write */
UINT32 options, /* transaction options */
int timeout /* timeout in ticks */
)
{
UINT8 addr7bit;
UINT8 addr10bitMsb;
UINT8 * pBuff10Bit = NULL;
int error = ENO_I2C_MASTER;
I2C_MASTER_OBJ* pI2CMaster;
pI2CMaster = pI2CSlave->i2cMaster;
if (i2cDebug)
printf ("i2cWrite : pI2CSlave = 0x%x, pI2CMaster = 0x%x\n", (int) pI2CSlave, (int) pI2CMaster);
if (pI2CMaster == NULL)
{
error = ENO_I2C_MASTER;
}
else if (pBuff != NULL)
{
/* get exclusive use of the master */
if ( !intContext() )
{
semTake(pI2CMaster->accessSem,WAIT_FOREVER);
}
if(pI2CSlave->flags & I2C_SLAVE_FLG_10_BIT_ADDR)
{
/* 10 bit addr is composed of all ones in the
* upper nibble, the upper 2 bits of the 10 bit
* address in bit position 2:1, and the read/write
* bit setting at bit 0 */
addr10bitMsb = (UINT8) ((0xF0 | (pI2CSlave->i2cAddr>>7)) & 0xFE);
/* get memory one more byte larger then input buffer
* in order to prefix the buffer with the LSB of the 10 bit addr */
pBuff10Bit = malloc(nBytes + 1);
if(pBuff10Bit == NULL)
{
/* we are done using the master, release the resource */
if ( !intContext() )
{
semGive(pI2CMaster->accessSem);
}
return(ERROR);
}
/* set the first byte of the payload to be the LSB of the
* 10 bit addr */
pBuff10Bit[0] = (UINT8) (pI2CSlave->i2cAddr & 0xFF);
bcopy(pBuff, (pBuff10Bit + 1), nBytes);
error = pI2CMaster->pFuncTable->write (pI2CMaster, addr10bitMsb,
pBuff10Bit, nBytes + 1, options, timeout);
free(pBuff10Bit);
}
else
{
addr7bit = (pI2CSlave->i2cAddr<<1) & 0xFE;
error = pI2CMaster->pFuncTable->write (pI2CMaster, addr7bit,
pBuff, nBytes, options, timeout);
}
/* we are done using the master, release the resource */
if ( !intContext() )
{
semGive(pI2CMaster->accessSem);
}
}
return (error);
}
/*****************************************************************************
*
* i2cRead - read from an i2c slave device via a master i2c interface
*
* This routine reads from an i2c slave device via a master i2c interface
*
* <pCookie>
* Expects the pointer returned from i2cMasterBind(). This pointer
* identifies the binding between the i2c master and slave devices.
* <pBuff>
* Expects a pointer to the buffer that contains the data you want
* to read into.
* <nBytes>
* Expects the number of bytes you want to read. Not including the address bytes.
* <options>
* Expects a bitmap of i2c options like I2C_OPT_NO_ACK
*
* RETURNS: OK, or ENO_I2C_BIND if <pCookie> does not represent a valid binding,
* or ERROR if the i2c master driver's i2cMasterRead() routine fails.
*
*/
STATUS i2cRead
(
I2C_SLAVE_OBJ * pI2CSlave, /* i2c slave device structure */
UINT8 * pBuff, /* data buffer to read into */
UINT32 nBytes, /* number of bytes to read */
UINT32 options, /* transaction options */
int timeout /* timeout in ticks */
)
{
UINT8 addr7bit;
UINT8 addr10bitMsb;
UINT8 pBuff10Bit[1];
I2C_MASTER_OBJ* pI2CMaster;
int error = ENO_I2C_MASTER;
pI2CMaster = pI2CSlave->i2cMaster;
if (i2cDebug)
logMsg ("i2cRead : pI2CSlave = 0x%x, pI2CMaster = 0x%x\n", (int) pI2CSlave, (int) pI2CMaster, 0, 0, 0, 0);
if (pI2CMaster == NULL)
{
error = ENO_I2C_MASTER;
}
else if (pBuff != NULL)
{
/* get exclusive use of the master */
if ( !intContext() )
{
semTake(pI2CMaster->accessSem,WAIT_FOREVER);
}
if(pI2CSlave->flags & I2C_SLAVE_FLG_10_BIT_ADDR)
{
/* 10 bit addr is composed of all ones in the
* upper nibble, the upper 2 bits of the 10 bit
* address in bit position 2:1, and the read/write
* bit setting at bit 0 */
/* we first do a dummy write operation to set the
* full 10 bit address, then we follow it will a
* read operation */
addr10bitMsb = (UINT8) ((0xF0 | (pI2CSlave->i2cAddr>>7)) & 0xFE);
/* set the single byte payload to be the LSB of the
* 10 bit addr */
pBuff10Bit[0] = (UINT8) (pI2CSlave->i2cAddr & 0xFF);
error = pI2CMaster->pFuncTable->write (pI2CMaster, addr10bitMsb,
pBuff10Bit, 1, options, timeout);
if(error != OK)
{
/* we are done using the master, release the resource */
if ( !intContext() )
{
semGive(pI2CMaster->accessSem);
}
return(error);
}
/* now switch to a read operation */
addr10bitMsb |= 0x01;
error = pI2CMaster->pFuncTable->read (pI2CMaster, addr10bitMsb,
pBuff, nBytes, options, timeout);
}
else
{
addr7bit = ((pI2CSlave->i2cAddr & 0x7F)<<1) | 0x01;
error = pI2CMaster->pFuncTable->read (pI2CMaster, addr7bit,
pBuff, nBytes, options, timeout);
}
/* we are done using the master, release the resource */
if ( !intContext() )
{
semGive(pI2CMaster->accessSem);
}
}
return (error);
}
+618
View File
@@ -0,0 +1,618 @@
/* ixp400I2c.c - Intel IXP400 I2C source file */
/*
* Copyright (c) 2002, 2004, 2005, 2007-2008 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*
* Certain portions of these files may be copyright (c) 2002-2005 Intel
* Corporation.
*/
/*
modification history
--------------------
01f,18jun08,mdo fix apigen errors
01e,08oct07,mdo Driver needs to get its header file from the target/h/drv/i2c
01d,28feb05,pai Picked up Intel mods to init functions.
01c,26jan05,pai Reorganized C-preprocessor use.
01b,20dec04,pai Updated copyright notice.
01a,05jun02,jb initial version...
*/
/*
DESCRIPTION
This is a driver for the Intel IXP400 I2C bus protocol. When the
INCLUDE_I2C_HW_CTRL BSP configuration constant is defined, the routines
in this module support the IXP465 I2C controller. Otherwise, this is a
software only implementation which uses two pins on the IXP400 GPIO
Controller.
USAGE
An example read from an I2C device using the individual protocol functions
is shown below:
\cs
...
{
if (OK == ixp400I2CStart ())
{
ixp400I2CByteTransmit ((devAddr & IXP400_I2C_WRITE_MSK));
ixp400I2CAckReceive();
ixp400I2CByteTransmit (offset);
ixp400I2CAckReceive();
/@ Switch to read mode @/
IXP400_I2C_SCL_SET_HIGH;
IXP400_I2C_SDA_SET_HIGH;
if(ixp400I2CStart() != OK)
{
ixp400I2CStop ();
return ERROR;
}
ixp400I2CByteTransmit ((devAddr | IXP400_I2C_READ_FLAG));
ixp400I2CAckReceive ();
for (byteCnt = 0; byteCnt<num; ++byteCnt)
{
ixp400I2CByteReceive (Buf);
++Buf;
/@ Prevent giving an ACK on the last byte @/
if (byteCnt < (num - 1))
ixp400I2CAckSend ();
}
ixp400I2CStop();
}
}
...
\ce
INCLUDE FILES: ixp400I2c.h
SEE ALSO:
\tb "ixp400 Data Sheet,"
*/
/* includes */
#include "vxWorks.h"
#include "config.h"
#include "ixp400.h"
#include "ixdp400.h"
#include "ixp400Gpio.h"
#include "drv/i2c/ixp400I2c.h"
#include "intLib.h"
#include "IxI2cDrv.h"
/* defines */
/* Microsecond delay for SCL setup and hold times */
#define IXP400_I2C_SCLDELAY sysMicroDelay(10)
/* Data setup time */
#define IXP400_I2C_SDADELAY sysMicroDelay(1)
#define IXP400_I2C_SDA_GET(val) (ixp400GPIOLineGet(IXP400_I2C_SDA, (val)))
#define IXP400_I2C_SCL_GET(val) (ixp400GPIOLineGet(IXP400_I2C_SCL, (val)))
#define IXP400_I2C_SDA_SET_HIGH {\
ixp400GPIOLineSet(IXP400_I2C_SDA, IXP400_GPIO_HIGH); \
IXP400_I2C_SDADELAY;}
#define IXP400_I2C_SDA_SET_LOW {\
ixp400GPIOLineSet(IXP400_I2C_SDA, IXP400_GPIO_LOW); \
IXP400_I2C_SDADELAY;}
#define IXP400_I2C_SCL_SET_HIGH {\
ixp400GPIOLineSet(IXP400_I2C_SCL, IXP400_GPIO_HIGH); \
IXP400_I2C_SCLDELAY;}
#define IXP400_I2C_SCL_SET_LOW {\
ixp400GPIOLineSet(IXP400_I2C_SCL, IXP400_GPIO_LOW); \
IXP400_I2C_SCLDELAY;}
/* imports */
extern void sysMicroDelay ();
/* forward declarations */
#ifndef INCLUDE_I2C_HW_CTRL
LOCAL STATUS ixp400I2CBusFree (void);
#endif
/******************************************************************************
*
* ixp400I2CStart - (Control signal)initiate an I2C bus transfer
*
* This routine initiates a transfer on the I2C bus. This should only be
* called from a master device (i.e. GPIO controller on IXP400).
*
* RETURNS:
* OK when the bus is free, else ERROR if the bus is already in use by
* another task.
*/
STATUS ixp400I2CStart (void)
{
#ifndef INCLUDE_I2C_HW_CTRL
int const key = intLock();
if (ixp400I2CBusFree () == OK)
{
ixp400GPIOLineConfig (IXP400_I2C_SDA, IXP400_GPIO_OUT);
ixp400GPIOLineConfig (IXP400_I2C_SCL, IXP400_GPIO_OUT);
IXP400_I2C_SCL_SET_HIGH;
IXP400_I2C_SDA_SET_HIGH;
IXP400_I2C_SDA_SET_LOW;
intUnlock (key);
return (OK);
}
intUnlock (key);
#endif
return (ERROR);
}
/******************************************************************************
*
* ixp400I2CStop - (Control signal) terminate an I2C bus transfer
*
* This routine terminates a transfer on the I2C bus. The I2C bus will be
* left in a free state; namely, SCL HIGH and SDA HIGH. This should only be
* called from a master device (i.e. GPIO controller on IXP400)
*
* RETURNS: N/A
*/
void ixp400I2CStop (void)
{
#ifndef INCLUDE_I2C_HW_CTRL
ixp400GPIOLineConfig (IXP400_I2C_SDA, IXP400_GPIO_OUT);
ixp400GPIOLineConfig (IXP400_I2C_SCL, IXP400_GPIO_OUT);
IXP400_I2C_SDA_SET_LOW;
IXP400_I2C_SCL_SET_HIGH;
IXP400_I2C_SDA_SET_HIGH;
#endif
}
/******************************************************************************
*
* ixp400I2CAckSend - (Control signal) send an acknowledgement
*
* This routine sends an acknowledgement on the I2C bus.
*
* RETURNS: N/A
*/
void ixp400I2CAckSend (void)
{
#ifndef INCLUDE_I2C_HW_CTRL
ixp400GPIOLineConfig (IXP400_I2C_SDA, IXP400_GPIO_OUT);
ixp400GPIOLineConfig (IXP400_I2C_SCL, IXP400_GPIO_OUT);
IXP400_I2C_SDA_SET_LOW;
IXP400_I2C_SCL_SET_HIGH;
IXP400_I2C_SCL_SET_LOW;
IXP400_I2C_SDA_SET_HIGH;
#endif
}
/******************************************************************************
*
* ixp400I2CAckReceive - (Control Signal) get an acknowledgement
*
* This routine gets an acknowledgement from the I2C bus.
*
* RETURNS: OK if an acknowledgement is received, else ERROR.
*/
STATUS ixp400I2CAckReceive (void)
{
STATUS status = ERROR;
#ifndef INCLUDE_I2C_HW_CTRL
int retryCnt = 0;
IXP400_GPIO_SIG sda;
ixp400GPIOLineConfig (IXP400_I2C_SDA, IXP400_GPIO_OUT);
ixp400GPIOLineConfig (IXP400_I2C_SCL, IXP400_GPIO_OUT);
IXP400_I2C_SDA_SET_HIGH;
ixp400GPIOLineConfig(IXP400_I2C_SDA, IXP400_GPIO_IN);
IXP400_I2C_SCL_SET_HIGH;
do
{
IXP400_I2C_SDA_GET (&sda);
++retryCnt;
} while ((sda != IXP400_GPIO_LOW) && (retryCnt < IXP400_I2C_ACK_RTY) );
IXP400_I2C_SCL_SET_LOW;
if (sda != IXP400_GPIO_LOW)
status = ERROR;
else
status = OK;
#endif
return status;
}
/******************************************************************************
*
* ixp400I2CByteTransmit - transmit a byte on the I2C bus
*
* This routine transmits a specified <dataByte> on the I2C bus. All
* byte transfers are Most Significant Bit (MSB) first.
*
* RETURNS: N/A
*/
void ixp400I2CByteTransmit
(
unsigned char dataByte
)
{
#ifndef INCLUDE_I2C_HW_CTRL
int bitCnt = 0;
ixp400GPIOLineConfig (IXP400_I2C_SDA, IXP400_GPIO_OUT);
ixp400GPIOLineConfig (IXP400_I2C_SCL, IXP400_GPIO_OUT);
IXP400_I2C_SCL_SET_LOW;
for (bitCnt = 7; bitCnt >= 0; --bitCnt)
{
if (dataByte & BIT (bitCnt))
{
IXP400_I2C_SDA_SET_HIGH;
}
else
{
IXP400_I2C_SDA_SET_LOW;
}
IXP400_I2C_SCL_SET_HIGH;
IXP400_I2C_SCL_SET_LOW;
}
#endif
}
/******************************************************************************
*
* ixp400I2CByteReceive - receive a byte on the I2C bus
*
* This routine receives a byte of data from the I2C bus and stores it to
* the location specified by the <dataByte> parameter. All byte transfers
* are Most Significant Bit (MSB) first.
*
* RETURNS: N/A
*/
void ixp400I2CByteReceive
(
unsigned char * dataByte
)
{
#ifndef INCLUDE_I2C_HW_CTRL
IXP400_GPIO_SIG sda = 0;
unsigned char tmpByte = 0;
int bitCnt = 0;
ixp400GPIOLineConfig (IXP400_I2C_SDA, IXP400_GPIO_IN);
ixp400GPIOLineConfig (IXP400_I2C_SCL, IXP400_GPIO_OUT);
IXP400_I2C_SCL_SET_LOW;
for (bitCnt = 7; bitCnt >= 0; --bitCnt)
{
IXP400_I2C_SCL_SET_HIGH;
IXP400_I2C_SDA_GET (&sda); /* Get the data bit */
tmpByte |= (sda << bitCnt);
IXP400_I2C_SCL_SET_LOW;
}
ixp400GPIOLineConfig (IXP400_I2C_SDA, IXP400_GPIO_OUT);
IXP400_I2C_SDA_SET_LOW;
*dataByte = tmpByte;
#endif
}
/******************************************************************************
*
* ixp400I2CBusFree - test for a free I2C bus
*
* This routine can be used to determine whether or not the I2C bus is in
* use.
*
* RETURNS: OK if the bus is free, ERROR otherwise.
*/
#ifndef INCLUDE_I2C_HW_CTRL
LOCAL STATUS ixp400I2CBusFree (void)
{
STATUS status = ERROR;
IXP400_GPIO_SIG sda = 0;
IXP400_GPIO_SIG scl = 0;
/*
* Listen in on the data (SDA), and clock (SCL) lines. If both
* are high then the bus is free.
*/
IXP400_I2C_SDA_GET (&sda);
IXP400_I2C_SCL_GET (&scl);
if((sda == IXP400_GPIO_HIGH) && (scl == IXP400_GPIO_HIGH))
status = OK;
else
status = ERROR;
return status;
}
#endif
/******************************************************************************
*
* ixp400I2CWriteTransfer - write to a slave device
*
* This routine writes <num> bytes from <buffer> to <offset> in a slave
* device with address <devAddr>.
*
* RETURNS:
* The number of bytes actually written, which may be zero or less
* than <num> in the event of an error.
*/
int ixp400I2CWriteTransfer
(
UINT8 devAddr,
UINT8 * buffer,
UINT32 num,
UINT8 offset
)
{
int byteCnt = 0;
if (NULL == buffer)
return byteCnt;
#ifdef INCLUDE_I2C_HW_CTRL
for (byteCnt = 0; byteCnt < num; ++byteCnt)
{
char tmp[2];
tmp[0] = offset + byteCnt;
tmp[1] = buffer[byteCnt];
if (IX_I2C_SUCCESS != ixI2cDrvWriteTransfer (devAddr, tmp, 2, 0))
return byteCnt;
taskDelay (((sysClkRateGet () * 100) / 1000));
}
#else
if (ixp400I2CStart () == OK)
{
ixp400I2CByteTransmit ((devAddr & IXP400_I2C_WRITE_MSK));
if(ixp400I2CAckReceive() != OK)
{
ixp400I2CStop ();
return (byteCnt);
}
ixp400I2CByteTransmit (offset);
if (ixp400I2CAckReceive () != OK)
{
ixp400I2CStop ();
return (byteCnt);
}
for(byteCnt = 0; byteCnt < num; ++byteCnt)
{
ixp400I2CByteTransmit (*buffer);
if(ixp400I2CAckReceive () != OK)
{
ixp400I2CStop ();
return (byteCnt);
}
++buffer;
}
ixp400I2CStop ();
}
#endif
return (byteCnt);
}
/******************************************************************************
*
* ixp400I2CReadTransfer - read from a slave device
*
* This routine reads <num> bytes into <buffer> from <offset> in a slave
* device with address <devAddr>.
*
* RETURNS:
* The number of bytes actually read, which may be zero or less
* than <num> in the event of an error.
*/
int ixp400I2CReadTransfer
(
UINT8 devAddr,
UINT8 * buffer,
UINT32 num,
UINT8 offset
)
{
int byteCnt = 0;
if (NULL == buffer)
return byteCnt;
#ifdef INCLUDE_I2C_HW_CTRL
/* write the slave address and offset, this sets the internal address */
if (IX_I2C_SUCCESS != ixI2cDrvWriteTransfer (devAddr, &offset, 1, 0))
return byteCnt;
/* now go into read mode */
if (IX_I2C_SUCCESS == ixI2cDrvReadTransfer (devAddr, buffer, num, 0))
{
byteCnt = num;
}
#else
if (ixp400I2CStart () == OK)
{
ixp400I2CByteTransmit ((devAddr & IXP400_I2C_WRITE_MSK));
if(ixp400I2CAckReceive () != OK)
{
ixp400I2CStop ();
return byteCnt;
}
ixp400I2CByteTransmit (offset);
if (ixp400I2CAckReceive() != OK)
{
ixp400I2CStop ();
return byteCnt;
}
/* Switch to read mode */
{
int const key = intLock ();
IXP400_I2C_SCL_SET_HIGH;
IXP400_I2C_SDA_SET_HIGH;
intUnlock (key);
}
if(ixp400I2CStart () != OK)
{
ixp400I2CStop ();
return byteCnt;
}
ixp400I2CByteTransmit ((devAddr | IXP400_I2C_READ_FLAG));
if(ixp400I2CAckReceive () != OK)
{
ixp400I2CStop ();
return byteCnt;
}
for(byteCnt = 0; byteCnt < num; ++byteCnt)
{
ixp400I2CByteReceive (buffer);
++buffer;
/* Prevent giving an ACK on the last byte */
if (byteCnt < (num - 1))
ixp400I2CAckSend ();
}
ixp400I2CStop ();
}
#endif
return (byteCnt);
}
#ifdef INCLUDE_I2C_HW_CTRL
/******************************************************************************
*
* ixp400I2CInit -
*
* RETURNS:
*
* \NOMANUAL
*/
UINT32 ixp400I2CInit (void)
{
IxI2cInitVars InitVarsSelected;
/* Select either normal (100kbps) or fast mode (400kbps) */
InitVarsSelected.I2cSpeedSelect = IX_I2C_NORMAL_MODE;
/* Select interrupt or poll mode */
InitVarsSelected.I2cFlowSelect = IX_I2C_POLL_MODE;
/* Enable/disable the unit from driving the SCL line during
* master mode operation
*/
InitVarsSelected.SCLEnable = 1;
/* The address the unit will response to as a slave device */
InitVarsSelected.I2cHWAddr = 0x01;
return (UINT32) ixI2cDrvInit (&InitVarsSelected);
}
#endif
@@ -0,0 +1,682 @@
/* m5200I2CMaster.c - MGT5200 I2C generic bus driver */
/* Copyright 2003 Wind River Systems, Inc. */
/* Copyright 2003 Wind River Services */
#include "copyright_wrs.h"
/*
modification history
--------------------
01e,19feb04,p_h introduce the variable i2cFreqSetting for i2c frequency
01c,05nov03,e_c Add comment for documentation
01b,24oct03,e_c Rewrite read cycle
01a,13oct03,e_c Written
*/
/*
DESCRIPTION
I2C bus driver for onchip MGT5200 i2c controller.
This master driver can be used for both onchip I2C controllers on the MGT5200 cpu.
This driver presents the same interface as the END drivers used by the Mux layer and
is initialized by using a load fonction by using the i2cMasterDevLoad function
of the i2cLib library. This library is provided in the cp2 BSP directory.
The I2C master device load string used to initialize routine of the driver
has the following format.
"<unit>:<regBase>"
<unit>
Device Unit number
<regBase>
Device register base memory address offset from the MBAR.
Slave device drivers will use this master device drivers when specifying
"m5200i2c:<unitNumber>" in their load string.
After that slave device drivers can access the I2C bus with
the help of i2cRead/i2cWrite functionof the i2cLib.
Also the master will never be used directly by an application but only by slave drivers
through the i2cLib :
Application
-------------------------------------------
I2C Slave driver
-------------------------------------------
I2C Lib
-------------------------------------------
I2C Master driver
-------------------------------------------
I2C MG5200 Controller
An application will use directly slave device drivers APIs
INCLUDE FILES: m5200I2CMaster.h i2cLib.h
SEE ALSO:
.pG "i2cLib"
*/
/* includes */
#include "vxWorks.h"
#include "string.h"
#include "stdlib.h"
#include "drv/i2c/i2cLib.h"
#include "drv/i2c/m5200I2CMaster.h"
#include "logLib.h"
#ifndef EIEIO
IMPORT void sysEieio (void);
#define EIEIO sysEieio ()
#endif
/* externals */
/* globals */
unsigned int i2cFreqSetting =
/* 0x1a000000; */ /* 85,9khz */
/* 0x19000000; */ /* 103khz */
/* 0x15000000; */ /* 206khz */
0x12000000; /* 343khz */
#undef DRV_DEBUG_I2C
/* Driver debug control */
#ifdef DRV_DEBUG_I2C
#define DRV_DEBUG_OFF 0x0000
#define DRV_DEBUG_RX 0x0001
#define DRV_DEBUG_TX 0x0002
#define DRV_DEBUG_ALL 0xffff
#define DRV_DEBUG_LOAD 0x0004
int m5200I2CDebug = DRV_DEBUG_RX|DRV_DEBUG_TX;
#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \
do { \
if (m5200I2CDebug & FLG) \
if (logMsg != NULL) \
logMsg (X0, (int)X1, (int)X2, (int)X3, (int)X4, \
(int)X5, (int)X6); \
} while (0)
#define DRV_PRINT(FLG, X) \
do { \
if (m5200I2CDebug & FLG) \
printf X; \
} while (0)
#else /* DRV_DEBUG_I2C */
#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)
#define DRV_PRINT(FLG, X)
#endif /* DRV_DEBUG_I2C */
/* forwards */
STATUS m5200I2CRead
(
M5200_I2C_DRV_CTRL * pDrvCtrl, /* ptr to driver structure */
UINT8 addr7bit, /* Seven bit address */
UINT8 * data, /* ptr to data buffer */
UINT32 nbytes, /* number of bytes to read */
UINT32 options,
int timeout /* time out in ticks */
);
/* forwards */
STATUS m5200I2CRead
(
M5200_I2C_DRV_CTRL * pDrvCtrl, /* ptr to driver structure */
UINT8 addr7bit, /* Seven bit address */
UINT8 * data, /* ptr to data buffer */
UINT32 nbytes, /* number of bytes to read */
UINT32 options,
int timeout /* time out in ticks */
);
STATUS m5200I2CWrite
(
M5200_I2C_DRV_CTRL * pDrvCtrl, /* ptr to driver structure */
UINT8 addr7bit, /* Seven bit address */
UINT8 * data, /* ptr to data buffer */
UINT32 nbytes, /* number of bytes to write */
UINT32 options,
int timeout /* timeout in ticks */
);
LOCAL STATUS m5200I2CRx
(
M5200_I2C_DRV_CTRL * pDrvCtrl, /* ptr to driver structure */
UINT8 * data, /* ptr to data buffer */
int stop, /* time out in ticks */
int nack, /* ptr to data buffer */
int timeout /* time out in ticks */
);
LOCAL STATUS m5200I2CTx
(
M5200_I2C_DRV_CTRL * pDrvCtrl, /* ptr to driver structure */
UINT8 data, /* ptr to data buffer */
int timeout /* timeout in ticks */
);
LOCAL STATUS m5200I2CInitParse
(
/* pointer to X220_I2C_DRV_CTRL structure */
M5200_I2C_DRV_CTRL * pDrvCtrl,
char * initString /* parameter string */
);
STATUS m5200I2CReset
(
M5200_I2C_DRV_CTRL * pDrvCtrl /* ptr to driver structure */
);
void * m5200I2CDrvLoad(char *);
/* locals */
#define M5200_I2C_WRITE32(reg_offset, val) \
(* (volatile UINT32 *) (pDrvCtrl->regBase + reg_offset) = (UINT32) val)
#define M5200_I2C_READ32(reg_offset) \
(* (volatile UINT32 *) (pDrvCtrl->regBase + reg_offset))
#define M5200_I2C_SET32(reg_offset, val) \
(M5200_I2C_WRITE32(reg_offset, (M5200_I2C_READ32(reg_offset) | (UINT32) val)))
#define M5200_I2C_CLEAR32(reg_offset, val) \
(M5200_I2C_WRITE32(reg_offset, (M5200_I2C_READ32(reg_offset) & (UINT32) ~val)))
/*
* Define the device function table. This is static across all driver
* instances.
*/
LOCAL I2C_MASTER_FUNCS i2cMasterFuncs =
{
(FUNCPTR) m5200I2CWrite, /* write func. */
(FUNCPTR) m5200I2CRead, /* read func. */
};
/***************************************************************************
*
* m5200I2CDrvLoad - Load i2c driver module
*
* Load i2c driver module
*
* The I2C master device load string formed by this routine is in the following
* following format.
* "<unit>:<regBase>"
* <unit>
* Device Unit number
* <regBase>
* Device register base memory address from MBAR value :
* - 0x3d00 for I2C1 MGT5200 controller
* - 0x3d40 for I2C2s MGT5200 controller
*
* RETURNS: OK on success, ERROR on failure
*/
void * m5200I2CDrvLoad
(
char * initString /* ptr to initialization string */
)
{
/* pointer to X220 I2C driver structure */
M5200_I2C_DRV_CTRL * pDrvCtrl;
DRV_LOG (DRV_DEBUG_LOAD, ("Loading m5200 I2C driver..\n"), 1, 2, 3, 4, 5, 6);
if (initString == NULL)
return (NULL);
if (initString[0] == 0)
{
bcopy ((char *)M5200I2C_DEV_NAME,
(void *)initString, M5200I2C_DEV_NAME_LEN);
return (0);
}
/* allocate the device structure */
pDrvCtrl = (M5200_I2C_DRV_CTRL *) calloc (sizeof (M5200_I2C_DRV_CTRL), 1);
if (pDrvCtrl == NULL)
return (NULL);
/* Parse InitString */
if (m5200I2CInitParse (pDrvCtrl, initString) == ERROR)
goto errorExit;
/*
* reset the chip: this should be replaced by a true
* adapter reset routine, once the init code is here.
*/
if (m5200I2CReset (pDrvCtrl) != OK)
goto errorExit;
/* sanity check the unit number */
if (pDrvCtrl->unit < 0 )
goto errorExit;
/* i2CObj initializations */
if (i2cMasterObjInit ((I2C_MASTER_OBJ*) pDrvCtrl,
M5200I2C_DEV_NAME,
pDrvCtrl->unit,
&i2cMasterFuncs,
"MGT 5200 I2C Master Controller",
I2C_MASTER_FLG_STANDARD_MODE_ONLY) == ERROR)
goto errorExit;
DRV_LOG (DRV_DEBUG_LOAD, ("m5200DrvLoad... Done \n"), 1, 2, 3, 4, 5, 6);
return (&pDrvCtrl->i2cMasterObj);
errorExit:
DRV_LOG (DRV_DEBUG_LOAD, "m5200DrvLoad failed\n", 0,0,0,0,0,0);
free ((char *) pDrvCtrl);
return NULL;
}
/*******************************************************************************
*
* m5200I2CInitParse - parse parameter values from initString
*
* The I2C master device load string formed by this routine is in the following
* following format.
* "<unit>:<regBase>"
* <unit>
* Device Unit number
* <regBase>
* Device register base memory address
*
* RETURNS: OK or ERROR
*/
LOCAL STATUS m5200I2CInitParse
(
/* pointer to X220_I2C_DRV_CTRL structure */
M5200_I2C_DRV_CTRL * pDrvCtrl,
char * initString /* parameter string */
)
{
char * tok; /* an initString token */
char * holder = NULL; /* points to initString fragment beyond tok */
tok = (char *) strtok_r (initString, ":", &holder);
if (tok == NULL)
return ERROR;
pDrvCtrl->unit = atoi (tok);
tok = (char *) strtok_r (NULL, ":", &holder);
if (tok == NULL)
return ERROR;
pDrvCtrl->regBase = strtoul (tok, NULL, 16);
DRV_LOG (DRV_DEBUG_LOAD,
"m5200I2CInitParse: unit=%d regBase=0x%x flags=0x%x\n",
pDrvCtrl->unit, (UINT32) pDrvCtrl->regBase,
0, 0,0,0);
return (OK);
}
/***************************************************************************
*
* m5200I2CReset - Reset the master I2C Contoller
*
* Reset the master I2C controller
*
* RETURNS: OK on success, ERROR on failure
*/
STATUS m5200I2CReset
(
M5200_I2C_DRV_CTRL * pDrvCtrl /* ptr to driver structure */
)
{
/* reset I2C module*/
M5200_I2C_WRITE32(M5200_I2C_CTRL_REG_OFFSET,
0x00000000);
EIEIO;
/* set frequency to 85,9 kHz, SDA hold time to 1,95 ms */
/* SCL_Tap:12, SDA_Tap:4, SCL2Tap:62, Tap2Tap: 64 */
M5200_I2C_WRITE32(M5200_I2C_FREQDIV_REG_OFFSET, i2cFreqSetting);
EIEIO;
/* Enable I2C Bus (Settings: Enable I2C, Disable I2C Interrupts, Transmit mode) */
M5200_I2C_WRITE32(M5200_I2C_CTRL_REG_OFFSET,
M5200_I2C_CTL_REG_EN);
EIEIO;
/* reset status register */
M5200_I2C_WRITE32(M5200_I2C_STAT_REG_OFFSET,
0x00000000);
EIEIO;
return(OK);
}
/***************************************************************************
*
* m5200I2CRead - read data from i2c slave device
*
* Read data from i2c slave device
*
* RETURNS: OK on success, ERROR on failure
*/
STATUS m5200I2CRead
(
M5200_I2C_DRV_CTRL * pDrvCtrl, /* ptr to driver structure */
UINT8 addr7bit, /* Seven bit address */
UINT8 * data, /* ptr to data buffer */
UINT32 nbytes, /* number of bytes to read */
UINT32 options,
int timeout /* time out in time loop wait */
)
{
/* index into data buffer */
int timeoutCount = 0;
if (data == NULL)
{
return ERROR;
}
m5200I2CReset(pDrvCtrl);
/* generate start Signal */
M5200_I2C_WRITE32(M5200_I2C_CTRL_REG_OFFSET,
M5200_I2C_READ32(M5200_I2C_CTRL_REG_OFFSET)|M5200_I2C_CTL_REG_TX|M5200_I2C_CTL_REG_STA);
EIEIO;
/* transmit slave adress */
if (m5200I2CTx (pDrvCtrl,addr7bit|0x1,timeout) != OK)
{
/* generate STOP */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
DRV_LOG (DRV_DEBUG_RX, ("m5200I2CRead... Tx error \n"), 1, 2, 3, 4, 5, 6);
return ERROR;
}
/* wait for bus busy */
timeoutCount = 0;
while ( ( !(M5200_I2C_READ32(M5200_I2C_STAT_REG_OFFSET) & M5200_I2C_STAT_REG_BB) ) &&
(timeoutCount < timeout ) )
{
timeoutCount++;
}
if (timeoutCount == timeout)
{
/* generate STOP */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
DRV_LOG (DRV_DEBUG_RX, ("m5200I2CRead... Timeout \n"), 1, 2, 3, 4, 5, 6);
return ERROR;
}
/* setup Receive mode */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_TX);
EIEIO;
if (nbytes == 1)
{
/* last byte must not be acknowledged */
M5200_I2C_WRITE32(M5200_I2C_CTRL_REG_OFFSET,
M5200_I2C_READ32(M5200_I2C_CTRL_REG_OFFSET)|M5200_I2C_CTL_REG_TXAK);
}
else
{
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_TXAK);
}
EIEIO;
if (nbytes)
{
/* dummy read to start transfer */
*data = I2C_TO_M5200_DATA(M5200_I2C_READ32(M5200_I2C_DATA_REG_OFFSET));
}
EIEIO;
while (nbytes)
{
if ((m5200I2CRx (pDrvCtrl, data++, nbytes==1, nbytes==2,timeout)) != OK)
{
/* generate STOP */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
DRV_LOG (DRV_DEBUG_RX, ("m5200I2CRead... Rx error \n"), 1, 2, 3, 4, 5, 6);
return ERROR;
}
nbytes--;
}
return(OK);
}
/***************************************************************************
*
* m5200I2CWrite - write data to i2c slave device
*
* Write data to i2c slave device
*
* RETURNS: OK on success, ERROR on failure
*/
STATUS m5200I2CWrite
(
M5200_I2C_DRV_CTRL * pDrvCtrl, /* ptr to driver structure */
UINT8 addr7bit, /* Seven bit address in 7 msb bits*/
UINT8 * data, /* ptr to data buffer */
UINT32 nbytes, /* number of bytes to write */
UINT32 options,
int timeout /* timeout in ticks */
)
{
int timeoutCount = 0;
if (data == NULL)
{
return ERROR;
}
m5200I2CReset(pDrvCtrl);
/* generate start Signal */
M5200_I2C_WRITE32(M5200_I2C_CTRL_REG_OFFSET,
M5200_I2C_READ32(M5200_I2C_CTRL_REG_OFFSET)|M5200_I2C_CTL_REG_TX|M5200_I2C_CTL_REG_STA);
EIEIO;
/* transmit slave adress */
if (m5200I2CTx (pDrvCtrl,addr7bit,timeout) != OK)
{
/* generate STOP */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
return ERROR;
}
/* wait for bus busy */
timeoutCount = 0;
while ( ( !( M5200_I2C_READ32(M5200_I2C_STAT_REG_OFFSET) & M5200_I2C_STAT_REG_BB) ) &&
(timeoutCount < timeout ) )
{
timeoutCount++;
}
if (timeoutCount == timeout)
{
/* generate STOP */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
return ERROR;
}
while (nbytes)
{
if (m5200I2CTx (pDrvCtrl,*data++,timeout) != OK)
{
/* generate STOP */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
return ERROR;
}
nbytes--;
}
/* generate STOP */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
return(OK);
}
/***************************************************************************
*
* m5200I2CRx - Read one byte of data on i2c bus
*
*
*
* RETURNS: OK on success, ERROR on failure
*/
LOCAL STATUS m5200I2CRx
(
M5200_I2C_DRV_CTRL * pDrvCtrl, /* ptr to driver structure */
UINT8 * data, /* ptr to data buffer */
int stop, /* stop to send */
int nack, /* no ack */
int timeout /* time out in ticks */
)
{
int timeoutCount = 0;
/* wait for tranfer finished */
timeoutCount = 0;
while ( ( !(M5200_I2C_READ32(M5200_I2C_STAT_REG_OFFSET) & M5200_I2C_STAT_REG_IF ) ) &&
(timeoutCount < timeout ) )
{
timeoutCount++;
}
if (timeoutCount == timeout)
{
/* generate STOP */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
DRV_LOG (DRV_DEBUG_RX, ("m5200I2CRx... Timeout \n"), 1, 2, 3, 4, 5, 6);
return ERROR;
}
M5200_I2C_CLEAR32(M5200_I2C_STAT_REG_OFFSET,M5200_I2C_STAT_REG_IF);
EIEIO;
if (stop)
{
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
}
if (nack)
{
M5200_I2C_WRITE32(M5200_I2C_CTRL_REG_OFFSET,
M5200_I2C_READ32(M5200_I2C_CTRL_REG_OFFSET)|M5200_I2C_CTL_REG_TXAK);
}
else
{
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_TXAK);
EIEIO;
}
*data = I2C_TO_M5200_DATA(M5200_I2C_READ32(M5200_I2C_DATA_REG_OFFSET));
EIEIO;
return OK;
}
/***************************************************************************
*
* m5200I2CTx - Transmit one byte on I2C bus
*
*
*
* RETURNS: OK on success, ERROR on failure
*/
LOCAL STATUS m5200I2CTx
(
M5200_I2C_DRV_CTRL * pDrvCtrl, /* ptr to driver structure */
UINT8 data, /* ptr to data buffer */
int timeout /* timeout */
)
{
int timeoutCount = 0;
M5200_I2C_WRITE32(M5200_I2C_DATA_REG_OFFSET,M5200_TO_I2C_DATA(data));
EIEIO;
/* wait for tranfer finished */
timeoutCount = 0;
while ( ( !( M5200_I2C_READ32(M5200_I2C_STAT_REG_OFFSET) & M5200_I2C_STAT_REG_IF) ) &&
( timeoutCount < timeout ) )
{
timeoutCount++;
}
if (timeoutCount == timeout)
{
/* generate STOP */
M5200_I2C_CLEAR32(M5200_I2C_CTRL_REG_OFFSET,M5200_I2C_CTL_REG_STA);
EIEIO;
DRV_LOG (DRV_DEBUG_TX, ("m5200I2CTx... timeout \n"), 1, 2, 3, 4, 5, 6);
return ERROR;
}
M5200_I2C_CLEAR32(M5200_I2C_STAT_REG_OFFSET,M5200_I2C_STAT_REG_IF);
EIEIO;
if (M5200_I2C_READ32(M5200_I2C_STAT_REG_OFFSET) & M5200_I2C_STAT_REG_RXAK)
{ /* Ack received? */
DRV_LOG (DRV_DEBUG_TX, ("m5200I2CTx... No ack received \n"), 1, 2, 3, 4, 5, 6);
return ERROR;
}
return OK;
}
@@ -0,0 +1,635 @@
/* ambaIntrCtl.c - AMBA interrupt controller driver */
/* Copyright 1984-2005, Wind River Systems, Inc. */
/*
modification history
--------------------
01k,01apr05,rec rmove warnings
01j,09feb05,rec fix manual autogenerate format problems
01i,03dec01,rec fix compiler warnings
01h,21sep98,cdp fixed intEnable/Disable(0) (TSR#115062);
corrected range check in ambaIntLvlEnable/Disable;
made AMBA_INT_CSR_MASK optional;
added configurable interrupt priorities.
01f,10mar98,jpd layout tidying.
01e,13nov97,cdp include intLib.h and remove things pulled in from it;
make default I/O access 32 (not 16) bits wide; documentation.
01d,15aug97,cdp rewritten for new interrupt structure (template 01d).
01c,14may97,jpd added conditional use of valid interrupts mask.
01b,18feb97,cdp renamed sysIntEnable/Disable and made global with result.
Tidyup for mangen. intEnable/Disable now return int.
01a,13dec96,cdp created from target/config/pid7t/intPid.c.
*/
/*
This module implements the AMBA interrupt controller driver.
The AMBA interrupt controller is a simple, generic interrupt controller
described in full in the ARM Reference Peripherals Specification. The
interrupt controller has status and request registers, separate enable
and disable registers and supports level-sensitive interrupts. This
library provides the routines to manage interrupts multiplexed by the
AMBA interrupt controller.
The AMBA interrupt controller has a number of registers. Those used by
this driver are described below under the symbolic names used herein.
AMBA_INT_CSR_ENB (write): this is the "Enable Set" register described
in the ARM Reference Peripherals Specification. When this register is
written, each data bit that is set (1) causes the corresponding
interrupt to be enabled. Bits that are clear (0) have no effect.
AMBA_INT_CSR_DIS (write): this is the "Enable Clear" register which has
the opposite effect. When this register is written, each data bit that
is set (1) causes the corresponding interrupt to be disabled. Bits
that are clear (0) have no effect.
AMBA_INT_CSR_PEND (read): this is the "Interrupt Request" register.
When this register is read, each data bit that is set (1) indicates an
interrupt source that is both active and enabled i.e. can interrupt the
processor. This driver provides a means by which bits in this register
can be masked if the particular implementation of AMBA returns bits in
an undefined state. Setting AMBA_INT_CSR_MASK to be a bitwise OR of
all the valid bits achieves the required effect. If
AMBA_INT_PRIORITY_MAP is not #defined (see below), the driver also uses
an external array ambaIntLvlMask[] to determine what should be written
to AMBA_INT_CSR_ENB to change interrupt levels. This should be defined
by the BSP such that ambaIntLvlMask[n] has a bit set (1) for each
interrupt source that should be enabled for interrupt level <n>. For
example, ambaIntLvlMask[0] should be 0 so that all interrupts are
disabled when interrupt level 0 is selected.
The number of interrupts supported by the device i.e. the number of
bits in the AMBA_INT_CSR_PEND register, is specified by
AMBA_INT_NUM_LEVELS.
We assume that config.h or <bsp>.h has defined the addresses of the
controller chips registers: AMBA_INT_CSR_ENB, AMBA_INT_CSR_DIS and
AMBA_INT_CSR_PEND and also the driver constants AMBA_INT_CSR_MASK (if
required) and AMBA_INT_NUM_LEVELS.
This driver assumes that the chip is memory-mapped and does direct
memory accesses to the registers which are assumed to be 32 bits wide.
If a different access method is needed, the BSP can redefine the macros
AMBA_INT_REG_READ(addr,result) and AMBA_INT_REG_WRITE(addr,data).
This driver assumes that interrupt vector numbers are calculated and
not the result of a special cycle on the bus. Vector numbers are
generated by adding the current interrupt level number to
AMBA_INT_VEC_BASE to generate a vector number which the architecture
level will use to invoke the proper handling routine. If a different
mapping scheme, or a special hardware routine is needed, then the BSP
should redefine the macro AMBA_INT_LVL_VEC_MAP(level,vector) to
override the version defined in this file.
This driver was designed to support a single instance of a real
device. At some point it should be upgraded to operate on an object
model and to support any number of real devices.
Priorities
==========
The order of interrupt level priority is undefined at the architecture
level. In this driver, level 0 is highest and and indicates that all
levels are disabled; level <AMBA_INT_NUM_LEVELS> is the lowest and
indicates that all levels are enabled.
By default, this driver implements a least-significant bit first
interrupt priority scheme (this is compatible with earlier versions of
this driver) which requires a definition of ambaIntLvlMask (see above).
If required, the driver can be compiled to implement a BSP-configurable
interrupt priority scheme by #defining AMBA_INT_PRIORITY_MAP. For this
model, the BSP should define an array of int called ambaIntLvlPriMap,
each element of which is a bit number to be polled. The list should be
terminated with an entry containing -1. This list is used in the
interrupt handler to check bits in the requested order and is also used
to generate a map of interrupt source to new interrupt level such that
whilst servicing an interrupt, all interrupts defined by the BSP to be
of lower priority than that interrupt are disabled. Interrupt sources
not in the list are serviced after all others in least-significant bit
first priority. (Note that the list is a list of ints rather than
bytes because it causes the current compiler to generate faster code.)
Note that in this priority system, intLevelSet(n) does not necessarily
disable interrupt bit n and all lower-priority ones but uses
ambaIntLvlPriMap to determine which interrupts should be masked e.g.
if ambaIntLvlPriMap[] contains { 9, 4, 8, 5, -1 }, intLevelSet(0)
disables all interrupt bits; intLevelSet(1) enables interrupt bit 9 but
disables interrupts 4, 8, 5 and all others not listed; intLevelSet(3)
enables interrupt bits 9, 4 and 8 but disables all others. This
enabling of interrupts only occurs if the interrupt has been explicitly
enabled via a call to ambaIntLvlEnable().
If the list is empty (contains just a terminator) or ambaIntLvlPriMap
is declared as an int pointer of value 0 (this is more efficient),
interrupts are handled as least-significant bit is highest priority.
The BSP will initialize this driver in sysHwInit2(), after initializing
the main interrupt library, usually intLibInit(). The initialization
routine, ambaIntDevInit() will setup the interrupt controller device,
it will mask off all individual interrupt sources and then set the
interrupt level to enable all interrupts. See ambaIntDevInit for more
information.
All of the functions in this library are global. This allows them to
be used by the BSP if it is necessary to create wrapper routines or to
incorporate several drivers together as one.
*/
#include "vxWorks.h"
#include "config.h"
#include "intLib.h"
IMPORT int ffsLsb (UINT32);
/* Defines from config.h, or <bsp>.h */
#if !defined (AMBA_INT_CSR_PEND) || !defined (AMBA_INT_CSR_ENB) || \
!defined (AMBA_INT_NUM_LEVELS) || !defined (AMBA_INT_CSR_DIS)
# error missing AMBA interrupt definitions
#endif
#define AMBA_INT_VEC_BASE (0x0)
/* hardware access methods */
#ifndef AMBA_INT_REG_READ
#define AMBA_INT_REG_READ(reg,result) \
((result) = *(volatile UINT32 *)(reg))
#endif /*AMBA_INT_REG_READ*/
#ifndef AMBA_INT_REG_WRITE
#define AMBA_INT_REG_WRITE(reg,data) \
(*((volatile UINT32 *)(reg)) = (data))
#endif /*AMBA_INT_REG_WRITE*/
/* Convert level number to vector number */
#ifndef AMBA_INT_LVL_VEC_MAP
#define AMBA_INT_LVL_VEC_MAP(level, vector) \
((vector) = ((level) + AMBA_INT_VEC_BASE))
#endif /* AMBA_INT_LVL_VEC_MAP */
#ifndef AMBA_INT_PRIORITY_MAP
/* Convert pending register value, to a level number */
#ifndef AMBA_INT_PEND_LVL_MAP
#define AMBA_INT_PEND_LVL_MAP(pendReg, level) \
((level) = (pendReg))
#endif /* AMBA_INT_PEND_LVL_MAP */
#endif /* AMBA_INT_PRIORITY_MAP */
/* driver constants */
#define AMBA_INT_ALL_ENABLED (AMBA_INT_NUM_LEVELS)
#define AMBA_INT_ALL_DISABLED 0
/* Local data */
/* Current interrupt level setting (ambaIntLvlChg). */
LOCAL UINT32 ambaIntLvlCurrent = AMBA_INT_ALL_DISABLED; /* all levels disabled*/
/*
* A mask word. Bits are set in this word when a specific level
* is enabled. It is used to mask off individual levels that have
* not been explicitly enabled.
*/
LOCAL UINT32 ambaIntLvlEnabled;
#ifdef AMBA_INT_PRIORITY_MAP
/*
* Controller masks: for each interrupt level, this provides a mask for
* the controller (see IntLvlChg).
* Mask is 32 bits * (levels + 1)
*/
LOCAL UINT32 ambaIntLvlMask[(1 + AMBA_INT_NUM_LEVELS) * sizeof(UINT32)];
/*
* Map of interrupt bit number to level: if bit n is set, ambaIntLvlMap[n]
* is the interrupt level to change to such that interrupt n and all lower
* priority ones are disabled.
*/
LOCAL int ambaIntLvlMap[AMBA_INT_NUM_LEVELS * sizeof(int)];
#endif /* AMBA_INT_PRIORITY_MAP */
/* forward declarations */
STATUS ambaIntLvlVecChk (int*, int*);
STATUS ambaIntLvlVecAck (int, int);
int ambaIntLvlChg (int);
STATUS ambaIntLvlEnable (int);
STATUS ambaIntLvlDisable (int);
/*******************************************************************************
*
* ambaIntDevInit - initialize the interrupt controller
*
* This routine will initialize the interrupt controller device, disabling all
* interrupt sources. It will also connect the device driver specific routines
* into the architecture level hooks. If the BSP needs to create a wrapper
* routine around any of the arhitecture level routines, it should install the
* pointer to the wrapper routine after calling this routine.
*
* If used with configurable priorities (#define AMBA_INT_PRIORITY_MAP),
* before this routine is called, ambaIntLvlPriMap should be initialised
* as a list of interrupt bits to poll in order of decreasing priority and
* terminated by an entry containing -1. If ambaIntLvlPriMap is a null
* pointer (or an empty list), the priority scheme used will be
* least-significant bit first. This is equivalent to the scheme used if
* AMBA_INT_PRIORITY_MAP is not defined but slightly less efficient.
*
* The return value ERROR indicates that the contents of
* ambaIntLvlPriMap (if used) were invalid.
*
* RETURNS: OK or ERROR if ambaIntLvlPriMap invalid.
*/
int ambaIntDevInit (void)
{
#ifdef AMBA_INT_PRIORITY_MAP
int i, j;
int level;
UINT32 bit;
/* if priorities are supplied, validate the supplied list */
if (ambaIntLvlPriMap != 0)
{
/* first check the list is terminated (VecChk requires this) */
for (i = 0; i < AMBA_INT_NUM_LEVELS; ++i)
if (ambaIntLvlPriMap[i] == -1)
break;
if (!(i < AMBA_INT_NUM_LEVELS))
return ERROR; /* no terminator */
/* now check that all are in range and that there are no duplicates */
for (i = 0; ambaIntLvlPriMap[i] != -1; ++i)
if (ambaIntLvlPriMap[i] < 0 ||
ambaIntLvlPriMap[i] >= AMBA_INT_NUM_LEVELS)
{
return ERROR; /* out of range */
}
else
for (j = i + 1; ambaIntLvlPriMap[j] != -1; ++j)
if (ambaIntLvlPriMap[j] == ambaIntLvlPriMap[i])
{
return ERROR; /* duplicate */
}
}
/*
* Now initialise the mask array.
* For each level (in ascending order), the mask is the mask of the
* previous level with the bit for the current level set to enable it.
*/
ambaIntLvlMask[0] = 0; /* mask for level 0 = all disabled */
/* do the levels for which priority has been specified */
level = 1;
if (ambaIntLvlPriMap != 0)
{
for ( ; level <= AMBA_INT_NUM_LEVELS &&
(i = ambaIntLvlPriMap[level - 1], i >= 0); ++level)
{
/* copy previous level's mask to this one's */
ambaIntLvlMask[level] = ambaIntLvlMask[level - 1];
/* OR in the bit indicated by the next entry in PriMap[] */
ambaIntLvlMask[level] |= 1 << i;
/*
* set index in level map: to disable this interrupt and all
* lower-priority ones, select the level one less than this
*/
ambaIntLvlMap[i] = level - 1;
}
}
/* do the rest of the levels */
i = 0; /* lowest-numbered interrupt bit */
for ( ; level <= AMBA_INT_NUM_LEVELS; ++level)
{
/* copy previous level's mask to this one's */
ambaIntLvlMask[level] = ambaIntLvlMask[level - 1];
/* try to find a bit that has not yet been set */
for ( ; ; ++i)
{
bit = 1 << i;
if ((ambaIntLvlMask[level] & bit) == 0)
{
/* this bit not set so put it in the mask */
ambaIntLvlMask[level] |= bit;
/*
* set index in level map: to disable this interrupt and all
* lower-priority ones, select the level one less than this
*/
ambaIntLvlMap[i] = level - 1;
break;
}
}
}
#endif
/* install the driver routines in the architecture hooks */
sysIntLvlVecChkRtn = ambaIntLvlVecChk;
sysIntLvlVecAckRtn = ambaIntLvlVecAck;
sysIntLvlChgRtn = ambaIntLvlChg;
sysIntLvlEnableRtn = ambaIntLvlEnable;
sysIntLvlDisableRtn = ambaIntLvlDisable;
ambaIntLvlEnabled = 0; /* all sources disabled */
ambaIntLvlChg (AMBA_INT_ALL_ENABLED); /* enable all levels */
return OK;
}
/*******************************************************************************
*
* ambaIntLvlVecChk - check for and return any pending interrupts
*
* This routine interrogates the hardware to determine the highest priority
* interrupt pending. It returns the vector associated with that interrupt, and
* also the interrupt priority level prior to the interrupt (not the
* level of the interrupt). The current interrupt priority level is then
* raised to the level of the current interrupt so that only higher priority
* interrupts will be accepted until this interrupt is finished.
*
* This routine must be called with CPU interrupts disabled.
*
* The return value ERROR indicates that no pending interrupt was found and
* that the level and vector values were not returned.
*
* RETURNS: OK or ERROR if no interrupt is pending.
*/
STATUS ambaIntLvlVecChk
(
int* pLevel, /* ptr to receive old interrupt level */
int* pVector /* ptr to receive current interrupt vector */
)
{
int newLevel;
UINT32 isr;
#ifdef AMBA_INT_PRIORITY_MAP
UINT32 *priPtr;
int bitNum;
#endif
/* Read pending interrupt register and mask undefined bits */
AMBA_INT_REG_READ (AMBA_INT_CSR_PEND, isr);
#ifdef AMBA_INT_CSR_MASK
isr &= AMBA_INT_CSR_MASK;
#endif
/* If no interrupt is pending, return ERROR */
if (isr == 0)
return ERROR;
#ifdef AMBA_INT_PRIORITY_MAP
priPtr = (UINT32 *)ambaIntLvlPriMap;
/* service interrupts according to priority specifed in map */
while (bitNum = *priPtr++, bitNum != -1)
{
/* bitNum = interrupt bit from priority map */
if (isr & (1 << bitNum))
{
break;
}
}
/*
* if priority scan didn't find anything, look for any bit set,
* starting with the lowest-numbered bit
*/
if (bitNum == -1)
bitNum = ffsLsb (isr) - 1; /* ffsLsb returns numbers from 1, not 0 */
/* if no interrupt is pending, return ERROR */
if (bitNum == -1)
return ERROR;
/* map the interrupting device to an interrupt level number */
newLevel = ambaIntLvlMap[bitNum];
#else
/* find first bit set in ISR, starting from lowest-numbered bit */
if (newLevel = ffsLsb (isr), newLevel == 0)
return ERROR;
--newLevel; /* ffsLsb returns numbers from 1, not 0 */
/* map the interrupting device to an interrupt level number */
AMBA_INT_PEND_LVL_MAP (newLevel, newLevel);
#endif /* ifdef AMBA_INT_PRIORITY_MAP */
/* change to new interrupt level, returning previous level to caller */
*pLevel = ambaIntLvlChg (newLevel);
/* fetch, or compute the interrupt vector number */
#ifdef AMBA_INT_PRIORITY_MAP
AMBA_INT_LVL_VEC_MAP (bitNum, *pVector);
#else
AMBA_INT_LVL_VEC_MAP (newLevel, *pVector);
#endif
return OK;
}
/*******************************************************************************
*
* ambaIntLvlVecAck - acknowledge the current interrupt
*
* Acknowledge the current interrupt cycle. The level and vector values are
* those generated during the ambaIntLvlVecChk() routine for this interrupt
* cycle. The basic action is to reset the current interrupt and return
* the interrupt level to its previous setting. Note that the AMBA interrupt
* controller does not need an acknowledge cycle.
*
* RETURNS: OK or ERROR if a hardware fault is detected.
*/
STATUS ambaIntLvlVecAck
(
int level, /* old interrupt level to be restored */
int vector /* current interrupt vector, if needed */
)
{
/* restore the previous interrupt level */
ambaIntLvlChg (level);
return OK;
}
/*******************************************************************************
*
* ambaIntLvlChg - change the interrupt level value
*
* This routine implements the overall interrupt setting. All levels
* up to and including the specifed level are disabled. All levels above
* the specified level will be enabled, but only if they were specifically
* enabled by the ambaIntLvlEnable() routine.
*
* The specific priority level AMBA_INT_NUM_LEVELS is valid and represents
* all levels enabled.
*
* RETURNS: Previous interrupt level.
*/
int ambaIntLvlChg
(
int level /* new interrupt level */
)
{
int oldLevel;
oldLevel = ambaIntLvlCurrent;
if (level >= 0 &&
level <= AMBA_INT_NUM_LEVELS)
{
/* change current interrupt level */
ambaIntLvlCurrent = level;
}
/* Switch off all interrupts */
AMBA_INT_REG_WRITE (AMBA_INT_CSR_DIS, (UINT32)-1);
/* Activate the enabled interrupts */
AMBA_INT_REG_WRITE (AMBA_INT_CSR_ENB,
(ambaIntLvlMask[ambaIntLvlCurrent] & ambaIntLvlEnabled));
return oldLevel;
}
/*******************************************************************************
*
* ambaIntLvlEnable - enable a single interrupt level
*
* Enable a specific interrupt level. The enabled level will be allowed
* to generate an interrupt when the overall interrupt level is set to
* enable interrupts of this priority (as configured by ambaIntLvlPriMap,
* if appropriate). Without being enabled, the interrupt is blocked
* regardless of the overall interrupt level setting.
*
* RETURNS: OK or ERROR if the specified level cannot be enabled.
*/
STATUS ambaIntLvlEnable
(
int level /* level to be enabled */
)
{
int key;
if (level < 0 ||
level >= AMBA_INT_NUM_LEVELS)
return ERROR;
/* set bit in enable mask */
key = intLock ();
ambaIntLvlEnabled |= (1 << level);
intUnlock (key);
ambaIntLvlChg (-1); /* reset current mask */
return OK;
}
/*******************************************************************************
*
* ambaIntLvlDisable - disable a single interrupt level
*
* Disable a specific interrupt level. The disabled level is prevented
* from generating an interrupt even if the overall interrupt level is
* set to enable interrupts of this priority (as configured by
* ambaIntLvlPriMap, if appropriate).
*
* RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
*/
STATUS ambaIntLvlDisable
(
int level /* level to be disabled */
)
{
int key;
if (level < 0 ||
level >= AMBA_INT_NUM_LEVELS)
return ERROR;
/* clear bit in enable mask */
key = intLock ();
ambaIntLvlEnabled &= ~(1 << level);
intUnlock (key);
ambaIntLvlChg (-1); /* reset current mask */
return OK;
}
@@ -0,0 +1,466 @@
/* i82378Ibc.c - Intel i82378 ISA Bridge Controller (IBC) driver */
/*
* Copyright (c) 1984-1996, 2008 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use of this
* software may be licensed only pursuant to the terms of an applicable Wind
* River license agreement.
*/
/*
modification history
--------------------
01t,27aug08,jpb Renamed VSB header file
01s,18jun08,jpb Added include path for kernel configurations options set in
vsb.
01r,12may08,jpb Modifications for source build. Renamed
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
01q,24aug98,cjtc windview 2.0 event logging is now single step. Timestamp no
longer stored by intEnt. Avoids out-of-sequence timestamps in
event log (SPR 21868)
01p,16apr98,pr moved triggering support from arch/ppc
01o,05mar98,pr added WV_ON mask to WV 2.0 code
01n,22feb98,pr modified windview support for WV 2.0
01m,22dec96,tpr removed intUnlock() at the end of sysIbcIntHandler() SPR(#7679)
01l,08dec96,tpr changed _func_intEnableRtn() return value from void to int.
01o,09jul97,dat fixed SPR 8866, intDisable did not work for lvls 8 to 15.
01n,17jan97,mas fixed IRQ number to IRQ level mapping (SPR 7752) and
deleted unused SEM_ID extIntHandlerSem.
01m,22dec96,tpr removed intUnlock() at the end of sysIbcIntHandler() SPR(#7679)
01l,08dec96,tpr changed _func_intEnableRtn() return value from void to int.
added sysIbcIntEnable() return value code.
01k,30oct96,dat replaced sysInByte and sysOutByte by IBC_BYTE_READ and
tam IBC_BYTE_WRITE macros (spr #7415). Added description.
01j,29oct96,wlf doc: cleanup.
01i,24sep96,mas changed MV1305 to MV1300.
01h,23jul96,tam fixed sysIbcIntLevelSet() to mask int. level <intLevel> too
01g,08jul96,ms merged in pr's WindView instrumentation
01f,01jul96,tam added code to respect interrupt priorities (spr #6212).
01e,11jun96,tam fixed sysIbcIntConnect() to enable multiple int. handlers
connected to a same vector (spr #6588).
01d,05may96,mas fix IBC interrupt mappings for MV1305 vs. ULTRA/MV1600.
01c,16apr96,jds fix IBC interrupt mappings for ULTRA vs. MV1600
01b,06mar96,tpr clean-up
01a,29jan96,tam written from i8259Pic.c.
*/
/*
DESCRIPTION
This module implements the Intel i82378 ISA Bridge Controller (IBC) driver.
The i82378 IBC chip includes many functions. This driver only implements
the interrupt control functions. In fact this driver provides the
complete interrupt architecture functionality (which it shouldn't).
The macros IBC_BYTE_READ and IBC_BYTE_WRITE control the actual access
to the PIC registers. By default, these macros assume memory mapped
access to the registers. The default write macro includes an eieio
instruction to insure write-ordering is preserved. The BSP can redefine
these macros in config.h or <bsp>.h to specify some other access means
such as i/o mapping.
The IBC_BYTE_READ macro takes two arguments, the register address and
the data address. Data is read from the register address and stored
at the data address. Defining the macro to return a value is not preferred
because if the macro has to be defined within a code block, then data
cannot easily be returned.
The IBC_BYTE_WRITE macro also takes two arguments, the register address
and the data to be written. Including an eieio instruction after the
actual data write is recommended.
Neither macro returns any values.
*/
#include <vsbConfig.h>
#include "drv/intrCtl/i82378Ibc.h"
#include "private/funcBindP.h"
/* globals */
IMPORT UINT sysVectorIRQ0; /* vector for IRQ0 */
IMPORT STATUS (*_func_intConnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int);
IMPORT int (*_func_intEnableRtn) (int);
IMPORT int (*_func_intDisableRtn) (int);
IMPORT STATUS excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
#include "private/eventP.h"
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
/* system interrupt table */
INT_HANDLER_DESC * sysIntTbl [256];
/* locals */
/* PIC1 & PIC2 IRQ masks ordered by IRQ# */
UCHAR ibcIRQ2Pic1Mask[16] = {0xFB,0xFA,0xF8,0xF8,0xF0,0xE0,0xC0,0x80,
0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8};
UCHAR ibcIRQ2Pic2Mask[16] = {0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80};
/* forward static functions */
LOCAL void sysIbcEndOfInt (void);
LOCAL STATUS sysIbcIntConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine,
int parameter);
LOCAL int sysIbcIntEnable (int);
LOCAL int sysIbcIntDisable (int);
LOCAL void sysIbcIntLevelSet (UCHAR intNumber, UCHAR pic1Mask,
UCHAR pic2Mask);
void sysIbcIntHandler (void);
/*******************************************************************************
*
* sysIbcInit - initialize the ISA Bridge Controller
*
* This routine initializes the Intel i82378 ISA Bridge Controller (IBC).
*
* RETURNS: OK, always.
*/
STATUS sysIbcInit (void)
{
UINT vector;
UCHAR intVec;
/* initialize the interrupt table */
for (vector = 0; vector < 256; vector++)
sysIntTbl[vector] = NULL;
/* connect the interrupt demultiplexer to the PowerPC external interrupt */
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, sysIbcIntHandler);
#ifdef ULTRA
/*
* route PCI interrupts to ISA IRQs and other initialization
* PCI IRQ0: routed to LN_INT_LVL
* PCI IRQ1: routed to NOTHING (no device supported)
* PCI IRQ2: routed to SCSI_INT_LVL
* PCI IRQ3: routed to NOTHING (no device supported)
*/
*(ULONG *)(CNFG_IBC_ADRS + 0x60) = LONGSWAP((0x00000000 << 24) |
(SCSI_INT_LVL << 16) |
(0x00000000 << 8) |
LN_INT_LVL);
/* make the IRQ 15,14,11,10, 9 level sensitive */
(*(char *)i82378_INT2_ELC) = 0x80 | 0x40 | 0x08 | 0x04 | 0x02 ;
#endif /* #ifdef ULTRA */
#ifdef MV1300
/*
* route PCI interrupts to ISA IRQs and other initialization
* PCI IRQ0: routed to NOTHING (no device supported)
* PCI IRQ1: routed to VME2PCI_INT_LVL
* PCI IRQ2: routed to NOTHING (no device supported)
* PCI IRQ3: routed to IRQ15
*/
*(ULONG *)(CNFG_IBC_ADRS + 0x60) = LONGSWAP(0x0f000000 |
(0x00000000 << 16) |
(VME2PCI_INT_LVL << 8) |
0x00000000);
/* make the IRQ 15,14,11,10, 9 level sensitive */
(*(char *)i82378_INT2_ELC) = 0x80 | 0x40 | 0x08 | 0x04 | 0x02 ;
#endif /* #ifdef MV1300 */
#ifdef MV1600
/*
* route PCI interrupts to ISA IRQs and other initialization
* PCI IRQ0: routed to LN_INT_LVL
* PCI IRQ1: routed to VME2PCI_INT_LVL
* PCI IRQ2: routed to SCSI_INT_LVL
* PCI IRQ3: routed to IRQ15
*/
*(ULONG *)(CNFG_IBC_ADRS + 0x60) = LONGSWAP(0x0f000000 |
(SCSI_INT_LVL << 16) |
(VME2PCI_INT_LVL << 8) |
LN_INT_LVL);
/* make the IRQ 15,14,11,10, 9 level sensitive */
(*(char *)i82378_INT2_ELC) = 0x80 | 0x40 | 0x08 | 0x04 | 0x02 ;
#endif /* #ifdef MV1600 */
/* initialize the IBC (ISA Bridge Controller) */
IBC_BYTE_WRITE (PIC_port1 (PIC1_BASE_ADR),0x11); /* ICW1 */
IBC_BYTE_WRITE (PIC_port2 (PIC1_BASE_ADR),sysVectorIRQ0); /* ICW2 */
IBC_BYTE_WRITE (PIC_port2 (PIC1_BASE_ADR),0x04); /* ICW3 */
IBC_BYTE_WRITE (PIC_port2 (PIC1_BASE_ADR),0x01); /* ICW4 */
IBC_BYTE_WRITE (PIC_port1 (PIC2_BASE_ADR),0x11); /* ICW1 */
IBC_BYTE_WRITE (PIC_port2 (PIC2_BASE_ADR),sysVectorIRQ0+8); /* ICW2 */
IBC_BYTE_WRITE (PIC_port2 (PIC2_BASE_ADR),0x02); /* ICW3 */
IBC_BYTE_WRITE (PIC_port2 (PIC2_BASE_ADR),0x01); /* ICW4 */
/* disable interrupts */
IBC_BYTE_WRITE (PIC_IMASK (PIC1_BASE_ADR),0xfb);
IBC_BYTE_WRITE (PIC_IMASK (PIC2_BASE_ADR),0xff);
/* set the BSP driver specific Interrupt Handler and intConnect routines */
_func_intConnectRtn = sysIbcIntConnect;
_func_intEnableRtn = sysIbcIntEnable;
_func_intDisableRtn = sysIbcIntDisable;
/* clear the pending interrupts */
intVec = (*(char *)ISA_INTR_ACK_REG);
sysIbcEndOfInt (); /* perform the end of interrupt procedure */
return (OK);
}
/*******************************************************************************
*
* sysIbcIntEnable - enable an IBC interrupt number
*
* This routine enables a specified IBC interrupt number.
*
* RETURNS: OK.
*
* ARGSUSED0
*/
LOCAL int sysIbcIntEnable
(
int intNumber /* interrupt number to enable */
)
{
UINT8 temp;
UINT8 *pReg;
if (intNumber < 8)
{
pReg = (UINT8 *) PIC_IMASK (PIC1_BASE_ADR);
}
else
{
pReg = (UINT8 *) PIC_IMASK (PIC2_BASE_ADR);
intNumber -= 8;
}
IBC_BYTE_READ (pReg, &temp);
IBC_BYTE_WRITE (pReg, temp & ~(1 << intNumber));
return (OK);
}
/*******************************************************************************
*
* sysIbcIntDisable - disable an IBC interrupt number
*
* This routine disables a specified IBC interrupt number.
*
* RETURNS: OK.
*
* ARGSUSED0
*/
LOCAL int sysIbcIntDisable
(
int intNumber /* interrupt number to disable */
)
{
UINT8* pReg;
UINT8 temp;
if (intNumber < 8)
{
pReg = (UINT8 *) PIC_IMASK (PIC1_BASE_ADR);
}
else
{
pReg = (UINT8 *) PIC_IMASK (PIC2_BASE_ADR);
intNumber -= 8;
}
IBC_BYTE_READ (pReg, &temp);
IBC_BYTE_WRITE (pReg, temp | (1 << intNumber));
return (OK);
}
/******************************************************************************
*
* sysIbcIntConnect - connect an interrupt handler to the system vector table
*
* This function connects an interrupt handler to the system vector table.
*
* RETURNS: OK/ERROR.
*/
LOCAL STATUS sysIbcIntConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
INT_HANDLER_DESC * newHandler;
INT_HANDLER_DESC * currHandler;
if (((int)vector < 0) || ((int)vector > 0xff)) /* Out of Range? */
return (ERROR);
/* create a new interrupt handler */
newHandler = malloc (sizeof (INT_HANDLER_DESC));
/* check if the memory allocation succeed */
if (newHandler == NULL)
return (ERROR);
/* initialize the new handler */
newHandler->vec = routine;
newHandler->arg = parameter;
newHandler->next = NULL;
if (sysIntTbl[(int) vector] == NULL)
sysIntTbl [(int ) vector] = newHandler; /* single int. handler case */
else
{
currHandler = sysIntTbl[(int) vector]; /* multiple int. handler case */
while (currHandler->next != NULL)
{
currHandler = currHandler->next;
}
currHandler->next = newHandler;
}
return (OK);
}
/******************************************************************************
*
* sysIbcIntHandler - handle an i82378 IBC interrupt
*
* This routine is called to handle an Intel i82378 ISA Bridge Controller
* (IBC) interrupt exception.
*
* This routine generates the PCI IACK cycle to get the interrupt vector from
* the PIC chips. Once the vector is obtained, it is used as an index into
* the system vector table to locate the user-defined interrupt routine for
* that vector. Each entry in the vector table is a part of a singly-linked
* list and all routines on that list are executed in order.
*
* RETURNS: N/A
*/
void sysIbcIntHandler (void)
{
UCHAR intVec;
INT_HANDLER_DESC * currHandler;
char intReg1;
char intReg2;
int lock;
/*
* Reading ISA_INTR_ACK_REG would generate PCI IACK cycles on the
* PCI bus which would cause the IBC to put out vector from the 82378
* on the PCI bus.
* Bit 5 of PCI control register in the IBC i82378 should be
* programmed to 1 (By default it is 1) if the IBC should respond with
* a vector when PCI IACK cycles are generated.
*/
intVec = (*(char *)ISA_INTR_ACK_REG);
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
WV_EVT_INT_ENT(intVec)
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
/* Record current interrupt mask settings */
IBC_BYTE_READ (PIC_IMASK (PIC1_BASE_ADR), &intReg1);
IBC_BYTE_READ (PIC_IMASK (PIC2_BASE_ADR), &intReg2);
/* Mask this and lower priority interrupt levels */
sysIbcIntLevelSet (intVec, intReg1, intReg2);
/*
* Now the interrupt acknowledge is made, the interrupt can be re-enabled
*/
intUnlock (_PPC_MSR_EE);
/* call EACH respective interrupt handler */
if ((currHandler = sysIntTbl [intVec]) == NULL)
logMsg ("uninitialized interrupt %d\n", intVec, 0,0,0,0,0);
else
{
while (currHandler != NULL)
{
currHandler->vec (currHandler->arg);
currHandler = currHandler->next;
}
}
sysIbcEndOfInt (); /* perform the end of interrupt procedure */
/* Set the original interrupt masks back */
lock = intLock ();
IBC_BYTE_WRITE (PIC_IMASK (PIC1_BASE_ADR), intReg1);
IBC_BYTE_WRITE (PIC_IMASK (PIC2_BASE_ADR), intReg2);
}
/*******************************************************************************
*
* sysIbcEndOfInt - send EOI(end of interrupt) signal.
*
* This routine is called at the end of the interrupt handler.
*
*/
LOCAL void sysIbcEndOfInt (void)
{
IBC_BYTE_WRITE (PIC_IACK (PIC1_BASE_ADR), 0x20);
IBC_BYTE_WRITE (PIC_IACK (PIC2_BASE_ADR), 0x20);
}
/*******************************************************************************
*
* sysIbcIntLevelSet - set the interrupt mask
*
* This routine masks interrupts from the level of 'intNumber' to 15.
*
* RETURNS: N/A
*/
LOCAL void sysIbcIntLevelSet
(
UCHAR intNumber, /* interrupt level where to mask from */
UCHAR pic1Mask, /* state of Pic1 mask at IRQ */
UCHAR pic2Mask /* state of Pic2 mask at IRQ */
)
{
pic1Mask |= ibcIRQ2Pic1Mask[intNumber]; /* make new masks */
pic2Mask |= ibcIRQ2Pic2Mask[intNumber];
IBC_BYTE_WRITE (PIC_IMASK (PIC1_BASE_ADR), pic1Mask); /* set new masks */
IBC_BYTE_WRITE (PIC_IMASK (PIC2_BASE_ADR), pic2Mask);
}
@@ -0,0 +1,736 @@
/* i8259Intr.c - Intel 8259A PIC (Programmable Interrupt Controller) driver */
/*
* Copyright (c) 1993-2008,2014 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01x,24sep14,j_l VXW6-83369 - Use INCLUDE_SYMMETRIC_IO_MODE
01w,27aug08,jpb Renamed VSB header file
01v,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
for kernel configurations options set in vsb.
01u,18jun07,scm remove reference to sysCpuNumGet, replace with
vxCpuIndexGet...
01t,09oct06,scm remove sysBp dependencey for SMP...
01s,09nov05,mdo Fixes for apigen
01r,07may04,zmm Fix diab compiler warnings.
01q,11nov02,hdn fixed the IRQ15 spurious interrupt handling (spr 74209)
01p,16apr02,hdn added support for the Special Fully Nested Mode, IRQ0 Early
EOI Mode, IRQ0 Special Mask Mode, AEOI Mode (spr 76411)
01o,29mar02,hdn added forgotten back slash to the optimized code
01n,21mar02,hdn fixed doc build by removing comments in the optimized code
01m,25feb02,hdn updated i8259Init() for HTT (spr 73738)
added optimized version of EOI routines
01l,11sep01,hdn updated comment regarding the spr-28547 fix.
01k,27aug99,hdn fixed a bug for stray interrupt in i8259IntBoi(SPR 28547).
01j,11oct98,ms fixed compiler warning via typecast
01i,04jun98,hdn changed a method to exit i8259IntBoi().
01h,25may98,hdn changed function name starting from "i8259".
added i8259IntEoiMaster(), i8259IntEoiSlave(), i8259IntBoi().
removed sysIntEOI().
01g,17mar97,hdn added sysIntLock(), sysIntUnlock() for the system mode.
01f,25jun96,hdn added sysIntLevel() for windview.
01e,23may96,wlf doc: cleanup.
01d,14jun95,hdn renamed sysEndOfInt to sysIntEOI.
moved global function prototypes to sysLib.h.
01c,08aug94,hdn stopped toggling IRQ9 in enabling and disabling.
01b,22apr94,hdn made IRQ9 off in the initialization.
moved sysVectorIRQ0 to sysLib.c.
01a,05sep93,hdn written.
*/
/*
DESCRIPTION
This module is a driver for the Intel 8259A PIC (Programmable Interrupt
Controller). The Intel 8259A handles up to 8 vectored priority interrupts
for the CPU. It is cascadable for up to 64 vectored priority interrupts,
though this driver assumes two cascaded 8259A. It is initialized for
"Fully Nested Mode", "Non-Specific EOI" mode.
Fully Nested Mode.
In this mode, interrupt requests are ordered in priority
from 0 through 7 (0 is the highest priority). When an interrupt is
acknowledged, the highest priority request is determined and its vector is
placed on the bus. Additionally, a bit of the Interrupt Service (IS)
register is set. This bit remains set until the microprocessor issues an
EOI command immediately before returning from the service routine. While
the IS bit is set, all further interrupts of the same or lower priority
are inhibited, while higher level interrupts are allowed. The
i8259IntEoiSlaveNfnm() routine is used to issue the EOI command. The PICs
in a PC typically operate in this mode (normal nested mode). In this mode,
while the slave PIC is being serviced by the master PIC, the slave PIC blocks
all higher priority interrupt requests. Alternatively, to allow interrupts of
a higher priority, enable the Special Fully Nested Mode.
Special Fully Nested Mode: I8259_SPECIAL_FULLY_NESTED_MODE.
This mode is similar to the Fully Nested Mode with the following exceptions:
1) When an interrupt request from a slave PIC is in service, the slave is
not locked out from the master's priority logic and further interrupt
requests from higher priority IRs within the slave will be recognized by
the master and will initiate interrupts to the processor. 2) When exiting
the interrupt service routine, the software must check whether or not the
interrupt serviced was the only interrupt request from the slave. If it
was the only interrupt request, a non-specific EOI is sent to the master.
If not, no EOI is sent. This is implemented by the i8259EoiSlaveSfnm()
routine.
Non-Specific EOI: When the 8259A is operated in the Fully Nested Mode, it
can determine which IS bit to reset on EOI. When a non-specific EOI
command is issued, the 8259A will automatically reset the highest IS bit of
those that are set, since in the fully nested mode the highest IS level is
the last level acknowledged and serviced.
Spurious/Phantom Interrupt: The IR inputs must remain high until after the
falling edge of the first INTA. If the IR input goes low before this time,
a DEFAULT(Spurious/Phantom) IR7 will occur when the CPU acknowledges the
interrupt. The interrupt handler should simply return without sending
an EOI command.
The PIC(8259A) IRQ0 is hard wired to the PIT(8253) channel 0 in a PC
motherboard. IRQ0 is the highest priority in the 8259A interrupt
controller. Thus, the system clock interrupt handler blocks all lower
level interrupts. This may cause a delay of the lower level interrupts in
some situations even though the system clock interrupt handler finishes its
job without any delay. This is quite natural from the hardware point of
view, but may not be ideal from the application software standpoint. The
following modes are supplied to mitigate this situation by providing
corresponding configuration macros in the BSP. The three modes are mutually
exclusive.
Early EOI Issue in IRQ0 ISR.
In this mode, the EOI command is issued before the IRQ0 system clock interrupt
service routine starts the kernel work. This lowers the IRQ0 ISR blocking
level to the next lower level. If no IRQs are in service, the next lower
level is the lowest level. If IRQn is in service, the next lower level
corresponds to the next lower priority. As a result, the kernel work in the
system clock interrupt service routine can be interrupted by an interrupt
with a higher priority than the blocking level. The i8259IntBoiEem() routine
is called before the interrupt service routine, and no EOI is sent after
the interrupt service routine.
Special Mask Mode in IRQ0 ISR.
In this mode, the Special Mask Mode is used in the IRQ0 system clock
service routine. This lowers the blocking level to the specified level
(currently hard coded to the lowest level). The i8259IntBoiSmm() routine
is called before the interrupt service routine, and the i8259IntEoiSmm()
routine is called after the interrupt service routine.
Automatic EOI Mode: I8259_AUTO_EOI.
This mode provides no nested multi-level interrupt structure in PIC1. The
EOI command is automatically sent to the master PIC at the end of the
interrupt acknowledge cycle. Thus, no software intervention is needed. The
i8259IntBoi() routine is called before the IRQ7 and IRQ15 interrupt service
routines. Either the i8259IntEoiSlaveNfnm() routine or the
i8259IntEoiSlaveSfnm() routine is called after the slave PIC's interrupt
service routine.
SEE ALSO: pc386/target.ref
INCLUDE FILES: i8259.h
*/
#include <vsbConfig.h>
#include <drv/intrCtl/i8259.h>
/* externs */
IMPORT void intBoiExit ();
IMPORT UINT32 sysStrayIntCount;
#ifndef _WRS_CONFIG_SMP
IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
#endif /* _WRS_CONFIG_SMP */
/* defines */
#define I8259_EOI_OPTIMIZED /* use the optimized version */
/* globals */
/* local */
#if !defined(SYMMETRIC_IO_MODE) && !defined(INCLUDE_SYMMETRIC_IO_MODE)
LOCAL INT8 i8259IntMask1; /* interrupt mask for PIC1 */
LOCAL INT8 i8259IntMask2; /* interrupt mask for PIC2 */
LOCAL INT8 i8259Mask = 0; /* interrupt mask for PIC1 */
#endif /* !SYMMETRIC_IO_MODE && !INCLUDE_SYMMETRIC_IO_MODE */
/* forward static functions */
/*******************************************************************************
*
* i8259Init - initialize the PIC
*
* This routine initializes the PIC.
*
* RETURNS: N/A
*
* ERRNO
*/
VOID i8259Init (void)
{
UINT8 icw4 = 0x01;
/* return if it is not the Boot Processor (BP) */
#ifndef _WRS_CONFIG_SMP
if (sysBp == FALSE)
#else
if (vxCpuIndexGet() != 0)
#endif /* _WRS_CONFIG_SMP */
return;
/* initialize the PIC (Programmable Interrupt Controller) */
sysOutByte (PIC_port1 (PIC1_BASE_ADR),0x11); /* ICW1 */
sysOutByte (PIC_port2 (PIC1_BASE_ADR),INT_NUM_IRQ0); /* ICW2 */
sysOutByte (PIC_port2 (PIC1_BASE_ADR),0x04); /* ICW3 */
#ifdef I8259_SPECIAL_FULLY_NESTED_MODE
icw4 |= 0x10; /* SFNM */
#endif /* I8259_SPECIAL_FULLY_NESTED_MODE */
#ifdef I8259_AUTO_EOI
icw4 |= 0x02; /* AEOI */
#endif /* I8259_AUTO_EOI */
sysOutByte (PIC_port2 (PIC1_BASE_ADR),icw4); /* ICW4 */
sysOutByte (PIC_port1 (PIC2_BASE_ADR),0x11); /* ICW1 */
sysOutByte (PIC_port2 (PIC2_BASE_ADR),(char) (INT_NUM_IRQ0+8)); /* ICW2 */
sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x02); /* ICW3 */
sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x01); /* ICW4 */
/* disable interrupts */
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), (char)0xfb);
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), (char)0xff);
}
#if !defined(SYMMETRIC_IO_MODE) && !defined(INCLUDE_SYMMETRIC_IO_MODE)
/*******************************************************************************
*
* i8259IntBoiEem - issue EOI before the IRQ0 interrupt handler
*
* This routine is called before the IRQ0 interrupt handler that is PIT(8253)
* channel 0 system clock interrupt handler in the Early EOI Mode.
*
* RETURNS: N/A
*
* ERRNO
*/
VOID i8259IntBoiEem
(
int irqNo /* IRQ number of the interrupt */
)
{
INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
}
/*******************************************************************************
*
* i8259IntBoiSmm - enable Special Mask Mode before the IRQ0 interrupt handler
*
* This routine is called before the IRQ0 interrupt handler that is PIT(8253)
* channel 0 system clock interrupt handler, in the Special Mask Mode.
*
* RETURNS: N/A
*
* ERRNO
*/
VOID i8259IntBoiSmm
(
int irqNo /* IRQ number of the interrupt */
)
{
INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x68); /* enable SMM PIC1 */
i8259Mask = sysInByte (PIC_IMASK (PIC1_BASE_ADR)); /* save int mask */
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), 0x01); /* unlock except IRQ0 */
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
}
/*******************************************************************************
*
* i8259IntBoi - detect whether it is spurious interrupt or not
*
* This routine is called before the user's interrupt handler to detect the
* spurious interrupt.
*
* RETURNS: N/A
*
* ERRNO
*/
VOID i8259IntBoi
(
INT32 irqNo /* IRQ number of the interrupt */
)
{
INT32 oldLevel;
INT8 inserviceReg;
/* we are interested in IRQ7 and IRQ15 */
if ((irqNo != 7) && (irqNo != 15))
return;
/* if ISR bit is not set, we change the return address */
oldLevel = intLock (); /* LOCK INTERRUPT */
if (irqNo == 7)
{
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
}
else
{
sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b);
inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR));
/* check bit7 for spurious interrupt from the slave PIC IRQ15 */
if ((inserviceReg & 0x80) == 0)
{
/* make sure no IRQs in the slave PIC are in service */
if (inserviceReg == 0)
{
/* check the master PIC's in-service register */
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
/* send non-specific EOI to the master PIC IRQ2 */
if (inserviceReg & 0x04)
sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI);
}
}
}
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
/*
* another implementation idea...
*
* *((UINT32 *)&irqNo - 1) = (UINT32)intBoiExit;
* This changes the return addr on the stack. This is architecture
* specific and tricky. Thus making following change may be good idea.
*
* - let this routine return OK or ERROR
* - let interrupt stub code check the ret value and jump to intExit.
*
* New code would be like this:
* :
* if ((irqNo != 7) && (irqNo != 15))
* return (OK);
* :
* if ((inserviceReg & 0x80) == 0) * check bit7 for IRQ7 and IRQ15 *
* {
* sysStrayIntCount++; * increment the counter *
* return (ERROR);
* }
* }
*
* 00 e8 kk kk kk kk call _intEnt * tell kernel
* 05 50 pushl %eax * save regs
* 06 52 pushl %edx
* 07 51 pushl %ecx
* 08 68 pp pp pp pp pushl $_parameterBoi * push BOI param
* 13 e8 rr rr rr rr call _routineBoi * call BOI routine
* addl $4, %esp
* cmpl $0, %eax
* jne intConnectCode0
* 18 68 pp pp pp pp pushl $_parameter * push param
* 23 e8 rr rr rr rr call _routine * call C routine
* addl $4, %esp
* 28 68 pp pp pp pp pushl $_parameterEoi * push EOI param
* 33 e8 rr rr rr rr call _routineEoi * call EOI routine
* 38 83 c4 04 addl $4, %esp * pop param
* intConnectCode0:
* 41 59 popl %ecx * restore regs
* 42 5a popl %edx
* 43 58 popl %eax
* 44 e9 kk kk kk kk jmp _intExit * exit via kernel
*/
if ((inserviceReg & 0x80) == 0) /* check bit7 for IRQ7 and IRQ15 */
{
sysStrayIntCount++; /* increment the counter */
*((UINT32 *)&irqNo - 1) = (UINT32)intBoiExit; /* change return addr */
}
}
/*******************************************************************************
*
* i8259IntEoiSmm - disable Special Mask Mode with EOI signal to the master PIC
*
* This routine is called at the end of the IRQ0 interrupt handler that is
* PIT(8253) channel 0 system clock interrupt handler in the Special Mask Mode.
*
* RETURNS: N/A
*
* ERRNO
*/
VOID i8259IntEoiSmm
(
int irqNo /* IRQ number to send EOI */
)
{
INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), i8259Mask); /* restore old mask */
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x08); /* disable SMM PIC1 */
sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
}
/*******************************************************************************
*
* i8259IntEoiMaster - send EOI(end of interrupt) signal to the master PIC.
*
* This routine is called at the end of the interrupt handler.
*
* RETURNS: N/A
*
* ERRNO
*/
VOID i8259IntEoiMaster
(
INT32 irqNo /* IRQ number to send EOI */
)
{
#ifdef I8259_EOI_OPTIMIZED /* optimized version */
WRS_ASM (" \
pushfl; \
cli; \
movl $0x20, %edx; \
movl $0x20, %eax; \
outb %al, %dx; \
popfl; \
");
#else /* portable version */
INT32 oldLevel = intLock (); /* LOCK INTERRUPTS */
sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); /* non-specific EOI */
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
#endif /* I8259_EOI_OPTIMIZED */
}
/*******************************************************************************
*
* i8259IntEoiSlave - send EOI(end of interrupt) signal to the slave PIC.
*
* This routine is called at the end of the interrupt handler in the Normal
* Fully Nested Mode. This is kept for the backward compatibility.
*
* RETURNS: N/A
*
* ERRNO
*/
VOID i8259IntEoiSlave
(
INT32 irqNo /* IRQ number to send EOI */
)
{
#ifdef I8259_EOI_OPTIMIZED /* optimized version */
WRS_ASM (" \
pushfl; \
cli; \
movl $0xa0, %edx; \
movl $0x20, %eax; \
outb %al, %dx; \
movl $0x20, %edx; \
outb %al, %dx; \
popfl; \
");
#else /* portable version */
INT32 oldLevel = intLock (); /* LOCK INTERRUPTS */
sysOutByte (PIC_IACK (PIC2_BASE_ADR), I8259_EOI); /* non-specific EOI */
sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); /* non-specific EOI */
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
#endif /* I8259_EOI_OPTIMIZED */
}
/*******************************************************************************
*
* i8259IntEoiSlaveNfnm - send EOI(end of interrupt) signal to the slave PIC.
*
* This routine is called at the end of the interrupt handler in the Normal
* Fully Nested Mode.
*
* RETURNS: N/A
*
* ERRNO
*/
VOID i8259IntEoiSlaveNfnm
(
INT32 irqNo /* IRQ number to send EOI */
)
{
#ifdef I8259_EOI_OPTIMIZED /* optimized version */
WRS_ASM (" \
pushfl; \
cli; \
movl $0xa0, %edx; \
movl $0x20, %eax; \
outb %al, %dx; \
movl $0x20, %edx; \
outb %al, %dx; \
popfl; \
");
#else /* portable version */
INT32 oldLevel = intLock (); /* LOCK INTERRUPTS */
sysOutByte (PIC_IACK (PIC2_BASE_ADR), I8259_EOI); /* non-specific EOI */
sysOutByte (PIC_IACK (PIC1_BASE_ADR), I8259_EOI); /* non-specific EOI */
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
#endif /* I8259_EOI_OPTIMIZED */
}
/*******************************************************************************
*
* i8259IntEoiSlaveSfnm - send EOI(end of interrupt) signal to the slave PIC.
*
* This routine is called at the end of the interrupt handler in the Special
* Fully Nested Mode.
*
* RETURNS: N/A
*
* ERRNO
*/
VOID i8259IntEoiSlaveSfnm
(
int irqNo /* IRQ number to send EOI */
)
{
INT8 inserviceReg;
INT32 oldLevel = intLock (); /* LOCK INTERRUPT */
sysOutByte (PIC_IACK (PIC2_BASE_ADR), 0x20); /* NS EOI to PIC2 */
sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b); /* issue OCW3 */
inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR)); /* read ISR */
if (inserviceReg == 0)
sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20); /* NS EOI to PIC1 */
intUnlock (oldLevel); /* UNLOCK INTERRUPT */
}
/*******************************************************************************
*
* i8259IntDisable - disable a specified PIC interrupt input line
*
* This routine disables a specified PIC interrupt input line.
*
* RETURNS: OK, always.
*
* SEE ALSO: i8259IntEnable()
*
* ERRNO
*/
LOCAL STATUS i8259IntDisable
(
INT32 irqNo /* IRQ number to disable */
)
{
if (irqNo < 8)
{
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
sysInByte (PIC_IMASK (PIC1_BASE_ADR)) | (1 << irqNo));
}
else
{
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
sysInByte (PIC_IMASK (PIC2_BASE_ADR)) | (1 << (irqNo - 8)));
}
return (OK);
}
/*******************************************************************************
*
* i8259IntEnable - enable a specified PIC interrupt input line
*
* This routine enables a specified PIC interrupt input line.
*
* RETURNS: OK, always.
*
* SEE ALSO: i8259IntDisable()
*
* ERRNO
*/
LOCAL STATUS i8259IntEnable
(
INT32 irqNo /* IRQ number to enable */
)
{
if (irqNo < 8)
{
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
sysInByte (PIC_IMASK (PIC1_BASE_ADR)) & ~(1 << irqNo));
}
else
{
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
sysInByte (PIC_IMASK (PIC2_BASE_ADR)) & ~(1 << (irqNo - 8)));
}
return (OK);
}
/*******************************************************************************
*
* i8259IntLock - lock out all PIC interrupts
*
* This routine saves the mask and locks out all PIC interrupts.
* It should be called in the interrupt disable state(IF bit is 0).
*
* RETURNS: N/A
*
* SEE ALSO: i8259IntUnlock()
*
* ERRNO
*/
LOCAL VOID i8259IntLock (void)
{
i8259IntMask1 = sysInByte (PIC_IMASK (PIC1_BASE_ADR));
i8259IntMask2 = sysInByte (PIC_IMASK (PIC2_BASE_ADR));
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), (char)0xff);
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), (char)0xff);
}
/*******************************************************************************
*
* i8259IntUnlock - unlock the PIC interrupts
*
* This routine restores the mask and unlocks the PIC interrupts
* It should be called in the interrupt disable state(IF bit is 0).
*
* RETURNS: N/A
*
* SEE ALSO: i8259IntLock()
*
* ERRNO
*/
LOCAL VOID i8259IntUnlock (void)
{
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), i8259IntMask1);
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), i8259IntMask2);
}
#if FALSE
/*
* There is a function sysIntLevel() which gets the interrupt level from the
* interrupt stub, so we don't need it anymore.
*/
/*******************************************************************************
*
* i8259IntLevel - Get IRQ number by reading Interrupt Service Register.
*
* This routine is called to get an IRQ number in service.
*
* RETURNS: 0 - 15
*
* ERRNO
*/
LOCAL INT32 i8259IntLevel (void)
{
INT32 inserviceReg;
INT32 irq;
INT32 oldLevel;
INT32 retry;
oldLevel = intLock ();
for (retry=0; retry < 1; retry ++)
{
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
for (irq=0; irq < 8; irq++)
if ((inserviceReg & 1) && (irq != 2))
goto i8259IntLevelExit;
else
inserviceReg >>= 1;
sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b);
inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR));
for (irq=8; irq < 16; irq++)
if (inserviceReg & 1)
goto i8259IntLevelExit;
else
inserviceReg >>= 1;
}
i8259IntLevelExit:
intUnlock (oldLevel);
return (irq);
}
#endif /* FALSE */
#endif /* !SYMMETRIC_IO_MODE && !INCLUDE_SYMMETRIC_IO_MODE */
@@ -0,0 +1,269 @@
/* i8259Pic.c - Intel 8259A PIC (Programmable Interrupt Controller) driver */
/* Copyright (c) 1993-2005 Wind River Systems, Inc. */
/*
modification history
--------------------
01k,09nov05,mdo Fixes for apigen
01j,26oct04,jb Really fix SPR 102687
01i,14oct04,jb Fix compiler warnings
01h,20sep04,pes added conditional compilation of sysIntInitPic and
sysIntEOI functions to allow them to be excluded when not
being used. This eliminates compilation warnings about
local functions not being used.
01g,17mar97,hdn added sysIntLock(), sysIntUnlock() for the system mode.
01f,25jun96,hdn added sysIntLevel() for windview.
01e,23may96,wlf doc: cleanup.
01d,14jun95,hdn renamed sysEndOfInt to sysIntEOI.
moved global function prototypes to sysLib.h.
01c,08aug94,hdn stopped toggling IRQ9 in enabling and disabling.
01b,22apr94,hdn made IRQ9 off in the initialization.
moved sysVectorIRQ0 to sysLib.c.
01a,05sep93,hdn written.
*/
/*
DESCRIPTION
This module implements the Intel 8259A PIC driver.
INCLUDE FILES: i8259a.h
*/
#include <drv/intrCtl/i8259a.h>
/* globals */
IMPORT UINT sysVectorIRQ0; /* vector for IRQ0 */
/* local */
char sysIntMask1; /* interrupt mask for PIC1 */
char sysIntMask2; /* interrupt mask for PIC2 */
/* forward static functions */
#if !defined (_WRS_SYS_INT_INIT_PIC_NOT_USED)
LOCAL void sysIntInitPIC (void);
/*******************************************************************************
*
* sysIntInitPIC - initialize the PIC
*
* This routine initializes the PIC.
*
* RETURNS: N/A
*
* ERRNO
*/
LOCAL void sysIntInitPIC (void)
{
/* initialize the PIC (Programmable Interrupt Controller) */
sysOutByte (PIC_port1 (PIC1_BASE_ADR),0x11); /* ICW1 */
sysOutByte (PIC_port2 (PIC1_BASE_ADR),sysVectorIRQ0); /* ICW2 */
sysOutByte (PIC_port2 (PIC1_BASE_ADR),0x04); /* ICW3 */
sysOutByte (PIC_port2 (PIC1_BASE_ADR),0x01); /* ICW4 */
sysOutByte (PIC_port1 (PIC2_BASE_ADR),0x11); /* ICW1 */
sysOutByte (PIC_port2 (PIC2_BASE_ADR),sysVectorIRQ0+8); /* ICW2 */
sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x02); /* ICW3 */
sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x01); /* ICW4 */
/* disable interrupts */
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),(_WRS_IOCHAR)0xfb);
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),(_WRS_IOCHAR)0xff);
}
#endif /* !defined (_WRS_SYS_INT_INIT_PIC_NOT_USED) */
#if !defined (_WRS_SYS_INT_EOI_NOT_USED)
LOCAL void sysIntEOI (void);
/*******************************************************************************
*
* sysIntEOI - send EOI(end of interrupt) signal.
*
* This routine is called at the end of the interrupt handler.
*
* RETURNS: N/A
*
* ERRNO
*/
LOCAL void sysIntEOI (void)
{
int oldLevel;
oldLevel = intLock ();
sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20);
sysOutByte (PIC_IACK (PIC2_BASE_ADR), 0x20);
intUnlock (oldLevel);
}
#endif /* !defined (_WRS_SYS_INT_EOI_NOT_USED) */
/*******************************************************************************
*
* sysIntDisablePIC - disable a PIC interrupt level
*
* This routine disables a specified PIC interrupt level.
*
* RETURNS: OK, always.
*
* SEE ALSO: sysIntEnablePIC()
*
* ERRNO
*/
STATUS sysIntDisablePIC
(
int intLevel /* interrupt level to disable */
)
{
if (intLevel < 8)
{
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
sysInByte (PIC_IMASK (PIC1_BASE_ADR)) | (1 << intLevel));
}
else
{
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
sysInByte (PIC_IMASK (PIC2_BASE_ADR)) | (1 << (intLevel - 8)));
}
return (OK);
}
/*******************************************************************************
*
* sysIntEnablePIC - enable a PIC interrupt level
*
* This routine enables a specified PIC interrupt level.
*
* RETURNS: OK, always.
*
* SEE ALSO: sysIntDisablePIC()
*
* ERRNO
*/
STATUS sysIntEnablePIC
(
int intLevel /* interrupt level to enable */
)
{
if (intLevel < 8)
{
sysOutByte (PIC_IMASK (PIC1_BASE_ADR),
sysInByte (PIC_IMASK (PIC1_BASE_ADR)) & ~(1 << intLevel));
}
else
{
sysOutByte (PIC_IMASK (PIC2_BASE_ADR),
sysInByte (PIC_IMASK (PIC2_BASE_ADR)) & ~(1 << (intLevel - 8)));
}
return (OK);
}
/*******************************************************************************
*
* sysIntLevel - Get interrupt level by reading Interrupt Service Register.
*
* This routine is called to get an interrupt level in service.
*
* RETURNS: 0 - 15
*
* ERRNO
*/
int sysIntLevel (void)
{
int inserviceReg;
int level;
int oldLevel;
int retry;
oldLevel = intLock ();
level = 0;
for (retry=0; retry < 1; retry ++)
{
sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);
inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));
for (level=0; level < 8; level++)
if ((inserviceReg & 1) && (level != 2))
goto sysIntLevelExit;
else
inserviceReg >>= 1;
sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b);
inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR));
for (level=8; level < 16; level++)
if (inserviceReg & 1)
goto sysIntLevelExit;
else
inserviceReg >>= 1;
}
sysIntLevelExit:
intUnlock (oldLevel);
return (level);
}
/*******************************************************************************
*
* sysIntLock - lock out all PIC interrupts
*
* This routine saves the mask and locks out all PIC interrupts.
* It should be called in the interrupt disable state(IF bit is 0).
*
* RETURNS: N/A
*
* SEE ALSO: sysIntUnlock()
*
* ERRNO
*/
VOID sysIntLock (void)
{
sysIntMask1 = sysInByte (PIC_IMASK (PIC1_BASE_ADR));
sysIntMask2 = sysInByte (PIC_IMASK (PIC2_BASE_ADR));
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), (_WRS_IOCHAR)0xff);
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), (_WRS_IOCHAR)0xff);
}
/*******************************************************************************
*
* sysIntUnlock - unlock the PIC interrupts
*
* This routine restores the mask and unlocks the PIC interrupts
* It should be called in the interrupt disable state(IF bit is 0).
*
* RETURNS: N/A
*
* SEE ALSO: sysIntLock()
*
* ERRNO
*/
VOID sysIntUnlock (void)
{
sysOutByte (PIC_IMASK (PIC1_BASE_ADR), sysIntMask1);
sysOutByte (PIC_IMASK (PIC2_BASE_ADR), sysIntMask2);
}
@@ -0,0 +1,691 @@
/* ioApicIntr.c - Intel IO APIC/xAPIC driver */
/*
* Copyright (c) 1997-1998, 2000-2002, 2004, 2006-2008 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use of this
* software may be licensed only pursuant to the terms of an applicable Wind
* River license agreement.
*/
/*
modification history
--------------------
01n,27aug08,jpb Renamed VSB header file
01m,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
for kernel configurations options set in vsb.
01l,26apr07,dlk PCI interrupt temporary workaround for SMP --
For VXBUS case, ioApicInit() allocates memory using
hwMemAlloc().
01k,09oct06,scm remove sysBp dependencey for SMP...
01j,26jul06,scm update for pentium/xeon support...
01i,18aug04,dmh parameter checking
01h,01apr04,dmh add support for multiple APICs
01g,08mar02,hdn updated ioApicInit(), added ioApicEnable()
removed redTable, added ioApicRedS/G(HTT (spr 73738)
01f,29nov01,hdn doc update for 5.5
01e,07nov01,hdn updated the interrupt delivery type setting
added new routine ioApicIrqMove ()
01d,26jun01,hdn added support for Pentium4 IO xAPIC
moved show routine to ioApicIntrShow.c
01c,17nov00,mks importing loApicBase and loApicId for successful compilation,
added redTablePtr and made redTableNumEnt global. SPR 35733.
01b,25mar98,hdn re-written.
01a,20jun97,sub written.
*/
/*
DESCRIPTION
This module is a driver for the IO APIC/xAPIC (Advanced Programmable
Interrupt Controller) for P6 (PentiumPro, II, III) family processors
and P7 (Pentium4) family processors. The IO APIC/xAPIC is included
in the Intel's system chip set, such as ICH2. Software intervention
may be required to enable the IO APIC/xAPIC in some chip sets.
The 8259A interrupt controller is intended for use in a uni-processor
system, IO APIC can be used in either a uni-processor or multi-processor
system. The IO APIC handles interrupts very differently than the 8259A.
Briefly, these differences are:
- Method of Interrupt Transmission. The IO APIC transmits interrupts
through a 3-wire bus and interrupts are handled without the need for
the processor to run an interrupt acknowledge cycle.
- Interrupt Priority. The priority of interrupts in the IO APIC is
independent of the interrupt number. For example, interrupt 10 can
be given a higher priority than interrupt 3.
- More Interrupts. The IO APIC supports a total of 24 interrupts.
The IO APIC unit consists of a set of interrupt input signals, a 24-entry
by 64-bit Interrupt Redirection Table, programmable registers, and a message
unit for sending and receiving APIC messages over the APIC bus or the
Front-Side (system) bus. IO devices inject interrupts into the system by
asserting one of the interrupt lines to the IO APIC. The IO APIC selects the
corresponding entry in the Redirection Table and uses the information in that
entry to format an interrupt request message. Each entry in the Redirection
Table can be individually programmed to indicate edge/level sensitive interrupt
signals, the interrupt vector and priority, the destination processor, and how
the processor is selected (statically and dynamically). The information in
the table is used to transmit a message to other APIC units (via the APIC bus
or the Front-Side (system) bus).
IO APIC is used in the Symmetric IO Mode (define SYMMETRIC_IO_MODE in the BSP).
The base address of IO APIC is determined in loApicInit() and stored in the
global variable ioApicBase and ioApicData. ioApicInit() initializes the IO
APIC with information stored in ioApicRed0_15 and ioApicRed16_23.
The ioApicRed0_15 is the default lower 32 bit value of the redirection table
entries for IRQ 0 to 15 that are edge triggered positive high, and
the ioApicRed16_23 is for IRQ 16 to 23 that are level triggered positive low.
ioApicRedSet() and ioApicRedGet() are used to access the redirection table.
ioApicEnable() enables the IO APIC or xAPIC. ioApicIrqSet() set the specific
IRQ to be delivered to the specific Local APIC.
This implementation doesn't support multiple IO APIC configuration.
INCLUDE FILES: loApic.h, ioApic.h
SEE ALSO: loApicIntr.c
*/
/* includes */
#include <vsbConfig.h>
#include "intLib.h"
#include "drv/intrCtl/loApic.h"
#include "drv/intrCtl/ioApic.h"
/* externs */
IMPORT UINT32 loApicBase; /* addr of Local APIC */
IMPORT UINT32 loApicId; /* local APIC Id */
IMPORT UINT32 sysProcessor; /* 0=386, 1=486, 2=P5, 4=P6, 5=P7 */
IMPORT INT8 excCallTbl []; /* table of Calls in excALib.s */
IMPORT INT32 sysCsInt; /* CS for interrupt */
IMPORT VOIDFUNCPTR intEoiGet; /* function used in intConnect() for B/EOI */
IMPORT UINT32 sysIntIdtType; /* IDT entry type */
#ifndef _WRS_CONFIG_SMP
IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
#else
IMPORT int sysCpuNumGet (); /* define in sysLib.c of BSP */
#endif
IMPORT void sysPciIoApicEnable(); /* enable/disable the IO APIC */
IMPORT void sysPciPirqEnable(); /* enable/disable the PCI PIRQ */
#ifdef INCLUDE_VXBUS
IMPORT char * hwMemAlloc (int reqSize);
#endif
/* globals */
const UINT32 ioApicRed0_15 = IOAPIC_EDGE | IOAPIC_HIGH | IOAPIC_FIXED;
const UINT32 ioApicRed16_23 = IOAPIC_LEVEL | IOAPIC_LOW | IOAPIC_FIXED;
UINT32 ioApicVersion[MAX_IOAPICS]; /* IO APIC version register per APIC */
UINT8 ioApicRedNum[MAX_IOAPICS]; /* IO APIC redirection table number per APIC */
UINT32 ioApicRedEntries = 24;
/* locals */
LOCAL UINT32 * ioApicIntTable;
/* forward declarations */
STATUS ioApicIrqMove (INT32 srcIrq, INT32 dstIrq); /* not published yet */
/*******************************************************************************
*
* ioApicInit - initialize the IO APIC or xAPIC
*
* This routine initializes the IO APIC or xAPIC.
*
*/
STATUS ioApicInit (void)
{
INT32 ix,ioApicId;
UINT32 ioApicBase,ioApicData;
UINT32 entries = 0;
/* enable the IOAPIC */
if (MAX_IOAPICS < NUM_IOAPICS)
return (ERROR);
#ifndef _WRS_CONFIG_SMP
if (sysBp)
#else
if (sysCpuNumGet() == 0)
#endif
ioApicEnable (TRUE);
for (ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
{
ioApicBase = LID_TO_BASE(ioApicId);
ioApicData = ioApicBase + IOAPIC_DATA;
/* get the IOAPIC version */
ioApicVersion[ioApicId] = ioApicGet (ioApicBase, ioApicData, IOAPIC_VERS);
/* get a number of redirection table entries */
ioApicRedNum[ioApicId] = ((ioApicVersion[ioApicId] & IOAPIC_MRE_MASK) >> 16) + 1;
}
for (ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
entries += ioApicRedNum[ioApicId];
ioApicRedEntries = entries;
/* allocate memory for saving the interrupt mask bit */
#if !defined (INCLUDE_VXBUS)
ioApicIntTable = (UINT32 *) memalign (_CACHE_ALIGN_SIZE, entries * sizeof (UINT32));
#else /* defined (INCLUDE_VXBUS) */
/* Note, hwMemAlloc() doesn't return on failure. */
ioApicIntTable = (UINT32 *)
hwMemAlloc (_CACHE_ALIGN_SIZE + entries * sizeof (UINT32));
ioApicIntTable = (UINT32 *)(((UINT32)ioApicIntTable + _CACHE_ALIGN_SIZE - 1) &
~(_CACHE_ALIGN_SIZE - 1));
#endif /* defined (INCLUDE_VXBUS) */
#ifndef _WRS_CONFIG_SMP
if (sysBp == FALSE)
#else
if (sysCpuNumGet() != 0)
#endif /* _WRS_CONFIG_SMP */
return (OK);
for (ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
{
int lastentry = 0;
ioApicBase = LID_TO_BASE(ioApicId);
ioApicData = ioApicBase + IOAPIC_DATA;
entries = ioApicRedNum[ioApicId];
/* set the IOAPIC bus arbitration ID */
ioApicSet (ioApicBase, ioApicData, IOAPIC_ID,
ioApicGet (ioApicBase, ioApicData, IOAPIC_ID));
/* set the int-delivery type to Front Side Bus, not APIC Serial Bus */
if (sysProcessor == X86CPU_PENTIUM4)
ioApicSet (ioApicBase, ioApicData, IOAPIC_BOOT, IOAPIC_DT_FS);
/* initialize the redirection table for the first ioapic with the default values */
if(ioApicId == 0)
{
for (ix = 0; ix < entries; ix++)
{
UINT32 lower32;
UINT32 upper32 = (loApicId << 24);
UINT32 vector = (IOAPIC_INT_MASK | IOAPIC_PHYSICAL | sysInumTbl[ix]);
if (ix < 16)
lower32 = (ioApicRed0_15 | vector);
else
lower32 = (ioApicRed16_23 | vector);
ioApicRedSet (ix, upper32, lower32, ioApicId);
}
}
else
{
for (ix = 0; ix < entries; ix++)
{
UINT32 lower32, vector;
UINT32 upper32 = (loApicId << 24);
if(ix < NUM_REDIRECTION_ENTRIES(ioApicId))
{
vector = (IOAPIC_INT_MASK | IOAPIC_PHYSICAL | sysInumTbl[ix + IRQ_OFFSET(ioApicId)]);
lower32 = (IOAPIC_INT_MASK | IOAPIC_PHYSICAL | ioApicRed16_23 | vector);
}
else
lower32 = IOAPIC_INT_MASK;
ioApicRedSet (IRQ_TO_BIRQ(ioApicId, ix), upper32, lower32, ioApicId);
}
}
lastentry += entries;
}
return (OK);
}
/*******************************************************************************
*
* ioApicEnable - enable or disable the IO xAPIC in ICHx
*
* This routine enables or disables the IO xAPIC in ICHx. If the parameter is
* TRUE, the IO xAPIC in ICHx is enabled and the default ISA IRQ routing
* information is saved in the table. If the parameter is FALSE, the IO xAPIC
* in ICHx is disabled.
*
* RETURNS: N/A
*/
void ioApicEnable
(
BOOL enable /* enable the IO xAPIC in ICHx */
)
{
/* enables or disables the IO APIC */
sysPciIoApicEnable (enable);
/* enables or disables the PIRQ direct handling */
sysPciPirqEnable (enable);
}
/*******************************************************************************
*
* ioApicIntEoi - send EOI (End Of Interrupt) signal to IO APIC
*
* This routine sends an EOI signal to the IO APIC's interrupting source.
*
* RETURNS: N/A
*/
LOCAL void ioApicIntEoi
(
INT32 irqNo /* INTIN number to send EOI */
)
{
UINT32 ioApicId;
#ifdef SYS_INT_DEBUG
extern UINT32 sysIntCount [];
sysIntCount [irqNo]++;
#endif /* SYS_INT_DEBUG */
for(ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
{
if (ioApicVersion[ioApicId] & IOAPIC_PRQ)
{
*(int *)(LID_TO_BASE(ioApicId) + IOAPIC_EOI) = INT_NUM_GET(irqNo);
#ifdef SYS_INT_DEBUG
/* do not log console interrupts */
if(irqNo != (devParas[CONSOLE_TTY].intLevel))
logMsg ("IRQ(%d), serviced by IOAPIC(%d), Vector(%x)\n",
irqNo, 0, INT_NUM_GET(irqNo), 4,5,6);
#endif
}
}
*(int *)(loApicBase + LOAPIC_EOI) = 0;
}
/*******************************************************************************
*
* ioApicIntEnable - enable a specified APIC interrupt input line
*
* This routine enables a specified APIC interrupt input line.
*
* RETURNS: OK or ERROR if the interrupt input line number is invalid
*
* SEE ALSO: ioApicIntDisable()
*
* ARGSUSED0
*/
STATUS ioApicIntEnable
(
INT32 irqNo /* INTIN number to enable */
)
{
UINT32 ioApicBase,ioApicData, ioApicId;
UINT32 lower32, upper32;
ioApicId = irqNo / 24;
ioApicBase = LID_TO_BASE(ioApicId);
ioApicData = ioApicBase + IOAPIC_DATA;
ioApicRedGet((INT32) (IRQ_TO_BIRQ(ioApicId, irqNo)), (INT32 *) &upper32,
(INT32 *) &lower32, (INT32) ioApicId);
upper32 = (loApicId << 24);
/* enable the interrupt */
return ioApicRedSet(IRQ_TO_BIRQ(ioApicId, irqNo), upper32, lower32 & ~IOAPIC_INT_MASK, ioApicId);
}
/*******************************************************************************
*
* ioApicIntDisable - disable a specified APIC interrupt input line
*
* This routine disables a specified APIC interrupt input line.
*
* RETURNS: OK or ERROR if the interrupt input line number is invalid
*
* SEE ALSO: ioApicIntEnable()
*
* ARGSUSED0
*/
LOCAL STATUS ioApicIntDisable
(
INT32 irqNo /* INTIN number to disable */
)
{
UINT32 ioApicBase,ioApicData, ioApicId;
UINT32 lower32, upper32;
ioApicId = irqNo / 24;
ioApicBase = LID_TO_BASE(ioApicId);
ioApicData = ioApicBase + IOAPIC_DATA;
ioApicRedGet((INT32) (IRQ_TO_BIRQ(ioApicId, irqNo)), (INT32 *) &upper32,
(INT32 *) &lower32, (INT32) ioApicId);
/* disable the interrupt */
return ioApicRedSet(IRQ_TO_BIRQ(ioApicId, irqNo), upper32, lower32 | IOAPIC_INT_MASK, ioApicId);
}
/*******************************************************************************
*
* ioApicIntLock - lock out all IO APIC interrupts
*
* This routine saves the mask and locks out all IO APIC interrupts.
* It should be called in the interrupt disable state(IF bit is 0).
*
* RETURNS: N/A
*
* SEE ALSO: ioApicIntUnlock()
*
* ARGSUSED0
*/
LOCAL VOID ioApicIntLock (void)
{
INT32 ix;
INT32 upper32;
INT32 lower32;
INT32 ioApicId = 0;
for (ix = 0; ix < 24; ix++)
{
ioApicRedGet (IRQ_TO_BIRQ(ioApicId, ix), &upper32, &lower32, ioApicId);
/* lock if the destination is my Local APIC and unlocked */
if ((((upper32 & IOAPIC_DESTINATION) >> 24) == loApicId) &&
((lower32 & IOAPIC_INT_MASK) == 0))
{
ioApicRedSet(IRQ_TO_BIRQ(ioApicId, ix), upper32, lower32 | IOAPIC_INT_MASK, ioApicId);
ioApicIntTable[ix] = lower32; /* save the old state */
}
}
}
/*******************************************************************************
*
* ioApicIntUnlock - unlock the IO APIC interrupts
*
* This routine restores the mask and unlocks the IO APIC interrupts
* It should be called in the interrupt disable state(IF bit is 0).
*
* RETURNS: N/A
*
* SEE ALSO: ioApicIntLock()
*
* ARGSUSED0
*/
LOCAL VOID ioApicIntUnlock (void)
{
INT32 ix;
INT32 upper32;
INT32 lower32;
INT32 ioApicId = 0;
for (ix = 0; ix < 24; ix++)
{
ioApicRedGet (IRQ_TO_BIRQ(ioApicId, ix), &upper32, &lower32, ioApicId);
/* unlock if the destination is my Local APIC and unlocked */
if ((((upper32 & IOAPIC_DESTINATION) >> 24) == loApicId)
&& ((ioApicIntTable[ix] & IOAPIC_INT_MASK) == 0))
{
ioApicRedSet(IRQ_TO_BIRQ(ioApicId, ix), upper32, lower32 & ~IOAPIC_INT_MASK, ioApicId);
}
}
}
/*******************************************************************************
*
* ioApicGet - get a value from the IO APIC register.
*
* This routine gets a value from the IO APIC register.
*
* RETURNS: A value of the IO APIC register.
*/
INT32 ioApicGet
(
UINT32 index, /* IO register select (index) */
UINT32 data, /* IO window (data) */
INT32 offset /* offset to the register */
)
{
INT32 value;
INT32 oldLevel;
oldLevel = intLock (); /* LOCK INTERRUPT */
*(char *)index = (char)offset; /* select the register */
value = *(int *)data; /* must be a 32bit read */
intUnlock (oldLevel); /* UNLOCK */
return (value);
}
/*******************************************************************************
*
* ioApicSet - set a value into the IO APIC register.
*
* This routine sets a value into the IO APIC register.
*
* RETURNS: N/A
*/
void ioApicSet
(
UINT32 index, /* IO register select (index) */
UINT32 data, /* IO window (data) */
INT32 offset, /* offset to the register */
INT32 value /* value to set the register */
)
{
INT32 oldLevel;
oldLevel = intLock (); /* LOCK INTERRUPT */
*(char *)index = (char)offset; /* select the register */
*(int *)data = value; /* must be a 32bit write */
intUnlock (oldLevel); /* UNLOCK */
}
/*******************************************************************************
*
* ioApicRedGet - get a specified entry in the Redirection Table
*
* This routine gets a specified entry in the Redirection Table
*
* RETURNS: OK, or ERROR if intNum is out of range
*/
STATUS ioApicRedGet
(
INT32 irq, /* index of the table */
INT32 * pUpper32, /* upper 32 bit (MS LONG) */
INT32 * pLower32, /* lower 32 bit (LS LONG) */
INT32 ioApicId
)
{
UINT32 ioApicBase,ioApicData;
INT32 offset;
if (irq >= ioApicRedNum[ioApicId])
return (ERROR);
offset = IOAPIC_REDTBL + (irq << 1);
ioApicBase = LID_TO_BASE(ioApicId);
ioApicData = ioApicBase + IOAPIC_DATA;
*pUpper32 = ioApicGet (ioApicBase, ioApicData, offset + 1);
*pLower32 = ioApicGet (ioApicBase, ioApicData, offset);
return (OK);
}
/*******************************************************************************
*
* ioApicRedSet - set a specified entry in the Redirection Table
*
* This routine sets a specified entry in the Redirection Table
*
* RETURNS: OK, or ERROR if intNum is out of range
*/
STATUS ioApicRedSet
(
INT32 irq, /* index of the table */
INT32 upper32, /* upper 32 bit (MS LONG) */
INT32 lower32, /* lower 32 bit (LS LONG) */
INT32 ioApicId
)
{
UINT32 ioApicBase, ioApicData;
INT32 offset;
if (irq >= ioApicRedNum[ioApicId])
return (ERROR);
ioApicBase = LID_TO_BASE(ioApicId);
ioApicData = ioApicBase + IOAPIC_DATA;
offset = IOAPIC_REDTBL + (irq << 1);
ioApicSet (ioApicBase, ioApicData, offset + 1, upper32);
ioApicSet (ioApicBase, ioApicData, offset, lower32);
return (OK);
}
/*******************************************************************************
*
* ioApicIrqMove - move interrupt handler from source IRQ to destination IRQ
*
* This routine moves the interrupt handler from the source IRQ to the
* destination IRQ. If the source IRQ's interrupt handler is the default
* handler, it just returns. Otherwise it is moved and the destination IRQ's
* vector table entry will be overridden. This routine is for the chipset
* that have programmable IRQ capability. This routine should be called at
* the initialization time, otherwise there are no guarantee for losing
* interrupts. The polarity and the trigger mode of the IRQ is not changed.
*
* RETURNS: OK, or ERROR if the source intHandler is the default handler.
*/
STATUS ioApicIrqMove
(
INT32 srcIrq, /* source IRQ moving from */
INT32 dstIrq /* destination IRQ moving to */
)
{
FUNCPTR intHandler; /* interrupt handler */
INT32 idtType; /* IDT type */
INT32 selector; /* code selector */
INT32 srcInum = INT_NUM_GET (srcIrq);
INT32 dstInum = INT_NUM_GET (dstIrq);
INT8 * pCode; /* pointer to intConnect code */
INT32 oldLevel;
/* lock interrupts */
oldLevel = intLock (); /* LOCK INTERRUPTS */
ioApicIntDisable (srcIrq);
ioApicIntDisable (dstIrq);
/* get the info from the source IRQ vector table entry */
intVecGet2 ((FUNCPTR *)INUM_TO_IVEC (srcInum), &intHandler,
&idtType, &selector);
/* return if the intHandler is the default handler */
if (intHandler == (FUNCPTR)&excCallTbl[srcInum * 5])
return (ERROR);
/* set the info to the destination IRQ vector table entry */
intVecSet2 ((FUNCPTR *)INUM_TO_IVEC (dstInum), intHandler,
idtType, selector);
/* update the IRQ (parameter of EOI routine) in the intConnect code */
if (intEoiGet != NULL)
{
pCode = (INT8 *)intHandler;
*(INT32 *)(pCode + ICC_EOI_PARAM) = dstIrq;
}
/* set the default interrupt handler to the source IRQ */
intVecSet2 ((FUNCPTR *)INUM_TO_IVEC (srcInum),
(FUNCPTR)&excCallTbl[srcInum * 5],
sysIntIdtType, sysCsInt);
/* unlock interrupts */
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
ioApicIntEnable (dstIrq);
return (OK);
}
/*******************************************************************************
*
* ioApicIrqSet - set the Local APIC ID of the specified IRQ
*
* This routine sets the Local APIC ID of the specified IRQ in the IO APIC
* Redirection Table.
*
* RETURNS: OK, or ERROR if the IRQ is out of bound
*/
STATUS ioApicIrqSet
(
INT32 irq, /* IRQ */
INT32 destApicId, /* Local APIC ID */
INT32 sourceApicId
)
{
INT32 upper32;
INT32 oldLevel;
UINT32 ioApicBase,ioApicData;
INT32 offset = IOAPIC_REDTBL + (irq * 2);
ioApicBase = LID_TO_BASE(sourceApicId);
ioApicData = ioApicBase + IOAPIC_DATA;
if (irq >= ioApicRedNum[destApicId])
return (ERROR);
/* lock interrupts */
oldLevel = intLock (); /* LOCK INTERRUPTS */
ioApicIntDisable (irq);
/* set the loApicId */
upper32 = ioApicGet (ioApicBase, ioApicData, offset + 1);
upper32 = (upper32 & ~IOAPIC_DESTINATION) | (destApicId << 24);
ioApicSet (ioApicBase, ioApicData, offset + 1, upper32);
/* unlock interrupts */
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
ioApicIntEnable (irq);
return (OK);
}
@@ -0,0 +1,87 @@
/* ioApicIntrShow.c - Intel IO APIC/xAPIC driver show routines */
/* Copyright 1984-2002 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01d,26jul06,scm update for pentium/xeon support...
01c,01apr04,dmh add support for multiple APICs
01b,08mar02,hdn added the description
01a,25jun01,hdn extracted from 01d version of ioApicIntr.c
*/
/*
DESCRIPTION
This module is a show routine for the IO APIC/xAPIC (Advanced
Programmable Interrupt Controller) for P6 (PentiumPro, II, III)
family processors and P7 (Pentium4) family processors.
ioApicShow() shows content of the IO APIC registers.
INCLUDE FILES: loApic.h, ioApic.h
SEE ALSO: ioApicIntr.c
*/
/* includes */
#include "drv/intrCtl/loApic.h"
#include "drv/intrCtl/ioApic.h"
/* externs */
/* globals */
/* locals */
/* forward declarations */
/*******************************************************************************
*
* ioApicShow - show IO APIC registers
*
* This routine shows IO APIC registers
*
* RETURNS: N/A
*/
void ioApicShow (void)
{
int ix,id;
int version;
UINT32 ioApicBase,ioApicData;
for(id = 0; id < NUM_IOAPICS; id++)
{
ioApicBase = LID_TO_BASE(id);
ioApicData = ioApicBase + IOAPIC_DATA;
printf ("IOAPIC_ID = 0x%08x\n",
ioApicGet (ioApicBase, ioApicData, IOAPIC_ID));
version = ioApicGet (ioApicBase, ioApicData, IOAPIC_VERS);
printf ("IOAPIC_VER = 0x%08x\n", version);
printf ("IOAPIC_ARB = 0x%08x\n",
ioApicGet (ioApicBase, ioApicData, IOAPIC_ARB));
if (ioApicVersion[id] & IOAPIC_PRQ) /* use PRQ bit XXX */
printf ("IOAPIC_BOOT = 0x%08x\n",
ioApicGet (ioApicBase, ioApicData, IOAPIC_BOOT));
for (ix = 0; ix <= ((version & IOAPIC_MRE_MASK) >> 16); ix++)
{
printf ("IOAPIC_TBL%02d = 0x%08x ", ix,
ioApicGet (ioApicBase, ioApicData, IOAPIC_REDTBL + ix * 2 + 1));
printf ("%08x\n",
ioApicGet (ioApicBase, ioApicData, IOAPIC_REDTBL + ix * 2));
}
}
}
@@ -0,0 +1,493 @@
/* ixp400IntrCtl.c - interrupt controller driver for the ixp400 */
/*
Copyright (c) 2002, 2004, 2005 Wind River Systems, Inc. All rights reserved.
Certain portions of these files may be copyright (c) 2002-2004 Intel
Corporation.
*/
/*
modification history
--------------------
01d,23jun05,m_h SPR 109992 ixp400IntLvlChg while intLock
01c,28jan05,pai Unconditionally compile for ixp465.
01b,20dec04,pai Updated copyright notice.
01a,05jun02,jb initial version...
*/
/*
DESCRIPTION
This module implements the Ixp400 interrupt controller driver.
The Ixp400 interrupt controller is a simple, generic interrupt controller
described in full Ixp400 Data Book [Reference[]]. The
interrupt controller has status and request registers, separate enable
and disable registers and supports level-sensitive interrupts. This
library provides the routines to manage interrupts multiplexed by the
Ixp400 interrupt controller.
The Ixp400 interrupt controller has a number of registers. Those used by
this driver are described below under the symbolic names used herein.
IXP400_ICMR (write): this is the "Enable Set" register. When this register is
written, each data bit that is set (1) causes the corresponding
interrupt to be enabled. Bits that are clear (0) have no effect.
IXP400_ICIP (read): this is the "Interrupt Request" register.
When this register is read, each data bit that is set (1) indicates an
interrupt source that is both active and enabled i.e. can interrupt the
processor.
The number of interrupts supported by the device i.e. the number of
bits in the IXP400_ICIP register, is specified by
IXP400_INT_NUM_LEVELS.
We assume that config.h or <bsp>.h has defined the addresses of the
controller chips registers: IXP400_ICMR,
IXP400_ICIP and also the driver constant IXP400_INT_NUM_LEVELS.
This driver assumes that the chip is memory-mapped and does direct
memory accesses to the registers which are assumed to be 32 bits wide.
If a different access method is needed, the BSP can redefine the macros
IXP400_INT_REG_READ(addr,result) and IXP400_INT_REG_WRITE(addr,data).
This driver assumes that interrupt vector numbers are calculated and
not the result of a special cycle on the bus. Vector numbers are
generated by adding the current interrupt level number to
AMBA_INT_VEC_BASE to generate a vector number which the architecture
level will use to invoke the proper handling routine. If a different
mapping scheme, or a special hardware routine is needed, then the BSP
should redefine the macro IXP400_INT_LVL_VEC_MAP(level,vector) to
override the version defined in this file.
Priorities
==========
The order of interrupt level priority is undefined at the architecture
level. In this driver, level 0 is highest and and indicates that all
levels are disabled; level <IXP400_INT_NUM_LEVELS> is the lowest and
indicates that all levels are enabled.
By default, this driver implements a least-significant bit first
interrupt priority scheme (this is compatible with earlier versions of
this driver) which requires a definition of ambaIntLvlMask (see above).
Note: The IXP400 interrupt controller provides a mechanism to reorder the
priority order of the top 8 interrupts sources. The IXP400_ICHR may
be programmed to change the default behaviour. To change the default
priority IXP400_ICHR_INIT_VALUE should be redefined.
The BSP will initialize this driver in sysHwInit2(), after initializing
the main interrupt library, usually intLibInit(). The initialization
routine, ixp400IntDevInit() will setup the interrupt controller device,
it will mask off all individual interrupt sources and then set the
interrupt level to enable all interrupts. See ixp400IntDevInit for more
information.
All of the functions in this library are global. This allows them to
be used by the BSP if it is necessary to create wrapper routines or to
incorporate several drivers together as one.
.SH INCLUDE FILES:
drv/intrCtl/ixp400IntrCtl.h
SEE ALSO:
.I "Ixp400 Data Sheet,"
*/
#include "vxWorks.h"
#include "config.h"
#include "ixp400.h"
#include "drv/intrCtl/ixp400IntrCtl.h"
#include "intLib.h"
IMPORT int ffsLsb (UINT32);
/* Defines from config.h, or <bsp>.h */
#if !defined (IXP400_ICIP) || !defined (IXP400_ICMR) || \
!defined (IXP400_INT_NUM_LEVELS)
#error missing IXP400 interrupt definitions
#endif
#define IXP400_INT_VEC_BASE (0x0)
/* Convert level number to vector number */
#ifndef IXP400_INT_LVL_VEC_MAP
#define IXP400_INT_LVL_VEC_MAP(level, vector) \
((vector) = ((level) + IXP400_INT_VEC_BASE))
#endif /* IXP400_INT_LVL_VEC_MAP */
/* Convert pending register value, to a level number */
#ifndef IXP400_INT_PEND_LVL_MAP
#define IXP400_INT_PEND_LVL_MAP(pendReg, level) \
((level) = (pendReg))
#endif /* IXP400_INT_PEND_LVL_MAP */
/* driver constants */
#define IXP400_INT_ALL_ENABLED (IXP400_INT_NUM_LEVELS)
#define IXP400_INT_ALL_DISABLED 0
#define IXP400_MASK_ALL_INTERRUPTS() IXP400_REG_INT_WRITE (IXP400_ICMR,0x00000000);\
IXP400_REG_INT_WRITE (IXP400_ICMR_UPPER,0x00000000);
/* Local data */
/* Current interrupt level setting (ixp400IntLvlChg). */
LOCAL UINT32 ixp400IntLvlCurrent = IXP400_INT_ALL_DISABLED; /* all levels disabled*/
/*
* A mask word. Bits are set in this word when a specific level
* is enabled. It is used to mask off individual levels that have
* not been explicitly enabled.
*/
LOCAL UINT32 ixp400IntLvlEnabled;
LOCAL UINT32 ixp400IntLvlEnabledUpper;
/* use this table for INT 0-31*/
LOCAL UINT32 ixp400IntLvlMask [IXP400_INT_NUM_LEVELS_LOWER + 1] = /* int lvl mask */
{
0x0000, /* level 0, all disabled */
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
/* level 1-32 all enabled */
};
LOCAL UINT32 ixp400IntLvlMaskUpper[(IXP400_INT_NUM_LEVELS-IXP400_INT_NUM_LEVELS_LOWER) + 1] = /* int lvl mask */
/* use this table for INT 32-63*/
{
0x0000, /* 33-64 all disabled */
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
/* level 33-64 all enabled */
};
#if IXP400_INT_NUM_LEVELS != 64
#error ixp400IntLvlMask is wrong size for number of levels
#endif
/* forward declarations */
STATUS ixp400IntLvlVecChk (int*, int*);
STATUS ixp400IntLvlVecAck (int, int);
int ixp400IntLvlChg (int);
STATUS ixp400IntLvlEnable (int);
STATUS ixp400IntLvlDisable (int);
/*******************************************************************************
*
* ixp400IntDevInit - initialize the interrupt controller
*
* This routine will initialize the interrupt controller device, disabling all
* interrupt sources. It will also connect the device driver specific routines
* into the architecture level hooks. If the BSP needs to create a wrapper
* routine around any of the arhitecture level routines, it should install the
* pointer to the wrapper routine after calling this routine.
*
* RETURNS: OK
*/
STATUS ixp400IntDevInit (void)
{
/* install the driver routines in the architecture hooks */
sysIntLvlVecChkRtn = ixp400IntLvlVecChk;
sysIntLvlVecAckRtn = ixp400IntLvlVecAck;
sysIntLvlChgRtn = ixp400IntLvlChg;
sysIntLvlEnableRtn = ixp400IntLvlEnable;
sysIntLvlDisableRtn = ixp400IntLvlDisable;
ixp400IntLvlEnabled = 0; /* all sources disabled 0-31*/
ixp400IntLvlEnabledUpper = 0; /* all sources disabled 32-63*/
/*
* Set default interrupty priority.
*/
IXP400_REG_INT_WRITE (IXP400_ICHR, IXP400_ICHR_INIT_VALUE);
ixp400IntLvlChg (IXP400_INT_ALL_ENABLED); /* enable all levels */
return OK;
}
/*******************************************************************************
*
* ixp400IntLvlVecChk - check for and return any pending interrupts
*
* This routine interrogates the hardware to determine the highest priority
* interrupt pending. It returns the vector associated with that interrupt, and
* also the interrupt priority level prior to the interrupt (not the
* level of the interrupt). The current interrupt priority level is then
* raised to the level of the current interrupt so that only higher priority
* interrupts will be accepted until this interrupt is finished.
*
* This routine must be called with CPU interrupts disabled.
*
* The return value ERROR indicates that no pending interrupt was found and
* that the level and vector values were not returned.
*
* RETURNS: OK or ERROR if no interrupt is pending.
*
*
* Note:
* This routine does not employ the INTR_IRQ_ENC_ST (aka register IXP400_ICIH) which encodes
* the highest priority interrupt (incremented by 1) since the interrupt priority regsiter
* INTR_PRTY (aka IXP400_ICHR) is programmed to its default priorities
*/
STATUS ixp400IntLvlVecChk
(
int* pLevel, /* ptr to receive old interrupt level */
int* pVector /* ptr to receive current interrupt vector */
)
{
int newLevel;
int newLevelTmp;
UINT32 isr;
UINT32 isrUpper = 0;
/* Read pending interrupt register and mask undefined bits */
isr = IXP400_REG_INT_READ (IXP400_ICIP);
isrUpper = IXP400_REG_INT_READ (IXP400_ICIP_UPPER);
/* If no interrupt is pending, return ERROR */
if ((0==isr) && (0==isrUpper))
return ERROR;
/* find first bit set in ISR, starting from lowest-numbered bit */
if (0 == (newLevel = ffsLsb (isr)))
{
if (0 == (newLevel = ffsLsb (isrUpper)))
{return ERROR;}
else
{
/* newlevel is 1 to 32, add lower level offset */
newLevel += IXP400_INT_NUM_LEVELS_LOWER;
}
}
--newLevel; /* ffsLsb returns numbers from 1, not 0 */
/* map the interrupting device to an interrupt level number */
IXP400_INT_PEND_LVL_MAP (newLevel, newLevelTmp);
/* change to new interrupt level, returning previous level to caller */
*pLevel = ixp400IntLvlChg (newLevelTmp);
/* fetch, or compute the interrupt vector number */
IXP400_INT_LVL_VEC_MAP (newLevelTmp, *pVector);
return OK;
}
/*******************************************************************************
*
* ixp400IntLvlVecAck - acknowledge the current interrupt
*
* Acknowledge the current interrupt cycle. The level and vector values are
* those generated during the ixp400IntLvlVecChk() routine for this interrupt
* cycle. The basic action is to reset the current interrupt and return
* the interrupt level to its previous setting. Note that the Ixp400 interrupt
* controller does not need an acknowledge cycle.
*
* RETURNS: OK or ERROR if a hardware fault is detected.
*/
STATUS ixp400IntLvlVecAck
(
int level, /* old interrupt level to be restored */
int vector /* current interrupt vector, if needed */
)
{
/* restore the previous interrupt level */
ixp400IntLvlChg (level);
return OK;
}
/*******************************************************************************
*
* ixp400IntLvlChg - change the interrupt level value
*
* This routine implements the overall interrupt setting. All levels
* up to and including the specifed level are disabled. All levels above
* the specified level will be enabled, but only if they were specifically
* enabled by the ixp400IntLvlEnable() routine.
*
* The specific priority level IXP400_INT_NUM_LEVELS is valid and represents
* all levels enabled.
*
* Passing a value of -1 will reset the current interrupt level mask.
*
* RETURNS: Previous interrupt level.
*/
int ixp400IntLvlChg
(
int level /* new interrupt level */
)
{
int oldLevel;
oldLevel = ixp400IntLvlCurrent;
if (level >= 0 &&
level <= IXP400_INT_NUM_LEVELS)
{
/* change current interrupt level */
ixp400IntLvlCurrent = level;
}
if (ixp400IntLvlCurrent >= IXP400_INT_NUM_LEVELS_LOWER)
{
/* Activate all the enabled interrupts for INT 0-31*/
IXP400_REG_INT_WRITE (IXP400_ICMR,
(ixp400IntLvlMask[IXP400_INT_NUM_LEVELS_LOWER] & ixp400IntLvlEnabled));
/* Activate the enabled interrupts for INTR 31-63 */
IXP400_REG_INT_WRITE (IXP400_ICMR_UPPER,
(ixp400IntLvlMaskUpper[ixp400IntLvlCurrent-IXP400_INT_NUM_LEVELS_LOWER] & ixp400IntLvlEnabledUpper));
}
else
{
/* Activate the enabled interrupts for INT 0-31 */
IXP400_REG_INT_WRITE (IXP400_ICMR,
(ixp400IntLvlMask[ixp400IntLvlCurrent] & ixp400IntLvlEnabled));
/* disable all interrupts for INTR 31-63 */
IXP400_REG_INT_WRITE (IXP400_ICMR_UPPER, ixp400IntLvlMaskUpper[0]);
}
return oldLevel;
}
/*******************************************************************************
*
* ixp400IntLvlEnable - enable a single interrupt level
*
* Enable a specific interrupt level. The enabled level will be allowed
* to generate an interrupt when the overall interrupt level is set to
* enable interrupts of this priority (as configured by ixp400IntLvlPriMap,
* if appropriate). Without being enabled, the interrupt is blocked
* regardless of the overall interrupt level setting.
*
* RETURNS: OK or ERROR if the specified level cannot be enabled.
*/
STATUS ixp400IntLvlEnable
(
int level /* level to be enabled */
)
{
int key;
if (level < 0 ||
level >= IXP400_INT_NUM_LEVELS)
return ERROR;
/* set bit in enable mask */
key = intLock ();
if (level >=IXP400_INT_NUM_LEVELS_LOWER)
{
ixp400IntLvlEnabledUpper |= (1 << (level-IXP400_INT_NUM_LEVELS_LOWER));
}
else
{
ixp400IntLvlEnabled |= (1 << level);
}
ixp400IntLvlChg (-1); /* reset current mask */
intUnlock (key);
return OK;
}
/*******************************************************************************
*
* ixp400IntLvlDisable - disable a single interrupt level
*
* Disable a specific interrupt level. The disabled level is prevented
* from generating an interrupt even if the overall interrupt level is
* set to enable interrupts of this priority.
*
* RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
*/
STATUS ixp400IntLvlDisable
(
int level /* level to be disabled */
)
{
int key;
if (level < 0 ||
level >= IXP400_INT_NUM_LEVELS)
return ERROR;
/* clear bit in enable mask */
key = intLock ();
if (level >=IXP400_INT_NUM_LEVELS_LOWER)
{
ixp400IntLvlEnabledUpper &=
~(1 << (level-IXP400_INT_NUM_LEVELS_LOWER));
}
else
{
ixp400IntLvlEnabled &= ~(1 << level);
}
ixp400IntLvlChg (-1); /* reset current mask */
intUnlock (key);
return OK;
}
@@ -0,0 +1,561 @@
/* loApicIntr.c - Intel Pentium[234] Local APIC/xAPIC driver */
/*
* Copyright 1984-2008 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01p,27aug08,jpb Renamed VSB header file
01o,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
for kernel configurations options set in vsb.
01n,15mar07,scm correct mask in loApicIpi...
01m,07dec06,scm smp:adjust loApicIpi for shorthand support...
01l,15nov06,scm adjust loApicIpi for shortHand delivery...
01k,13oct06,scm AP work...
01j,09oct06,scm remove sysBp dependencey for SMP...
01i,06sep06,scm debug for SMP...
01h,26jul06,scm update for pentium/xeon support...
01g,01apr04,dmh add support for multiple APICs
01f,15may02,hdn changed apicId 8 bit to 16 bit, added DBG_MSG.
added Error Status Register checking
01e,08mar02,hdn updated loApicInit() and loApicIpi()
added loApicEnable() for HTT (spr 73738)
01d,29nov01,hdn doc update for 5.5
01c,21jun01,hdn added support for Pentium4 Local xAPIC
moved show routines to loApicIntrShow.c
01b,25mar98,hdn re-written.
01a,20jun97,sub written.
*/
/*
DESCRIPTION
This module is a driver for the local APIC/xAPIC (Advanced Programmable
Interrupt Controller) in P6 (PentiumPro, II, III) family processors
and P7 (Pentium4) family processors. The local APIC/xAPIC is included
in selected P6 (PentiumPro, II, III) and P7 (Pentium4) family processors.
Beginning with the P6 family processors, the presence or absence of an
on-chip local APIC can be detected using the CPUID instruction. When the
CPUID instruction is executed, bit 9 of the feature flags returned in the
EDX register indicates the presence (set) or absence (clear) of an on-chip
local APIC.
The local APIC performs two main functions for the processor:
- It processes local external interrupts that the processor receives at its
interrupt pins and local internal interrupts that software generates.
- In multiple-processor systems, it communicates with an external IO APIC
chip. The external IO APIC receives external interrupt events from the
system and interprocessor interrupts from the processors on the system bus
and distributes them to the processors on the system bus. The IO APIC is
part of Intel's system chip set.
The local APIC controls the dispatching of interrupts (to its associated
processor) that it receives either locally or from the IO APIC. It provides
facilities for queuing, nesting and masking of interrupts. It handles the
interrupt delivery protocol with its local processor and accesses to APIC
registers, and also manages interprocessor interrupts and remote APIC register
reads. A timer on the local APIC allows local generation of interrupts, and
local interrupt pins permit local reception of processor-specific interrupts.
The local APIC can be disabled and used in conjunction with a standard 8259A
style interrupt controller. Disabling the local APIC can be done in hardware
for the Pentium processors or in software for the P6 and P7 (Pentium4) family
processors.
The local APIC in the Pentium4 processors (called the xAPIC) is an extension
of the local APIC found in the P6 family processors. The primary difference
between the APIC architecture and xAPIC architecture is that with Pentium4
processors, the local xAPICs and IO xAPIC communicate with one another through
the processors system bus; whereas, with the P6 family processors, communication
between the local APICs and the IO APIC is handled through a dedicated 3-wire
APIC bus. Also, some of the architectural features of the local APIC have been
extended and/or modified in the local xAPIC.
The base address of the local APIC and IO APIC is taken from the MP configuration
table (see Intel MP Specification Version 1.4) or the IA32_APIC_BASE MSR.
It uses LOAPIC_BASE and IOAPIC_INDEX_BASE defined in the BSP, if it is not able
to find the addresses. This driver contains three routines for use. They are:
loApicInit() initializes the Local APIC for the interrupt mode chosen.
loApicEnable() enables or disables the Local APIC.
loApicIpi() delivers the inter processor interrupt to the specified local APIC.
Local APIC is used in the Virtual Wire Mode (define VIRTUAL_WIRE_MODE in the
BSP) and the Symmetric IO Mode (define SYMMETRIC_IO_MODE in the BSP), but not
in the PIC Mode which is the default interrupt mode and uses 8259A PIC.
Virtual Wire Mode is one of three interrupt modes defined by the MP
specification. In this mode, interrupts are generated by the 8259A equivalent
PICs, but delivered to the Boot Strap Processor by the local APIC that is
programmed to act as a "virtual Wire"; that is, the local APIC is logically
indistinguishable from a hardware connection. This is a uniprocessor
compatibility mode.
Symmetric IO Mode is one of three interrupt modes defined by the MP
specification. In this mode, the local and IO APICs are fully functional,
and interrupts are generated and delivered to the processors by the APICs.
Any interrupt can be delivered to any processor. This is the only
multiprocessor interrupt mode.
The local and IO APICs support interrupts in the range of 32 to 255.
Interrupt priority is implied by its vector, according to the following
relationship: "priority = vector / 16".
Here the quotient is rounded down to the nearest integer value to determine
the priority, with 1 being the lowest and 15 is the highest. Because vectors
0 through 31 are reserved for exclusive use by the processor, the priority of
user defined interrupts range from 2 to 15. A value of 15 in the Interrupt
Class field of the Task Priority Register (TPR) will mask off all interrupts,
which require interrupt service.
The P6 family processor's local APIC includes an in-service entry and a holding
entry for each priority level. To avoid losing interrupts, software should
allocate no more than 2 interrupt vectors per priority. The Pentium4 processor
expands this support of all acceptance of two interrupts per vector rather than
per priority level.
INCLUDE FILES: loApic.h
*/
/* includes */
#include <vsbConfig.h>
#include "drv/intrCtl/loApic.h"
/* defines */
#undef LOAPIC_DBG
#ifdef LOAPIC_DBG
# define LOAPIC_DBG_MSG(STR,VALUE) logMsg(STR,VALUE,0,0,0,0,0);
#else
# define LOAPIC_DBG_MSG(STR,VALUE)
#endif /* IPI_DEBUG */
/* externs */
IMPORT CPUID sysCpuId; /* CPUID structure */
IMPORT UINT sysProcessor; /* CPU family */
#ifndef _WRS_CONFIG_SMP
IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
#endif /* !_WRS_CONFIG_SMP */
/* globals */
UINT32 loApicBase = LOAPIC_BASE; /* def Local APIC addr */
UINT32 loApicId; /* local APIC Id */
UINT32 loApicVersion; /* local APIC Version */
UINT32 loApicMaxLvt; /* local APIC Max LVT */
UINT32 loApicBusy = 0; /* counter for not sending IPI */
/* locals */
LOCAL UINT32 sysIntMaskLocalApic = 0;
LOCAL UINT32 loApicOldSvr = 0; /* original SVR */
LOCAL UINT32 loApicOldLint0 = 0; /* original LINT0 */
LOCAL UINT32 loApicOldLint1 = 0; /* original LINT1 */
/* forward declarations */
LOCAL void loApicIntEoi (INT32 irq);
#ifdef _WRS_CONFIG_SMP
IMPORT int sysCpuNumGet (); /* define in sysLib.c of BSP */
#endif /* _WRS_CONFIG_SMP */
/*******************************************************************************
*
* loApicInit - initialize the Local APIC or xAPIC
*
* This routine initializes Local APIC or xAPIC.
*
* RETURNS: N/A
*
*/
void loApicInit (void)
{
UINT32 apicBase[2];
/* override loApicBase, sysBp from MSR if available */
if (sysCpuId.featuresEdx & CPUID_APIC)
{
pentiumMsrGet (IA32_APIC_BASE, (long long int *)&apicBase);
loApicBase = apicBase[0] & LOAPIC_BASE_MASK; /* override */
#ifndef _WRS_CONFIG_SMP
sysBp = apicBase[0] & LOAPIC_BSP ? TRUE : FALSE; /* override */
#endif /* !_WRS_CONFIG_SMP */
/* enable the Local APIC explicitly */
apicBase[0] |= LOAPIC_GLOBAL_ENABLE; /* set E(nable) bit */
pentiumMsrSet (IA32_APIC_BASE, (long long int *)&apicBase);
}
/* remember the original state : SVR, LINT0, LINT1 for now */
loApicOldSvr = *(int *)(loApicBase + LOAPIC_SVR);
loApicOldLint0 = *(int *)(loApicBase + LOAPIC_LINT0);
loApicOldLint1 = *(int *)(loApicBase + LOAPIC_LINT1);
/* enable the Local APIC */
loApicEnable (TRUE);
*(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_FOCUS_DISABLE |
INT_NUM_LOAPIC_SPURIOUS;
/* get the Local APIC ID from Local APIC ID register */
loApicId = (*(int *)(loApicBase + LOAPIC_ID) & LOAPIC_ID_MASK) >> 24;
/* get the Local APIC Version from Local APIC Version register */
loApicVersion = *(int *)(loApicBase + LOAPIC_VER) & LOAPIC_VERSION_MASK;
loApicMaxLvt = (*(int *)(loApicBase + LOAPIC_VER) & LOAPIC_MAXLVT_MASK)
>> 16;
/* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */
*(int *)(loApicBase + LOAPIC_DFR) = (int)0xffffffff;
*(int *)(loApicBase + LOAPIC_TPR) = (int)0x0;
*(int *)(loApicBase + LOAPIC_TIMER_CONFIG) = (int)0x0;
*(int *)(loApicBase + LOAPIC_TIMER_ICR) = (int)0x0;
#if defined(VIRTUAL_WIRE_MODE)
/* program Local Vector Table for the Virtual Wire Mode */
#ifndef _WRS_CONFIG_SMP
if (sysBp)
#else
if (sysCpuNumGet() == 0)
#endif /* !_WRS_CONFIG_SMP */
{
/* set LINT0: extInt, high-polarity, edge-trigger, not-masked */
*(int *)(loApicBase + LOAPIC_LINT0) =
(*(int *)(loApicBase + LOAPIC_LINT0) &
~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) |
(LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE);
/* set LINT1: NMI, high-polarity, edge-trigger, not-masked */
*(int *)(loApicBase + LOAPIC_LINT1) =
(*(int *)(loApicBase + LOAPIC_LINT1) &
~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) |
(LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE);
}
else
{
*(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK;
*(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK;
}
#elif defined(SYMMETRIC_IO_MODE)
/* program Local Vector Table for the Symmetric IO Mode */
*(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK;
*(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK;
#endif /* defined(VIRTUAL_WIRE_MODE) */
/* lock the Local APIC interrupts */
*(int *)(loApicBase + LOAPIC_TIMER) = LOAPIC_MASK;
*(int *)(loApicBase + LOAPIC_ERROR) = LOAPIC_MASK;
if (loApicMaxLvt >= LOAPIC_LVT_P6)
*(int *)(loApicBase + LOAPIC_PMC) = LOAPIC_MASK;
if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4)
*(int *)(loApicBase + LOAPIC_THERMAL) = LOAPIC_MASK;
/* discard a pending interrupt if any */
*(int *)(loApicBase + LOAPIC_EOI) = 0;
}
/*******************************************************************************
*
* loApicEnable - enable or disable the Local xAPIC
*
* This routine enables or disables the Local xAPIC. If the parameter is TRUE,
* the Local xAPIC is enabled. If the parameter is FALSE, the Local xAPIC
* is disabled.
*
* RETURNS: N/A
*/
void loApicEnable
(
BOOL enable /* enable the Local xAPIC */
)
{
INT32 oldLevel;
BOOL loApicImcr = FALSE; /* TRUE if IMCR exist (MP Table) */
MP_FPS *pFps = mpApicFps;
/* check if the IMCR exists or not */
loApicImcr = (pFps->featureByte[1] & 0x80) ? TRUE : FALSE;
oldLevel = intLock (); /* LOCK INTERRUPTS */
/* enable or disable the Local APIC */
if (enable)
{
/* if the original mode is PIC mode, enable the Local APIC */
if ((loApicOldSvr & LOAPIC_ENABLE) == 0)
{
*(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_ENABLE;
}
#if defined (SYMMETRIC_IO_MODE)
/* switch to SYMMETRIC_IO mode from PIC/VIRTUAL_WIRE mode */
if (loApicImcr)
{
sysOutByte (IMCR_ADRS, IMCR_REG_SEL);
sysOutByte (IMCR_DATA, IMCR_IOAPIC_ON);
}
#endif /* defined (SYMMETRIC_IO_MODE) */
}
else
{
#if defined (SYMMETRIC_IO_MODE)
/* switch from SYMMETRIC_IO mode to PIC/VIRTUAL_WIRE mode */
if (loApicImcr)
{
sysOutByte (IMCR_ADRS, IMCR_REG_SEL);
sysOutByte (IMCR_DATA, IMCR_IOAPIC_OFF);
}
#endif /* defined (SYMMETRIC_IO_MODE) */
/* if the original mode is PIC mode, disable the Local APIC */
if ((loApicOldSvr & LOAPIC_ENABLE) == 0)
{
*(int *)(loApicBase + LOAPIC_SVR) &= ~LOAPIC_ENABLE;
}
else
{
/* restore the original value */
*(int *)(loApicBase + LOAPIC_SVR) = loApicOldSvr;
*(int *)(loApicBase + LOAPIC_LINT0) = loApicOldLint0;
*(int *)(loApicBase + LOAPIC_LINT1) = loApicOldLint1;
}
}
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
}
/*******************************************************************************
*
* loApicIntLock - lock out all Local APIC interrupts
*
* This routine locks out all Local APIC interrupts
* It should be called in the interrupt disable state(IF bit is 0).
*
* RETURNS: N/A
*
* SEE ALSO: loApicIntUnlock()
*
* ARGSUSED0
*/
LOCAL void loApicIntLock (void)
{
if (!(*(int *)(loApicBase + LOAPIC_TIMER) & LOAPIC_MASK))
{
sysIntMaskLocalApic |= LOCKED_TIMER;
*(int *)(loApicBase + LOAPIC_TIMER) |= LOAPIC_MASK;
}
if (!(*(int *)(loApicBase + LOAPIC_LINT0) & LOAPIC_MASK))
{
sysIntMaskLocalApic |= LOCKED_LINT0;
*(int *)(loApicBase + LOAPIC_LINT0) |= LOAPIC_MASK;
}
if (!(*(int *)(loApicBase + LOAPIC_LINT1) & LOAPIC_MASK))
{
sysIntMaskLocalApic |= LOCKED_LINT1;
*(int *)(loApicBase + LOAPIC_LINT1) |= LOAPIC_MASK;
}
if (!(*(int *)(loApicBase + LOAPIC_ERROR) & LOAPIC_MASK))
{
sysIntMaskLocalApic |= LOCKED_ERROR;
*(int *)(loApicBase + LOAPIC_ERROR) |= LOAPIC_MASK;
}
if ((loApicMaxLvt >= LOAPIC_LVT_P6) &&
(!(*(int *)(loApicBase + LOAPIC_PMC) & LOAPIC_MASK)))
{
sysIntMaskLocalApic |= LOCKED_PMC;
*(int *)(loApicBase + LOAPIC_PMC) |= LOAPIC_MASK;
}
if ((loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) &&
(!(*(int *)(loApicBase + LOAPIC_THERMAL) & LOAPIC_MASK)))
{
sysIntMaskLocalApic |= LOCKED_THERMAL;
*(int *)(loApicBase + LOAPIC_THERMAL) |= LOAPIC_MASK;
}
}
/*******************************************************************************
*
* loApicIntUnlock - unlock the Local APIC interrupts
*
* This routine unlocks the Local APIC interrupts
* It should be called in the interrupt disable state(IF bit is 0).
*
* RETURNS: N/A
*
* SEE ALSO: loApicIntLock()
*
* ARGSUSED0
*/
LOCAL void loApicIntUnlock (void)
{
if (sysIntMaskLocalApic & LOCKED_TIMER)
*(int *)(loApicBase + LOAPIC_TIMER) &= ~LOAPIC_MASK;
if (sysIntMaskLocalApic & LOCKED_LINT0)
*(int *)(loApicBase + LOAPIC_LINT0) &= ~LOAPIC_MASK;
if (sysIntMaskLocalApic & LOCKED_LINT1)
*(int *)(loApicBase + LOAPIC_LINT1) &= ~LOAPIC_MASK;
if (sysIntMaskLocalApic & LOCKED_ERROR)
*(int *)(loApicBase + LOAPIC_ERROR) &= ~LOAPIC_MASK;
if ((loApicMaxLvt >= LOAPIC_LVT_P6) &&
(sysIntMaskLocalApic & LOCKED_PMC))
*(int *)(loApicBase + LOAPIC_PMC) &= ~LOAPIC_MASK;
if ((loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) &&
(sysIntMaskLocalApic & LOCKED_THERMAL))
*(int *)(loApicBase + LOAPIC_THERMAL) &= ~LOAPIC_MASK;
sysIntMaskLocalApic = 0; /* reset the flags */
}
/*******************************************************************************
*
* loApicIntEoi - send EOI (End Of Interrupt) signal to Local APIC
*
* This routine sends an EOI signal to the Local APIC's interrupting source.
*
* RETURNS: N/A
*/
LOCAL void loApicIntEoi
(
INT32 irqNo /* INIIN number to send EOI */
)
{
#ifdef SYS_INT_DEBUG
extern UINT32 sysIntCount [];
sysIntCount [irqNo]++;
#endif /* SYS_INT_DEBUG */
*(int *)(loApicBase + LOAPIC_EOI) = 0;
}
/******************************************************************************
*
* loApicIpi - generate a Inter Processor Interrupt
*
* This routine delivers an Inter-Processor interrupt to the specified CPU
* in the specified mode, with the specified vectorNo. Level should always
* be 1 except INIT De-assert mode.
*
* RETURNS: OK, or ERROR if the delivery status is not idle
*/
STATUS loApicIpi
(
INT32 apicId, /* APIC ID number to send the interrupt */
INT32 shortHand, /* destination short hand */
INT32 trigger, /* trigger mode. 0: edge or 1: level */
INT32 level, /* level. 0: de-assert or 1: assert */
INT32 destMode, /* destination mode. 0: physical or 1: logical */
INT32 deliMode, /* delivery mode. 000: fixed ... 110: startup */
INT32 vectorNo /* vector number */
)
{
UINT32 icrHi = (*(int *)(loApicBase + LOAPIC_ICRHI)) & 0x00ffffff;
UINT32 icrLo = (*(int *)(loApicBase + LOAPIC_ICRLO)) & 0xfff32000;
/* ShortHand, Trigger, Level, DeliveryMode and Vector */
icrLo |= ((shortHand << 18) & 0xc0000) |
((trigger << 15) & 0x8000) |
((level << 14) & 0x4000) |
((destMode << 11) & 0x800) |
((deliMode << 8) & 0x700) |
(vectorNo & 0xff);
/* Destination Apic Id */
icrHi |= (apicId << 24) & 0xff000000;
/* is the interrupt idle? */
if (*(int *)(loApicBase + LOAPIC_ICRLO) & STATUS_PEND)
{
loApicBusy++;
LOAPIC_DBG_MSG ("ipi: LOAPIC busy 0x%x\n",
*(int *)(loApicBase + LOAPIC_ESR))
return (ERROR);
}
/* reset the error status register */
#ifndef _WRS_CONFIG_SMP
*(int *)(loApicBase + LOAPIC_ESR) = 0;
*(int *)(loApicBase + LOAPIC_ESR) = 0;
#endif /* !_WRS_CONFIG_SMP */
if (*(int *)(loApicBase + LOAPIC_ESR) != 0)
{
LOAPIC_DBG_MSG ("ipi: 0. ESR=0x%x\n",
*(int *)(loApicBase + LOAPIC_ESR))
return (ERROR);
}
/* Send it! */
#ifdef _WRS_CONFIG_SMP
/* Can send shorthand message by performing a single
* 32-bit memory write to the low half of the ICR.
*/
if ((shortHand == 0x00) || (destMode == 0x01))
*(int *)(loApicBase + LOAPIC_ICRHI) = icrHi;
#else
*(int *)(loApicBase + LOAPIC_ICRHI) = icrHi;
#endif
*(int *)(loApicBase + LOAPIC_ICRLO) = icrLo;
/* Wait till interrupt is sent */
while (*(int *)(loApicBase + LOAPIC_ICRLO) & STATUS_PEND)
if (*(int *)(loApicBase + LOAPIC_ESR) != 0)
{
LOAPIC_DBG_MSG ("ipi: 1. ESR=0x%x\n",
*(int *)(loApicBase + LOAPIC_ESR))
return (ERROR);
}
return(OK);
}
@@ -0,0 +1,590 @@
/* loApicIntrShow.c - Intel Local APIC/xAPIC driver show routines */
/* Copyright 1984-2002 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01e,26jul06,scm update for pentium/xeon support...
01d,18aug04,dmh improved mptable debugging information
01c,01apr04,dmh add support for multiple APICs
01b,08mar02,hdn added the description
01a,25jun01,hdn extracted from 01c version of loApicIntr.c
*/
/*
DESCRIPTION
This module is a show routine for the Local APIC/xAPIC (Advanced
Programmable Interrupt Controller) for P6 (PentiumPro, II, III)
family processors and P7 (Pentium4) family processors.
loApicShow() shows content of the Local APIC registers.
loApicMpShow() shows the MP configuration table.
INCLUDE FILES: loApic.h
*/
/* includes */
#include "drv/intrCtl/loApic.h"
/* externs */
/* globals */
/* locals */
/* forward declarations */
/*******************************************************************************
*
* loApicIntrShowScan - scans given memory range for the string match
*
* This routine scans the memory areas specified in its argument for the
* Intel MP signature string "_MP_", or other signature strings.
*
* RETURNS: pointer to address of matching string in the range , or NULL
*
*/
INT8 * loApicIntrShowScan
(
INT8 * match,
INT8 * start, /* start address to scan */
INT8 * end /* end address to scan */
)
{
INT8 * p;
for (p = start; (p+16) < end; p+=16)
{
if (strncmp (p, match, strlen(match)) == 0)
return (p);
}
return (NULL);
}
/*******************************************************************************
*
* loApicStatusShow - show Local APIC TMR, IRR, ISR registers
*
* This routine shows Local APIC TMR, IRR, ISR registers
*
* RETURNS: N/A
*/
LOCAL void loApicStatusShow (void)
{
int ix;
for (ix = 0; ix < 8; ix++)
{
printf ("LOAPIC_TMR%02d = 0x%08x ", ix,
*(UINT32 *)(loApicBase + LOAPIC_TMR + (ix * 0x10)));
printf ("LOAPIC_IRR%02d = 0x%08x ", ix,
*(UINT32 *)(loApicBase + LOAPIC_IRR + (ix * 0x10)));
printf ("LOAPIC_ISR%02d = 0x%08x\n", ix,
*(UINT32 *)(loApicBase + LOAPIC_ISR + (ix * 0x10)));
}
}
/*******************************************************************************
*
* loApicShow - show Local APIC registers
*
* This routine shows Local APIC registers
*
* RETURNS: N/A
*/
void loApicShow (void)
{
UINT32 localApicReg;
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ID);
printf ("local Apic ID = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_VER);
printf ("local Apic Version = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TPR);
printf ("Task Priority = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_APR);
printf ("Arbitration Priority = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_PPR);
printf ("Processor Priority = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_LDR);
printf ("Logical Destination = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_DFR);
printf ("Destination Format = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_SVR);
printf ("Spurious Interrupt Vector = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ESR);
printf ("Error Status = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ICRLO);
printf ("Interrupt Command 00-31 = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ICRHI);
printf ("Interrupt Command 32-63 = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TIMER);
printf ("Local Vector Table (Timer) = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_LINT0);
printf ("Local Vector Table (LINT0) = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_LINT1);
printf ("Local Vector Table (LINT1) = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_ERROR);
printf ("Local Vector Table (Error) = 0x%08x\n", localApicReg);
if (loApicMaxLvt >= LOAPIC_LVT_P6)
{
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_PMC);
printf ("Local Vector Table (PMC) = 0x%08x\n", localApicReg);
}
if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4)
{
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_THERMAL);
printf ("Local Vector Table (Therm) = 0x%08x\n", localApicReg);
}
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TIMER_ICR);
printf ("Timer Initial Count = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TIMER_CCR);
printf ("Timer Current Count = 0x%08x\n", localApicReg);
localApicReg = *(UINT32 *)(loApicBase + LOAPIC_TIMER_CONFIG);
printf ("Timer Divide Configuration = 0x%08x\n", localApicReg);
loApicStatusShow ();
}
/*******************************************************************************
*
* loApicMpShow - show MP configuration table
*
* This routine shows MP configuration table.
*
* RETURNS: N/A
*/
void loApicMpShow (void)
{
MP_FPS * pFps = NULL;
MP_HEADER * pTbl;
MP_CPU * pCpu;
MP_IOAPIC * pIoApic;
MP_BUS * pBus;
char * p;
int ix, iy;
/* MP Floating Point Structure */
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)EBDA_START, (char *)EBDA_END);
if (pFps == NULL)
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)BIOS_ROM_START,
(char *)BIOS_ROM_END);
if (pFps == NULL)
{
printf ("Not MP Compliant\n");
return;
}
printf ("MP Floating Point Structure\n");
printf (" Address Pointer = 0x%08x\n", pFps->configTableAddr);
printf (" Spec Version = 0x%02x\n", pFps->specRev);
printf (" Feature byte-1 = 0x%02x\n", pFps->featureByte[0]);
printf (" Feature byte-2 = 0x%02x\n", pFps->featureByte[1]);
printf (" Feature byte-3 = 0x%02x\n", pFps->featureByte[2]);
printf (" Feature byte-4 = 0x%02x\n", pFps->featureByte[3]);
printf (" Feature byte-5 = 0x%02x\n", pFps->featureByte[4]);
if ((pFps->featureByte[0] != 0) || (pFps->configTableAddr == 0))
{
printf ("MP Configuration Table does not exist");
return;
}
/* show MP Configuration Table Header */
pTbl = (MP_HEADER *)pFps->configTableAddr;
printf ("MP Configuration Table\n");
printf (" Base Table Length = 0x%04x\n", pTbl->tableLength);
printf (" OEM ID String = ");
for (ix = 0; ix < sizeof (pTbl->oemId); ix++)
printf ("%c", pTbl->oemId[ix]);
printf ("\n");
printf (" Product ID String = ");
for (ix = 0; ix < sizeof (pTbl->prodId); ix++)
printf ("%c", pTbl->prodId[ix]);
printf ("\n");
printf (" OEM Table Pointer = 0x%08x\n", pTbl->oemTablePtr);
printf (" OEM Table Size = 0x%04x\n", pTbl->oemTableSize);
printf (" Entry Count = 0x%04x\n", pTbl->entryCount);
printf (" Address of local APIC = 0x%08x\n", pTbl->localApicBaseAddr);
printf (" Extended Table Length = 0x%04x\n", pTbl->extendedTableLength);
/* show MP Configuration Table Entry */
p = (char *)pTbl + sizeof(MP_HEADER);
for (ix = 0; ix < pTbl->entryCount; ix++)
switch (*p)
{
case MP_ENTRY_CPU: /* Processor Entry */
pCpu = (MP_CPU *)p;
printf ("Processor Entry\n");
printf (" Local Apic ID = 0x%02x\n",
pCpu->localApicId);
printf (" Local Apic Ver = 0x%02x\n",
pCpu->localApicVersion);
printf (" CPU Flags = %s|%s\n",
(pCpu->cpuFlags&0x01)?"EN":"~EN",
(pCpu->cpuFlags&0x02)?"BP":"~BP");
printf (" CPU Signature = 0x%08x\n", pCpu->cpuSig);
printf (" Feature Flags = 0x%08x\n",
pCpu->featureFlags);
p += sizeof (MP_CPU);
break;
case MP_ENTRY_BUS: /* Bus Entry */
pBus = (MP_BUS *)p;
{
int busId = pBus->busId;
printf ("Bus Entry\n");
printf (" Bus ID = 0x%02x\n", busId);
}
printf (" Bus Type String = ");
for (iy = 0; iy < 6; iy++)
printf ("%c", pBus->busType[iy]);
printf ("\n");
p += 8;
break;
case MP_ENTRY_IOAPIC: /* IO APIC Entry */
pIoApic = (MP_IOAPIC *)p;
printf ("IO Apic Entry\n");
printf (" IO Apic ID = 0x%02x\n",
pIoApic->ioApicId);
printf (" IO Apic Ver = 0x%02x\n",
pIoApic->ioApicVersion);
printf (" IO Apic Flags = %s\n",
(pIoApic->ioApicFlags&0x01)?"EN":"~EN");
printf (" IO Apic Address = 0x%08x\n",
pIoApic->ioApicBaseAddress);
p += sizeof (MP_IOAPIC);
break;
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
printf ("IO Interrupt Entry\n");
printf (" Interrupt Type = 0x%02x\n", *(UINT8 *)(p + 1));
printf (" IO Interrupt Flag = InPol(");
switch( (*(UINT16 *)(p + 2))& 0x02)
{
case 0:
printf ("Bus");
break;
case 1:
printf ("AH");
break;
case 2:
printf ("RSV");
break;
case 3:
printf ("AL");
break;
}
printf (")|Trig(");
switch (((*(UINT16 *)(p + 2)) >> 2)& 0x02)
{
case 0:
printf ("Bus");
break;
case 1:
printf ("Edge");
break;
case 2:
printf ("RSV");
break;
case 3:
printf ("Lvl");
break;
}
printf (")\n");
printf (" Source Bus ID = 0x%02x\n", *(UINT8 *)(p + 4));
printf (" Source Bus IRQ = 0x%02x\n", *(UINT8 *)(p + 5));
printf (" Dest IO Apic ID = 0x%02x\n", *(UINT8 *)(p + 6));
printf (" Dest IO Apic INTIN = 0x%02x\n", *(UINT8 *)(p + 7));
p += 8;
break;
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
printf ("Local Interrupt Entry\n");
printf (" Interrupt Type = 0x%02x\n", *(UINT8 *)(p + 1));
printf (" IO Interrupt Flag = InPol(");
switch( (*(UINT16 *)(p + 2))& 0x02)
{
case 0:
printf ("Bus");
break;
case 1:
printf ("AH");
break;
case 2:
printf ("RSV");
break;
case 3:
printf ("AL");
break;
}
printf (")|Trig(");
switch (((*(UINT16 *)(p + 2)) >> 2)& 0x02)
{
case 0:
printf ("Bus");
break;
case 1:
printf ("Edge");
break;
case 2:
printf ("RSV");
break;
case 3:
printf ("Lvl");
break;
}
printf (")\n");
printf (" Source Bus ID = 0x%02x\n", *(UINT8 *)(p + 4));
printf (" Source Bus IRQ = 0x%02x\n", *(UINT8 *)(p + 5));
printf (" Dest Local Apic ID = 0x%02x\n", *(UINT8 *)(p + 6));
printf (" Dest Local Apic INTIN = 0x%02x\n", *(UINT8 *)(p + 7));
p += 8;
break;
default: /* Unknown Entry */
p += 8; /* wild guess */
}
/* p now pointing to the begining of the extended MP configuration table */
ix = 0;
while ( ix < (int) pTbl->extendedTableLength)
{
switch (*p)
{
case EXT_MP_ENTRY_SASM: /* System Address Space Map Entry */
printf ("System Address Space Map Entry\n");
printf (" Entry Length = 0x%02x\n", *(UINT8 *)(p + 1));
printf (" Bus ID = 0x%02x\n", *(UINT8 *)(p + 2));
printf (" Address Type = 0x%02x\n", *(UINT8 *)(p + 3));
printf (" Address Base (LOW) = 0x%04x\n",
*(UINT32 *)(p + 4));
printf (" Address Base (HIGH) = 0x%04x\n",
*(UINT32 *)(p + 8));
printf (" Address Length (LOW) = 0x%04x\n",
*(UINT32 *)(p + 4));
printf (" Address Length (HIGH) = 0x%04x\n",
*(UINT32 *)(p + 8));
p += 20;
ix += 20;
break;
case EXT_MP_ENTRY_BHD: /* Bus Hierarchy Descriptor Entry */
printf ("Bus Hierarchy Descriptor Entry\n");
printf (" Entry Length = 0x%02x\n", *(UINT8 *)(p + 1));
printf (" Bus ID = 0x%02x\n", *(UINT8 *)(p + 2));
printf (" Bus Info = 0x%02x\n", *(UINT8 *)(p + 3));
printf (" Parent Bus = 0x%02x\n", *(UINT8 *)(p + 4));
p += 8;
ix += 8;
break;
case EXT_MP_ENTRY_CBASM: /* Comp Address Space Modifier Entry */
printf ("Comp Address Space Modifier\n");
printf (" Entry Length = 0x%02x\n", *(UINT8 *)(p + 1));
printf (" Bus ID = 0x%02x\n", *(UINT8 *)(p + 2));
printf (" Address Mod = 0x%02x\n", *(UINT8 *)(p + 3));
printf (" Predefined Range List = 0x%04x\n",
*(UINT32 *)(p + 4));
p += 8;
ix += 8;
break;
default: /* Unknown Entry */
p += 8; /* wild guess */
ix += 8; /* wild guess */
}
}
}
/*******************************************************************************
*
* biosIoIntMapShow - show MP configuration table
*
* This routine shows MP configuration table.
*
* RETURNS: N/A
*/
void biosIoIntMapShow (void)
{
MP_FPS * pFps = NULL;
MP_HEADER * pTbl;
char * p;
int ix;
/* MP Floating Point Structure */
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)EBDA_START, (char *)EBDA_END);
if (pFps == NULL)
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)BIOS_ROM_START,
(char *)BIOS_ROM_END);
if (pFps == NULL)
{
printf ("Not MP Compliant\n");
return;
}
if ((pFps->featureByte[0] != 0) || (pFps->configTableAddr == 0))
{
printf ("MP Configuration Table does not exist");
return;
}
/* show MP Configuration Table Header */
pTbl = (MP_HEADER *)pFps->configTableAddr;
/* show Interrupt Configuration Table Entry */
printf ("BIOS I/O Interrupt Configuration Table\n");
printf (" Type Flags Bus ID Bus IRQ APIC ID APIC INT In Org Dev INT_n#\n");
printf (" ==== ====== ====== ======= ======= =========== ======= ======\n");
p = (char *)pTbl + sizeof(MP_HEADER);
for (ix = 0; ix < pTbl->entryCount; ix++)
switch (*p)
{
case MP_ENTRY_CPU: /* Processor Entry */
p += sizeof (MP_CPU);
break;
case MP_ENTRY_BUS: /* Bus Entry */
p += 8;
break;
case MP_ENTRY_IOAPIC: /* IO APIC Entry */
p += sizeof (MP_IOAPIC);
break;
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
printf(" 0x%02x 0x%04x %2d %3d %d %2d 0x%02x ",
*(p + 1), *(UINT16*)(p+2), *(p+4), *(p+5), *(p+6), *(p + 7), (*(p+5)) >> 2);
switch(*(p+5)&0x3)
{
case 0:
printf("A\n");
break;
case 1:
printf("B\n");
break;
case 2:
printf("C\n");
break;
case 3:
printf("D\n");
break;
}
p += 8;
break;
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
p += 8;
break;
default: /* Unknown Entry */
p += 8; /* wild guess */
}
}
/*******************************************************************************
*
* biosLocalIntMapShow - show MP configuration table
*
* This routine shows MP configuration table.
*
* RETURNS: N/A
*/
void biosLocalIntMapShow (void)
{
MP_FPS * pFps = NULL;
MP_HEADER * pTbl;
char * p;
int ix;
/* MP Floating Point Structure */
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)EBDA_START, (char *)EBDA_END);
if (pFps == NULL)
pFps = (MP_FPS *)loApicIntrShowScan ("_MP_", (char *)BIOS_ROM_START,
(char *)BIOS_ROM_END);
if (pFps == NULL)
{
printf ("Not MP Compliant\n");
return;
}
if ((pFps->featureByte[0] != 0) || (pFps->configTableAddr == 0))
{
printf ("MP Configuration Table does not exist");
return;
}
/* show MP Configuration Table Header */
pTbl = (MP_HEADER *)pFps->configTableAddr;
/* show Interrupt Configuration Table Entry */
printf ("BIOS Local Interrupt Configuration Table\n");
printf (" Type Flags Bus ID Bus IRQ APIC ID APIC INT In\n");
printf (" ==== ====== ====== ======= ========== ===========\n");
p = (char *)pTbl + sizeof(MP_HEADER);
for (ix = 0; ix < pTbl->entryCount; ix++)
switch (*p)
{
case MP_ENTRY_CPU: /* Processor Entry */
p += sizeof (MP_CPU);
break;
case MP_ENTRY_BUS: /* Bus Entry */
p += 8;
break;
case MP_ENTRY_IOAPIC: /* IO APIC Entry */
p += sizeof (MP_IOAPIC);
break;
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
p += 8;
break;
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
printf(" 0x%02x 0x%04x %2d %3d %d %2d\n",
*(p + 1), *(UINT16 *)(p + 2), *(p + 4), *(p + 5), *(p + 6), *(p + 7));
p += 8;
break;
default: /* Unknown Entry */
p += 8; /* wild guess */
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,618 @@
/* m8260Int.c - Motorola Voyager MPC 8260 interrupt controller driver */
/*
* Copyright (c) 1984-2004, 2008 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use of this
* software may be licensed only pursuant to the terms of an applicable Wind
* River license agreement.
*/
/*
modification history
--------------------
02b,03sep08,jpb Renamed VSB header file
02a,08apr08,tcr fix SV macro invocation
01z,18jun08,jpb Added include path for kernel configurations options set in
vsb.
01y,12may08,jpb Modifications for source build. Renamed
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
01x,22sep04,mdo Documentation fixes for apigen
01w,20apr04,dtr SPR 96472 sync required when loading mask values.
01v,04apr04,rec SPR 95018 - Aux timer hangs system
01u,24oct03,rec change Timer 2 to highest priority for PWR MGMT
01t,24nov03,to compilation fix and some style and spell fixes
01s,06nov03,kam added intDisconnect() functionality
01r,31jan03,dtr Adding PCI Interrupt for MPC8266 et al.
01q,14jan03,gjc Fix SPR#85215 - m8260IntrDeMux() Fails to break out of while
loop.
01p,28mar02,dtr Fix typo.
01o,28mar02,jrs Correct loop bounds check for attaching ISR's to int no's.
01n,12jan02,g_h Remove calling to intLock() in m8260IntrDeMux()
01m,07dec01,rcs masked vxImmrGet() value with IMMR_ISB_MASK SPR# 72027
01l,22oct01,g_h Change the m8260IntrDeMux function to check for interrupt 0
as indication for no interrupt. As long as reading the SIVEC
register different from 0 we have pending interrupt and
we need to server it, this fix SPR 71119.
01k,22oct01,g_h Clean compilation warning from m8260IntDisable function, and
change the declaration of intVec in m8260IntrDeMux to VINT32
from UINT32 to prevent optimization problem.
01j,16sep99,ms_ m8260IntrCtl.h comes from h/drv/intrCtl
01i,16sep99,ms_ rename m8260Int.h to m8260IntrCtl.h
01h,15jul99,ms_ make compliant with our coding standards
01g,13may99,ms_ minor fixes
01f,17apr99,ms_ final cleanup for EAR
01e,15apr99,ms_ disable only lower priority interrupts while processing
interrupt
01d,13apr99,ms_ redefine IVEC_TO_INUM and INUM_TO_IVEC to use the numbers as
shown in the MPC8260 user's manual
01c,12apr99,ms_ remove any sio specific items; that is handled in the sio
driver
01b,29mar99,ms_ add ability to mask out lower priority interrupts when
processing an interrupt
01a,22feb99,ms_ adapted from ppc8260Intr.c version 01f
*/
/*
DESCRIPTION
The PowerPC 8260 CPU is divided in three units: PowerPC core, System
Interface Unit (SIU) and Communication Processor Unit (CPM). The PowerPC
core accepts only one external interrupt exception (vector 0x500). The SIU
provides an interrupt controller which provides 55 interrupt sources
The Interrupt controller is connected to the PowerPC core external
interrupt. This library provides the routines to manage this interrupt
controllers.
m8260IntrInit() connects the default demultiplexer, m8260IntrDeMux(), to the
external interrupt vector and initializes a table containing a function pointer
and an associated parameter for each interrupt source. m8260IntrInit() is called
by sysHwInit() from sysLib.c.
The default demultiplexer, m8260IntrDeMux() detects which peripheral or
controller has raised an interrupt and calls the associated routine with its
parameter.
INCLUDE FILES: m8260IntrCtl.h
*/
/* includes */
#include <vsbConfig.h>
#include "intLib.h"
#include "iv.h"
#include "drv/intrCtl/m8260IntrCtl.h"
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
#include "private/funcBindP.h"
#include "private/eventP.h"
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
/* local */
LOCAL INTR_HANDLER intrVecTable[IVEC_MAX+1]; /* Intr vector table */
LOCAL VOIDFUNCPTR defaultVec; /* INTR3 default vector */
/* SIU Interrupt Mask structure; a value for the high and low parts */
typedef struct siu_int_mask
{
UINT32 simr_h;
UINT32 simr_l;
} SIU_INT_MASK;
/*
* For a given inum, return a pair of masks, one for SIMR_H and one for SIMR_L,
* which will enable only higher priority interrupts.
* REF: MPC8269 PowerQuiccII Family Reference Manual - Figs 4-16, 4-17
*/
LOCAL SIU_INT_MASK enableHighPriInts[] =
{
{0x00000000, 0x00000000}, /* interrupt 0 error - enable nothing */
{0x003F7C06, 0xECF0264A}, /* I2C */
{0x0FFF7F06, 0xECF0A7DA}, /* SPI */
{0x003F7C06, 0xECF0064A}, /* RISC Timer Table */
{0x3FFF7F06, 0xECF0E7DA}, /* SMC1 */
{0x3FFF7F06, 0xECF0F7DA}, /* SMC2 */
{0x00077C06, 0xECF00048}, /* IDMA1 */
{0x001F7C06, 0xECF00448}, /* IDMA2 */
{0x00FF7E06, 0xECF0A64A}, /* IDMA3 */
{0x0FFF7F06, 0xECF0A74A}, /* IDMA4 */
{0x00077C06, 0xECF00008}, /* SDMA Bus Error */
{0xFFFFFFFF, 0xFFFFFFEA}, /* interrupt 11 reserved - enable everything */
{0xFFFFFFFF, 0xFFFFFFEA}, /* Timer 1 - not used */
{0x00000000, 0x00000000}, /* Timer 2 - system timer, - enable nothing */
{0xFFFFFFFF, 0xFFFFFFEA}, /* Timer 3 - not used */
{0x07FF7F06, 0xECF0A748}, /* Timer 4 */
{0x00000000, 0x00000008}, /* TMCNT */
{0x00000004, 0x00000008}, /* PIT */
{0x00000000, 0x00000008}, /* PCI Interrupt */
{0x00000006, 0x00000008}, /* IRQ1 XXXX */
{0x00004006, 0xEC000008}, /* IRQ2 */
{0x00006006, 0xEC000008}, /* IRQ3 */
{0x00007006, 0xEC000008}, /* IRQ4 */
{0x00007806, 0xEC000008}, /* IRQ5 */
{0x00FF7C06, 0xECF0A64A}, /* IRQ6 */
{0x00FF7E06, 0xECF0A74A}, /* IRQ7 */
{0xFFFFFFFF, 0xFFFFFFEA}, /* interrupt 26 reserved - enable everything */
{0x00004006, 0x00000008}, /* FCC1 */
{0x00004006, 0x80000008}, /* FCC2 */
{0x00004006, 0xC0000008}, /* FCC3 */
{0xFFFFFFFF, 0xFFFFFFEA}, /* interrupt 30 reserved - enable everything */
{0x00004006, 0xE0000008}, /* MCC1 */
{0x00004006, 0xE8000008}, /* MCC2 */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 33 reserved - enable everything */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 34 reserved - enable everything */
{0x00007C06, 0xEC000008}, /* SCC1 */
{0x00007C06, 0xEC800008}, /* SCC2 */
{0x00007C06, 0xECC00008}, /* SCC3 */
{0x00007C06, 0xECE00008}, /* SCC4 */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 39 reserved - enable everything */
{0x00007C06, 0xECF00008}, /* PC15 */
{0x00017C06, 0xECF00008}, /* PC14 */
{0x00037C06, 0xECF00008}, /* PC13 */
{0x00077C06, 0xECF00448}, /* PC12 */
{0x000F7C06, 0xECF00448}, /* PC11 */
{0x001F7C06, 0xECF0064A}, /* PC10 */
{0x003F7C06, 0xECF0A64A}, /* PC9 */
{0x007F7C06, 0xECF0A64A}, /* PC8 */
{0x00FF7F06, 0xECF0A74A}, /* PC7 */
{0x01FF7F06, 0xECF0A74A}, /* PC6 */
{0x03FF7F06, 0xECF0A74A}, /* PC5 */
{0x07FF7F06, 0xECF0A74A}, /* PC4 */
{0x0FFF7F06, 0xECF0E7DA}, /* PC3 */
{0x1FFF7F06, 0xECF0E7DA}, /* PC2 */
{0x3FFF7F06, 0xECF0FFDA}, /* PC1 */
{0x7FFF7F06, 0xECF0FFDA}, /* PC0 */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 56 reserved - enable everything */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 57 reserved - enable everything */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 58 reserved - enable everything */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 59 reserved - enable everything */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 60 reserved - enable everything */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 61 reserved - enable everything */
{0xFFFFFFFF, 0xFFFFFFDA}, /* interrupt 62 reserved - enable everything */
{0xFFFFFFFF, 0xFFFFFFDA} /* interrupt 63 reserved - enable everything */
};
LOCAL UINT32 iNumToMaskPattern[] =
{
0x00000000, /* interrupt number 0: Error */
0x00008000, /* interrupt number 1: I2C */
0x00004000, /* interrupt number 2: SPI */
0x00002000, /* interrupt number 3: Risc Timer Table */
0x00001000, /* interrupt number 4: SMC 1 */
0x00000800, /* interrupt number 5: SMC 2 */
0x00000400, /* interrupt number 6: IDMA1 */
0x00000200, /* interrupt number 7: IDMA2 */
0x00000100, /* interrupt number 8: IDMA3 */
0x00000080, /* interrupt number 9: IDMA4 */
0x00000040, /* interrupt number 10: SDMA */
0x00000000, /* interrupt number 11: reserved */
0x00000010, /* interrupt number 12: Timer 1 */
0x00000008, /* interrupt number 13: Timer 2 */
0x00000004, /* interrupt number 14: Timer 3 */
0x00000002, /* interrupt number 15: Timer 4 */
0x00000004, /* interrupt number 16: TMCNT */
0x00000002, /* interrupt number 17: PIT */
0x00000001, /* interrupt number 18: PCI */
0x00004000, /* interrupt number 19: IRQ 1 interrupt */
0x00002000, /* interrupt number 20: IRQ 2 interrupt */
0x00001000, /* interrupt number 21: IRQ 3 interrupt */
0x00000800, /* interrupt number 22: IRQ 4 interrupt */
0x00000400, /* interrupt number 23: IRQ 5 interrupt */
0x00000200, /* interrupt number 24: IRQ 6 interrupt */
0x00000100, /* interrupt number 25: IRQ 7 interrupt */
0x00000000, /* interrupt number 26: reserved */
0x80000000, /* interrupt number 27: FCC1 */
0x40000000, /* interrupt number 28: FCC2 */
0x20000000, /* interrupt number 29: FCC3 */
0x00000000, /* interrupt number 30: reserved */
0x08000000, /* interrupt number 31: MCC1 */
0x04000000, /* interrupt number 32: MCC2 */
0x00000000, /* interrupt number 33: reserved */
0x00000000, /* interrupt number 34: reserved */
0x00800000, /* interrupt number 35: SCC1 */
0x00400000, /* interrupt number 36: SCC2 */
0x00200000, /* interrupt number 37: SCC3 */
0x00100000, /* interrupt number 38: SCC4 */
0x00000000, /* interrupt number 39: reserved */
0x00010000, /* interrupt number 40: Parallel I/O [15] */
0x00020000, /* interrupt number 41: Parallel I/O [14] */
0x00040000, /* interrupt number 42: Parallel I/O [13] */
0x00080000, /* interrupt number 43: Parallel I/O [12] */
0x00100000, /* interrupt number 44: Parallel I/O [11] */
0x00200000, /* interrupt number 45: Parallel I/O [10] */
0x00400000, /* interrupt number 46: Parallel I/O [9] */
0x00800000, /* interrupt number 47: Parallel I/O [8] */
0x01000000, /* interrupt number 48: Parallel I/O [7] */
0x02000000, /* interrupt number 49: Parallel I/O [6] */
0x04000000, /* interrupt number 50: Parallel I/O [5] */
0x08000000, /* interrupt number 51: Parallel I/O [4] */
0x10000000, /* interrupt number 52: Parallel I/O [3] */
0x20000000, /* interrupt number 53: Parallel I/O [2] */
0x40000000, /* interrupt number 54: Parallel I/O [1] */
0x80000000, /* interrupt number 55: Parallel I/O [0] */
0x00000000, /* interrupt number 56: reserved */
0x00000000, /* interrupt number 57: reserved */
0x00000000, /* interrupt number 58: reserved */
0x00000000, /* interrupt number 59: reserved */
0x00000000, /* interrupt number 60: reserved */
0x00000000, /* interrupt number 61: reserved */
0x00000000, /* interrupt number 62: reserved */
0x00000000 /* interrupt number 63: reserved */
};
/* forward declarations */
LOCAL void m8260IntrDeMux (void);
LOCAL STATUS m8260IntConnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
LOCAL STATUS m8260IntDisconnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
/*******************************************************************************
*
* m8260IntrInit - initialize the interrupt manager for the PowerPC 8260
*
* This routine connects the default demultiplexer, m8260IntrDeMux(), to the
* external interrupt vector and associates all
* interrupt sources with the default interrupt handler. This routine is
* called by sysHwInit() in sysLib.c.
*
* NOTE: All interrupts from the SIU unit are enabled, CICR is setup so
* that SCC1 has the highest relative interrupt priority, through SCC4 with the
* lowest.
*
* RETURNS: OK always
*
* ERRNO
*/
STATUS m8260IntrInit (void)
{
int vector;
UINT32 immrVal = (vxImmrGet()& IMMR_ISB_MASK);
/* Get the default vector connected to the External Interrupt (0x500) */
defaultVec = (VOIDFUNCPTR) excVecGet ((FUNCPTR *) _EXC_OFF_INTR);
/* Connect the interrupt demultiplexer to External Interrupt (0x500) */
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, m8260IntrDeMux);
/* Install `system' intConnect routine */
if (_func_intConnectRtn == NULL)
_func_intConnectRtn = m8260IntConnect;
if (_func_intDisconnectRtn == NULL)
_func_intDisconnectRtn = m8260IntDisconnect;
if (_func_intEnableRtn == NULL)
_func_intEnableRtn = m8260IntEnable;
if (_func_intDisableRtn == NULL)
_func_intDisableRtn = m8260IntDisable;
/* Set all vectors to default handler */
for (vector = 0; vector <= IVEC_MAX; vector++)
intConnect (INUM_TO_IVEC(vector), (VOIDFUNCPTR) defaultVec, 0);
/* disable all interrupts */
*M8260_SIMR_L(immrVal) = 0x00000000;
*M8260_SIMR_H(immrVal) = 0x00000000;
return (OK);
}
/*******************************************************************************
*
* m8260IntConnect - connect a routine to an interrupt
*
* This routine connects any C or assembly routine to one of the multiple
* sources of interrupts.
*
* The connected routine can be any normal C code, except that it must not
* invoke certain operating system functions that may block or perform I/O
* operations.
*
* <vector> types are defined in h/drv/intrClt/m8260Intr.h.
*
* RETURNS: OK, or ERROR if <vector> is unknown.
*
* ERRNO
*
* SEE ALSO: m8260Intr.h
*/
LOCAL STATUS m8260IntConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
/* test the vector */
if ((int)(vector) > IVEC_MAX)
return (ERROR);
intrVecTable[(int)(vector)].vec = routine;
intrVecTable[(int)(vector)].arg = parameter;
return (OK);
}
/*******************************************************************************
*
* m8260IntDisconnect - disconnect a routine from an interrupt
*
* This routine disconnects any C or assembly routine from one of the multiple
* sources of interrupts.
*
* <vector> types are defined in h/drv/intrClt/m8260Intr.h.
*
* RETURNS: OK, or ERROR if <vector> is unknown.
*
* ERRNO
*
* SEE ALSO: m8260Intr.h
*/
LOCAL STATUS m8260IntDisconnect
(
VOIDFUNCPTR * vector, /* interrupt vector to detach from */
VOIDFUNCPTR routine, /* routine to be disconnected */
int parameter /* parameter to be matched */
)
{
/* test the vector */
if ((int)(vector) > IVEC_MAX)
return (ERROR);
/* set the entry back to the default */
intrVecTable[(int)(vector)].vec = (VOIDFUNCPTR)defaultVec;
intrVecTable[(int)(vector)].arg = 0;
return (OK);
}
/*******************************************************************************
*
* m8260IntrDeMux - SIU interrupt demultiplexer
*
* This routine must be bound to an external interrupt exception (vector 0x500).
* It is used to call the appropriate handler with its argument when an
* interrupt occurs.
*
* The interrupts are prioritized in the following order:
*
* NOTE: when this function is called the interrupts are still locked. It's
* this function's responsibility to unlock the interrupt.
*
* RETURNS: N/A
*
* ERRNO
*/
LOCAL void m8260IntrDeMux (void)
{
VINT32 intVec; /* interrupt vector */
UINT32 oldIntMask_L; /* current interrupt mask */
UINT32 oldIntMask_H; /* current interrupt mask */
UINT32 immrVal;
UINT32 intLevel = _PPC_MSR_EE;
int dummy;
immrVal = (vxImmrGet() & IMMR_ISB_MASK);
/* read the interrupt vector register */
intVec = (0x0000003f & ((* M8260_SIVEC(immrVal)) >> 26));
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
EVT_CTX_1(EVENT_INT_ENT(0),intVec);
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
if ( intVec != 0 )
{
/* save the current interrupt mask */
oldIntMask_L = * M8260_SIMR_L(immrVal);
oldIntMask_H = * M8260_SIMR_H(immrVal);
/* enable only the higher priority interrupts */
* M8260_SIMR_L(immrVal)&=
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].simr_l;
* M8260_SIMR_H(immrVal)&=
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].simr_h;
/* New: read last written value into 'dummy' to enforce a sync */
dummy = * M8260_SIMR_H(immrVal);
/* unlock the interrupt */
intUnlock (_PPC_MSR_EE);
/* call the Interrupt Handler */
/* table is indexed by vector */
intrVecTable[intVec].vec (intrVecTable[intVec].arg);
/* restore the interrupt mask */
intLevel = intLock ();
* M8260_SIMR_L(immrVal) = oldIntMask_L;
* M8260_SIMR_H(immrVal) = oldIntMask_H;
intUnlock (intLevel);
}
return;
}
/*******************************************************************************
*
* m8260IntEnable - enable the indicated interrupt
*
* This routine enables the indicated interrupt by setting the appropriate
* bit in the SIU Interrupt Mask Registers.
*
* The design of the 8260 presents the following design requirements:
*
* 1. the mapping from interrupt number to mask bit can not be represented by
* a function. An array, indexed by interrupt number (INUM), is used to map
* the interrupt number to the appropriate mask.
*
* 2. There are two 32 bit mask registers (SIMR_L and SIMR_H). The interrupt
* number must be compared to 4 ranges to determine which register contains
* its mask bit:
*
* \cs
* interrupt number
* in m8260IntrCtl.h register
* ---------------- -------
* 0-15 SIMR_L
* 16-31 SIMR_H
* 32-47 SIMR_L
* 48-63 SIMR_H
* \ce
*
* RETURNS: 0, always.
*
* ERRNO
*/
int m8260IntEnable
(
int intNum /* interrupt level to enable */
)
{
UINT32 immrVal = (vxImmrGet() & IMMR_ISB_MASK);
if ((intNum > 0) && (intNum <= IVEC_MAX))
{
if (((intNum >= 0) && (intNum <= 15)) ||
((intNum >= 27) && (intNum <= 38)))
*M8260_SIMR_L(immrVal) |= iNumToMaskPattern[intNum];
else
*M8260_SIMR_H(immrVal) |= iNumToMaskPattern[intNum];
}
return 0;
}
/*******************************************************************************
*
* m8260IntDisable - Disable one of the Level or IRQ interrupts into the SIU
*
* This routine masks the bit in the SIMASK register corresponding to
* the requested interrupt level.
*
* RETURNS: 0, always.
*
* ERRNO
*/
int m8260IntDisable
(
int intNum /* interrupt level to disable */
)
{
UINT32 immrVal = (vxImmrGet() & IMMR_ISB_MASK);
if ((intNum >= 0) && (intNum <= IVEC_MAX))
{
if (((intNum >= 0) && (intNum <= 15)) ||
((intNum >= 27) && (intNum <= 38)))
*M8260_SIMR_L(immrVal) &= ~iNumToMaskPattern[intNum];
else
*M8260_SIMR_H(immrVal) &= ~iNumToMaskPattern[intNum];
}
return 0;
}
VOIDFUNCPTR * m8260InumToIvec
(
int intNum
)
{
if (intNum <0) /* error */
return ((VOIDFUNCPTR *) 0);
else if (intNum <= 25)
return ((VOIDFUNCPTR *) intNum);
else if (intNum == 26) /* error */
return ((VOIDFUNCPTR *) 0);
else if (intNum <= 38)
return ((VOIDFUNCPTR *) (intNum + 5));
else if (intNum == 39) /* error */
return ((VOIDFUNCPTR *) 0);
else if (intNum <= 55)
return ((VOIDFUNCPTR *) (intNum + 8));
else /* error */
return ((VOIDFUNCPTR *) 0);
}
/*******************************************************************************
*
* m8260IvecToInum - get the relevant interrupt number
*
* This routine finds out the interrupt number associated with the vector
* in <vector>.
*
* <vector> types are defined in h/drv/intrClt/m8260Intr.h.
*
* RETURNS: the interrupt number for the vector
*
* ERRNO
*
* SEE ALSO: m8260Intr.h
*/
int m8260IvecToInum
(
VOIDFUNCPTR * vector /* interrupt vector to attach to */
)
{
/* test the vector */
if ((int) (vector) <= 0)
return ((int ) 0);
else if ((int) vector < INUM_RESERVED26)
return ((int) vector);
else if ((int) vector < 32)
return (INUM_RESERVED26);
else if ((int) vector < 44)
return ((int) vector - 5);
else if ((int) vector < 48)
return ((int) INUM_RESERVED39);
else if ((int) vector <= IVEC_MAX)
return ((int) vector - 8);
else
return (0);
}
+336
View File
@@ -0,0 +1,336 @@
/* mpApic.c - Intel MP APIC/xAPIC (Advanced PIC) */
/* Copyright 2006, 2008, 2015 Wind River Systems, Inc. */
/*
modification history
--------------------
01g,29jun15,ten VXW6-84526 - Do not allocate space for disabled IO Apics.
Sort staticMpApicAddrTable and staticMpApicLogicalTable by
IO APIC ID
01f,27aug08,jpb Renamed VSB header file
01e,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
for kernel configurations options set in vsb.
01d,30oct06,scm rename mpApicNcpu to vxCpuCount...
01c,31aug06,scm add support for CPU ID translation table...
01b,26jul06,scm update for pentium/xeon support...
01a,26jul06,hdn written...
*/
/* includes */
#include <vsbConfig.h>
#include "private/vxSmpP.h"
#include "drv/intrCtl/loApic.h"
#include "drv/intrCtl/ioApic.h"
#include "drv/intrCtl/mpApic.h"
/* externs */
IMPORT UINT32 sysIrqToPciIrq(UINT32 physApicId, UINT32 irq);
/* forward declarations */
STATUS mpApicMpConfigTableInit(void);
INT8 *mpApicScan(INT8* match, INT8 * start, INT8 * end);
/* globals */
UINT32 mpApicNioApic = 0; /* number of IO APICs (MP Table) */
UINT32 mpApicNbus = 0; /* number of buses (MP Table) */
UINT32 mpApicNioint = 0; /* number of io interrupts (MP Table) */
UINT32 mpApicNloint = 0; /* number of local interrupts (MP Table) */
MP_FPS* mpApicFps = NULL;
UINT32 *mpApicAddrTable[MAX_IOAPICS]; /* logical apic id to address mapping */
UINT8 mpApicLogicalTable[MAX_IOAPICS]; /* recorded id mapping */
#ifdef _WRS_CONFIG_SMP
UINT8 mpCpuIndexTable[256]; /* cpu Id translation */
UINT8 mploApicIndexTable[VX_MAX_SMP_CPUS]; /* loApic Id translation */
#endif /* _WRS_CONFIG_SMP */
MP_INTERRUPT *mpApicInterruptTable; /* */
MP_BUS *mpApicBusTable; /* */
UINT8 mpApicBaseIrq[MAX_IOAPICS];
UINT8 mpApicRedEntries[MAX_IOAPICS];
#ifdef MPTABLE_OVER_RIDE /* in case maybe the bios has it all wrong */
IMPORT MP_FPS *sysFps;
IMPORT MP_BUS *sysBusTable;
IMPORT UINT32 sysNcpu;
IMPORT UINT32 sysNioApic;
IMPORT UINT32 sysNbus;
IMPORT UINT32 sysNioint;
IMPORT UINT32 sysNloint;
IMPORT MP_INTERRUPT sysIntTable[];
IMPORT MP_INTERRUPT *sysInterruptTable;
typedef struct apic_info
{
UINT8 id;
UINT32 *addr;
} APIC_INFO;
IMPORT APIC_INFO sysApicTable[];
IMPORT UINT8 sysBaseIrq[];
IMPORT UINT8 sysRedEntries[];
#endif /* MPTABLE_OVER_RIDE */
/*******************************************************************************
*
* mpApicMpConfigTableInit - initialize pointers to MP configuration table
*
* This routine scans the memory areas specified in MP ver1.4, to find the
* MP signature and initializes pointers to MP configuration tables. This
* is not comprehensive and the only data used by VxWorks is the
* APIC IDs and APIC base addresses.
*
* RETURNS: OK, or ERROR if not MP compliant
*
*/
#ifdef MPTABLE_OVER_RIDE /* some MP tables are broken, allow for override */
STATUS mpApicMpConfigTableInit (void)
{
int apicId;
#ifdef _WRS_CONFIG_SMP
vxCpuCount = sysNcpu;
#endif /* _WRS_CONFIG_SMP */
mpApicNioApic = sysNioApic;
mpApicNbus = sysNbus;
mpApicNioint = sysNioint;
mpApicNloint = sysNloint;
mpApicInterruptTable = sysInterruptTable;
mpApicBusTable = sysBusTable;
mpApicFps = sysFps;
for(apicId = 0; apicId < sysNioApic; apicId++)
{
mpApicLogicalTable[apicId] = sysApicTable[apicId].id;
mpApicAddrTable[apicId] = sysApicTable[apicId].addr;
mpApicRedEntries[apicId] = sysRedEntries[apicId];
mpApicBaseIrq[apicId] = sysBaseIrq[apicId];
}
return OK;
}
#else
STATUS mpApicMpConfigTableInit (void)
{
MP_HEADER * hdr;
MP_LOINTERRUPT * loint;
MP_IOINTERRUPT * ioint;
MP_CPU * cpu;
MP_IOAPIC * ioapic;
MP_BUS * bus;
MP_IOAPIC * pIoApic;
INT8 * p;
INT32 ix, numEntries;
UINT32 temp32;
UINT8 outerIndex, innerIndex;
/* scan for the MP Floating Point Structure */
mpApicFps = (MP_FPS *)mpApicScan ("_MP_", (char *)EBDA_START, (char *)EBDA_END);
if (mpApicFps == NULL)
mpApicFps = (MP_FPS *)mpApicScan ("_MP_", (char *)BIOS_ROM_START,
(char *)BIOS_ROM_END);
if (mpApicFps == NULL)
return (ERROR);
/*
* If featurebyte1 (array element 0) is non-zero, then we use
* standard configuration return ERROR and let the error handle use
* standard addresses and Local and IO APIC ID's.
*/
if ((mpApicFps->featureByte[0] != 0) || (mpApicFps->configTableAddr == 0))
return (ERROR);
/* get MP header pointer */
hdr = (MP_HEADER *) mpApicFps->configTableAddr;
/* First Pass identifies the number of each important entry */
p = (char *)hdr + sizeof(MP_HEADER);
for(ix = 0; ix < hdr->entryCount; ix++)
{
switch(*p)
{
case MP_ENTRY_CPU: /* Processor Configuration Entry */
#ifdef _WRS_CONFIG_SMP
vxCpuCount++; /* increment the CPU counter */
#endif /* _WRS_CONFIG_SMP */
p += sizeof (MP_CPU);
break;
case MP_ENTRY_IOAPIC: /* IO Apic Configuration Entry */
pIoApic = (MP_IOAPIC *)p;
/* Check to see if the IO APIC is enabled */
if (pIoApic->ioApicFlags & 0x01)
mpApicNioApic++; /* increment the IO APIC counter */
p += sizeof (MP_IOAPIC);
break;
case MP_ENTRY_BUS:
mpApicNbus++;
p += sizeof (MP_BUS);
break;
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
mpApicNioint++;
p += sizeof (MP_IOINTERRUPT);
break;
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
mpApicNloint++;
p += sizeof (MP_LOINTERRUPT);
break;
default:
p += 8; /* "maybe" it is 8 bytes till the next entry */
}
}
/* reset the counters */
numEntries = ix;
#ifdef _WRS_CONFIG_SMP
vxCpuCount = 0;
#endif /* _WRS_CONFIG_SMP */
mpApicNioApic = 0;
mpApicNbus = 0;
mpApicNioint = 0;
mpApicNloint = 0;
/* Second Pass takes action on each important entry */
p = (char *)hdr + sizeof(MP_HEADER);
for(ix = 0; ix < numEntries; ix++)
{
switch(*p)
{
case MP_ENTRY_CPU: /* Processor Configuration Entry */
cpu = (MP_CPU *)p;
#ifdef _WRS_CONFIG_SMP
/* build cpu/loApic Id translation tbls */
mpCpuIndexTable[cpu->localApicId] = vxCpuCount;
mploApicIndexTable[vxCpuCount] = cpu->localApicId;
vxCpuCount++; /* increment the CPU counter */
#endif /* _WRS_CONFIG_SMP */
p += sizeof (MP_CPU);
break;
case MP_ENTRY_IOAPIC: /* IO Apic Configuration Entry */
ioapic = (MP_IOAPIC *)p;
if ((ioapic->ioApicFlags & 0x1) && (mpApicNioApic < MAX_IOAPICS))
{
mpApicLogicalTable[mpApicNioApic] = ioapic->ioApicId;
mpApicAddrTable[mpApicNioApic] = (UINT32*)ioapic->ioApicBaseAddress;
mpApicNioApic++; /* increment the IO APIC counter */
}
p += sizeof (MP_IOAPIC);
break;
case MP_ENTRY_BUS: /* Bus Identifier Entry */
if (mpApicNbus == 0)
mpApicBusTable =(MP_BUS *)p;
mpApicNbus++;
bus = (MP_BUS *)p;
p += sizeof (MP_BUS);
break;
case MP_ENTRY_IOINTERRUPT: /* IO Interrupt Entry */
if (mpApicNioint == 0)
mpApicInterruptTable = (MP_IOINTERRUPT *)p;
mpApicNioint++;
ioint = (MP_IOINTERRUPT *)p;
p += sizeof (MP_IOINTERRUPT);
break;
case MP_ENTRY_LOINTERRUPT: /* Local Interrupt Entry */
loint = (MP_LOINTERRUPT *)p;
mpApicNloint++;
p += sizeof (MP_LOINTERRUPT);
break;
}
}
for (outerIndex = 0; outerIndex < pMpApicData->mpApicNioApic; outerIndex++)
for (innerIndex = 0; innerIndex < pMpApicData->mpApicNioApic - 1; innerIndex++)
if (mpApicLogicalTable[innerIndex] >
mpApicLogicalTable[innerIndex+1])
{
/* swap entries */
temp32 = mpApicAddrTable[innerIndex+1];
mpApicAddrTable[innerIndex+1] =
mpApicAddrTable[innerIndex];
mpApicAddrTable[innerIndex] = temp32;
tmp = mpApicLogicalTable[innerIndex+1];
mpApicLogicalTable[innerIndex+1] =
mpApicLogicalTable[innerIndex];
mpApicLogicalTable[innerIndex] = tmp;
}
/* Set up the Local APIC */
loApicBase = (UINT32)(hdr->localApicBaseAddr);
return(OK);
}
#endif /* OVER RIDE */
/*******************************************************************************
*
* mpApicScan - scans given memory range for the string match
*
* This routine scans the memory areas specified in its argument for the
* Intel MP signature string "_MP_", or other signature strings.
*
* RETURNS: pointer to address of matching string in the range , or NULL
*
*/
INT8 * mpApicScan
(
INT8 * match,
INT8 * start, /* start address to scan */
INT8 * end /* end address to scan */
)
{
INT8 * p;
for (p = start; (p+16) < end; p+=16)
{
if (strncmp (p, match, strlen(match)) == 0)
return (p);
}
return (NULL);
}
UINT32 mpApicIrqToBusIrq(UINT32 ioApicId, UINT32 irq)
{
UINT32 physApicId = mpApicLogicalTable[ioApicId];
return sysIrqToPciIrq(physApicId, irq);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,328 @@
/* ppc403Intr.c - IBM 403 EVB-specific interrupt handling library */
/*
* Copyright (c) 1984-2003, 2008 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use of this
* software may be licensed only pursuant to the terms of an applicable Wind
* River license agreement.
*/
/* modification history
-----------------------
01u,27aug08,jpb Renamed VSB header file
01t,18jul08,kk added inclusion of private/vsbConfigP.h to pick up macros
01s,14may08,jpb Modifications for source build. Renamed
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
01r,19nov03,to added intDisconnect() functionality
01q,24jan02,pch Fix Diab warnings
01p,24aug98,cjtc windview 2.0 event logging is now single step. Timestamp no
longer stored by intEnt. Avoids out-of-sequence timestamps in
event log (SPR 21868)
01o,16apr98,pr moved triggering support from arch/ppc
01n,08apr98,pr modified support for WindView 20
01m,07aug97,tam fixed critical exception handling (SPR #8964).
01l,10jun97,wlf doc: more cleanup.
01k,31mar97,tam clear DMA interrupts properly in sysPpc403IntHandler(SPR 8285)
01j,19mar97,tam mask CE bit as well (SPR 8192). Removed while loop in
sysPpc403IntEnable() & sysPpc403IntDisable().
01i,09dec96,tpr changed _func_intEnableRtn() & _func_intDisableRtn() return
type from void to int.
Added sysPpc403IntEnable() & sysPpc403IntDisable() return
code.
01h,15nov96,wlf doc: cleanup.
01g,11jul96,pr included eventP.h
01f,11jul96,pr added windview instrumentation
01e,11jul96,tam modified sysPpc403IntHandler to enable nested interrupt.
01d,18mar96,tam added sysPpc403IntEnable/Disable and cleanup.
01c,28feb96,tam renamed and moved src/arch/ppc/intPpp403Lib.c to
src/drv/intrCtl/ppc403Intr.c.
01b,09feb95,yao enabled nested interrupt.
01a,28nov94,yao created.
*/
/*
This library provides various interface routines to manipulate and connect
to external hardware interrupts for the PPC403GA Embedded Controller.
*/
#include <vxWorks.h>
#include <vsbConfig.h>
#include <logLib.h>
#include <stdio.h>
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
#include <private/eventP.h>
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
/* defines */
#define INT_LEVEL_MAX 31
#define INT_LEVEL_MIN 0
/* externals */
/* globals */
void sysPpc403IntHandler (void);
/* locals */
LOCAL VOIDFUNCPTR sysIntBlTbl [32] = {(VOIDFUNCPTR) NULL};
LOCAL int sysIntArg [32] = {0};
/* forward LOCAL functions declarations */
LOCAL STATUS sysPpc403IntConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine,
int parameter);
LOCAL STATUS sysPpc403IntDisconnect (VOIDFUNCPTR * vector,
VOIDFUNCPTR routine, int parameter);
LOCAL int sysPpc403IntEnable (int intLevel);
LOCAL int sysPpc403IntDisable (int intLevel);
/*******************************************************************************
*
* sysPpc403IntrInit - initialize the PPC403GA interrupt facility
*
* This routine initializes the interrupt facility for the PPC403GA Embedded
* Controller.
*
* RETURNS: OK, always.
*/
STATUS sysPpc403IntrInit (void)
{
/* set the BSP driver specific Interrupt Handler and intConnect routines */
_func_intConnectRtn = sysPpc403IntConnect;
_func_intDisconnectRtn = sysPpc403IntDisconnect;
_func_intEnableRtn = sysPpc403IntEnable;
_func_intDisableRtn = sysPpc403IntDisable;
return (OK);
}
/*******************************************************************************
*
* sysPpc403IntConnect - connect a C routine to a hardware interrupt
*
* This routine connects a specified C routine to a specified
* interrupt vector. It is called by intConnect().
*
* The PPC403GA Embedded Controller does not provide vectors for external
* interrupts. Instead, vectors are assigned according to the bits in the
* External Interrupt Enable Register (EXIER).
* In case of DMA interrupts, the DMA Status register is always passed to
* the ISR as the argument <parameter>.
*
* RETURNS: OK, or ERROR if <vector> is out of range.
*
* SEE ALSO: intConnect(), sysPpc403IntHandler()
*/
LOCAL STATUS sysPpc403IntConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
if (((int)vector > INT_LEVEL_MAX) || ((int)vector < INT_LEVEL_MIN))
return (ERROR);
else
{
sysIntBlTbl[(int)vector] = routine;
sysIntArg[(int)vector] = parameter;
return (OK);
}
}
/*******************************************************************************
*
* sysPpc403IntDisconnect - disconnect a C routine from a hardware interrupt
*
* This routine disconnects a specified C routine from a specified
* interrupt vector. It is called by intDisconnect().
*
* RETURNS: OK, or ERROR if <vector> is out of range.
*
* SEE ALSO: intDisconnect(), sysPpc403IntHandler()
*/
LOCAL STATUS sysPpc403IntDisconnect
(
VOIDFUNCPTR * vector, /* interrupt vector to detach from */
VOIDFUNCPTR routine, /* routine to be disconnected */
int parameter /* parameter to be matched */
)
{
if (((int)vector > INT_LEVEL_MAX) || ((int)vector < INT_LEVEL_MIN))
return (ERROR);
else
{
sysIntBlTbl[(int)vector] = (VOIDFUNCPTR) NULL;
sysIntArg[(int)vector] = 0;
return (OK);
}
}
/*******************************************************************************
*
* sysPpc403IntHandler - PPC403GA external interrupt handler
*
* This is the external interrupt handler for the PPC403GA
* Embedded Controller.
* In case of DMA interrupts, the DMA Status register is always passed to
* the ISR, that was connected to the DMA interrupt via intConnect(), as an
* argument.
*
* RETURNS: N/A
*/
void sysPpc403IntHandler (void)
{
int vector;
INT32 exisr;
INT32 exier;
UINT32 dmaSrVal = 0; /* DMA Status reg. value */
/* get interrupts status and interrupt control register */
exisr = vxExisrGet ();
exier = vxExierGet ();
exisr = exisr & exier;
/* get interrupt number */
vector = vxFirstBit (exisr);
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
WV_EVT_INT_ENT(vector)
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
if (vector <= INT_LEVEL_MAX)
{
/* is this a DMA interrupt ? */
if ((vector > 7) && (vector < 12))
{
/*
* got a DMA interrupt: clear DMASR[CSX,TSX,RIX,CTX] bits for
* DMA channel X before interrupts are re-enabled.
* Pass the DMA status register to the ISR that processes the
* DMA interrupt for channel X.
* This does prevent passing another argument than DMASR to the
* ISR via intConnect, only for the DMA interrupts. However it
* enables the ISR to detect the cause of the interrupt according
* to DMASR.
*/
dmaSrVal = vxDmasrGet();
vxDmasrSet (dmaSrVal & ((0x88880040 >> (vector -8)) & 0xfff80070));
sysIntArg[vector] = (UINT32) dmaSrVal;
}
/* clear the interrupt status bit */
vxExisrClear (1 << (INT_LEVEL_MAX - vector));
/*
* Mask this and lower priority interrupt levels:
* the critical interrupt has the highest priority while the
* external interrupt 4 has the lowest priority (cf EXIER reg.).
*/
vxExierSet ((0xFFFFFFFF << (INT_LEVEL_MAX+1 - vector)) & vxExierGet());
/*
* enable interrupt nesting: an external interrupt cannot be nested
* with a critical interrupt (CINT or watchdog int.) due to the
* implementation of the support for critical interrupt. However
* critical interrupts may be nested with each other.
*/
if (vector == 0)
intUnlock (_PPC_MSR_CE);
else
intUnlock (_PPC_MSR_EE | _PPC_MSR_CE);
if (sysIntBlTbl [vector] != (VOIDFUNCPTR) NULL)
(*sysIntBlTbl [vector]) (sysIntArg[vector]);
else
logMsg ("uninitialized interrupt vector %d\n", vector, 0,0,0,0,0);
/* re-enable interrupt mask */
vxExierSet (exier);
}
}
/*******************************************************************************
*
* sysPpc403IntDisable - disable an external interrupt level
*
* This routine disables a specified external interrupt for the PPC403GA
* Embedded Controller.
*
* RETURNS: OK, or ERROR if <intLevel> is not in the range 0 - 31.
*
* SEE ALSO: sysPpc403IntEnable()
*/
LOCAL int sysPpc403IntDisable
(
int intLevel /* interrupt level to disable */
)
{
UINT32 intMask;
if (intLevel > INT_LEVEL_MAX || intLevel < INT_LEVEL_MIN)
return (ERROR);
intMask = 1 << (INT_LEVEL_MAX - intLevel);
/* disable the interrupt level */
vxExierDisable (intMask);
vxExisrClear (intMask); /* clear pending interrupts */
return (OK);
}
/*******************************************************************************
*
* sysPpc403IntEnable - enable an external interrupt level
*
* This routine enables a specified external interrupt for the PPC403GA
* Embedded Controller.
*
* RETURNS: OK, or ERROR if <intLevel> is not in the range 0 - 31.
*
* SEE ALSO: sysPpc403IntDisable()
*/
LOCAL int sysPpc403IntEnable
(
int intLevel /* interrupt level to enable */
)
{
UINT32 intMask;
if (intLevel > INT_LEVEL_MAX || intLevel < INT_LEVEL_MIN)
return (ERROR);
intMask = 1 << (INT_LEVEL_MAX - intLevel);
vxExisrClear (intMask); /* clear pending interrupts */
/* enable the interrupt level */
vxExierEnable (intMask);
return (OK);
}
@@ -0,0 +1,520 @@
/* ppc860Intr.c - PowerPC 800 series interrupt driver */
/* Copyright 1997,1998 Motorola, Inc., All Rights Reserved */
/*
* Copyright (c) 1984-2005, 2008 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use of this
* software may be licensed only pursuant to the terms of an applicable Wind
* River license agreement.
*/
/*
modification history
--------------------
01n,27aug08,jpb Renamed VSB header file
01m,18jul08,kk added inclusion of private/vsbConfigP.h to pick up macros
01l,14may08,jpb Modifications for source build. Renamed
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
01k,08mar05,mig do not allow equal or lower priority interrupts [SPR# 106795]
01j,17nov03,to added intDisconnect() functionality
01i,28jan02,dtr Removing diab warnings.
01h,15sep01,dat Removed special def of CACHE_PIPE_FLUSH
01g,28apr99,dat Merge from 2_0_0
01o,30jan99,cn fixed SPR #22321.
01n,24aug98,cjtc windview 2.0 event logging is now single step. Timestamp no
longer stored by intEnt. Avoids out-of-sequence timestamps in
event log (SPR 21868)
0lm,12aug98,gls corrected assignment of evtIntNum
01l,04aug98,gls fixed SPR #21239, kernel locks on boot when instrumented
01k,16apr98,pr added WindView 20 instrumentation.
01j,30mar98,map initialize _func_int{Enable,Disable}Rtn [SPR# 20447]
01i,26mar98,map added ppc860IntEnable, ppc860IntDisable, removed duplicate
#ifdef'd code, reworked ppc860IntrInit(). [SPR# 20447]
01h,11nov97,map redo clearing CISR bits [SPR# 8781], and default SCC
interrupt priority
01g,23jun97,map added default SCC interrupt priority [SPR# 8692]
01f,19jun97,map added IV_SCC[34] definitions [SPR# 8450]
01e,17jun97,map fixed clearing CISR bits [SPR# 8781]
01d,06mar97,tpr fixed properly SPR #8042.
01c,21feb97,tpr fixed interrupt bit clearing in CISR (SPR #8042).
01b,18sep96,pr added WindView instrumentation.
01a,17feb96,tpr written.
*/
/*
DESCRIPTION
The PowerPC 800 CPU series is divided in three units: PowerPC core, System
Interface Unit (SIU) and Communication Processor Unit (CPM). The PowerPC
core accepts only one external interrupt exception (vector 0x500). The SIU
provides an interrupt controller which provides 32 levels but only 16 are
used. The Interrupt controller is connected to the PowerPC core external
interrupt. The CPM unit also provides an interrupt controller which can
be connected to one of the SIU interrupt controller entries. This library
provides the routines to manage these interrupt controllers
ppc860IntrInit() connects the default demultiplexers, ppc860IntrDeMux() and
ppc860CpmIntrDeMux(), to the external interrupt vector and initializes a table
containing a function pointer and an associated parameter for each interrupt
source. ppc860IntrInit() is called by sysHwInit() from sysLib.c.
The default demultiplexer, ppc860IntrDeMux() detects which peripheral or
controller has raised an interrupt and calls the associated routine with its
parameter. If the interrupt comes from the CPM interrupt controller, the
ppc860CpmIntDeMux() function is called. As ppc860IntrDeMux(), this function
detects which peripheral or controller has raised an interrupt and calls the
associated routine with its parameter.
INCLUDE FILES: drv/intrCtl/ppc860Intr.h, drv/multi/ppc860Siu.h,
drv/multi/ppc860Cpm.h
*/
/* includes */
#include <vsbConfig.h>
#include <intLib.h>
#include <iv.h>
#include <drv/intrCtl/ppc860Intr.h>
#include <drv/multi/ppc860Siu.h>
#include <drv/multi/ppc860Cpm.h>
/* default SCC relative interrupt priority */
#define CICR_SCCP_DEF (CICR_SCCDP_SCC4 | CICR_SCCCP_SCC3 | \
CICR_SCCBP_SCC2 | CICR_SCCAP_SCC1 )
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
#include <private/funcBindP.h>
#include <private/eventP.h>
LOCAL int cpmIntNum;
LOCAL int cpmVecNum;
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
/* local */
LOCAL INTR_HANDLER intrVecTable[NUM_VEC_MAX]; /* Intr vector table */
LOCAL VOIDFUNCPTR defaultVec; /* INTR3 default vector */
/* forward declarations */
LOCAL void ppc860IntrDeMux (void);
LOCAL void ppc860CpmIntrDeMux (int);
LOCAL STATUS ppc860IntConnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
LOCAL STATUS ppc860IntDisconnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
LOCAL int ppc860IntEnable (int);
LOCAL int ppc860IntDisable (int);
/*******************************************************************************
*
* ppc860IntrInit - initialize the interrupt manager for the PowerPC 800 series
*
* This routine connects the default demultiplexers, ppc860IntrDeMux() and
* ppc860CpmIntrDeMux, to the external interrupt vector and associates all
* interrupt sources with the default interrupt handler. This routine is
* called by sysHwInit() in sysLib.c.
*
* NOTE: All interrupt from the SIU and CPM unit are enabled, CICR is setup so
* that SCC1 has the highest relative interrupt priority, through SCC4 with the
* lowest.
*
* RETURN : OK or ERROR if the SUI interrupt level to connect the CPM
* interrupt controller is wrong.
*/
STATUS ppc860IntrInit
(
VOIDFUNCPTR * cpmIntrVec /* Intr level of the CPM Intr ctrl */
)
{
UINT32 regBase; /* device register base address */
UINT32 cicrIntLevel; /* CICR interrupt level */
UINT32 simaskIntLevel;
int vector;
/* Get the default vector connected to the External Interrupt (0x500) */
defaultVec = (VOIDFUNCPTR) excVecGet ((FUNCPTR *) _EXC_OFF_INTR);
/* Connect the interrupt demultiplexer to External Interrupt (0x500) */
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, ppc860IntrDeMux);
/* Install `system' intConnect routine */
if (_func_intConnectRtn == NULL)
_func_intConnectRtn = ppc860IntConnect;
if (_func_intDisconnectRtn == NULL)
_func_intDisconnectRtn = ppc860IntDisconnect;
if (_func_intEnableRtn == NULL)
_func_intEnableRtn = ppc860IntEnable;
if (_func_intDisableRtn == NULL)
_func_intDisableRtn = ppc860IntDisable;
/* Set all vectors to default handler */
for (vector = 0; vector < NUM_VEC_MAX; vector++)
ppc860IntConnect (INUM_TO_IVEC(vector), defaultVec, 0);
/* Get the CPM interrupt level */
switch (IVEC_TO_INUM(cpmIntrVec))
{
case IVEC_TO_INUM(IV_LEVEL0):
cicrIntLevel = CICR_IRL_LVL0;
simaskIntLevel = SIMASK_LVM0;
break;
case IVEC_TO_INUM(IV_LEVEL1):
cicrIntLevel = CICR_IRL_LVL1;
simaskIntLevel = SIMASK_LVM1;
break;
case IVEC_TO_INUM(IV_LEVEL2):
cicrIntLevel = CICR_IRL_LVL2;
simaskIntLevel = SIMASK_LVM2;
break;
case IVEC_TO_INUM(IV_LEVEL3):
cicrIntLevel = CICR_IRL_LVL3;
simaskIntLevel = SIMASK_LVM3;
break;
case IVEC_TO_INUM(IV_LEVEL4):
cicrIntLevel = CICR_IRL_LVL4;
simaskIntLevel = SIMASK_LVM4;
break;
case IVEC_TO_INUM(IV_LEVEL5):
cicrIntLevel = CICR_IRL_LVL5;
simaskIntLevel = SIMASK_LVM5;
break;
case IVEC_TO_INUM(IV_LEVEL6):
cicrIntLevel = CICR_IRL_LVL6;
simaskIntLevel = SIMASK_LVM6;
break;
case IVEC_TO_INUM(IV_LEVEL7):
cicrIntLevel = CICR_IRL_LVL7;
simaskIntLevel = SIMASK_LVM7;
break;
default:
return (ERROR);
}
/*
* Connect the CPM interrupt demultiplexer at the level specified by
* `cpmIntLevel'
*/
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
cpmVecNum = IVEC_TO_INUM(cpmIntrVec);
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
intConnect (cpmIntrVec, ppc860CpmIntrDeMux, simaskIntLevel);
/* Get the register base address */
regBase = vxImmrGet();
/*
* Set the request interrupt level from the CPM and enable CPM interrupt
* generation.
*/
* CICR(regBase) = (CICR_SCCP_DEF | cicrIntLevel | CICR_IEN | CICR_HP_MSK);
/* Enable required CPM interrupt */
* SIMASK(regBase) = simaskIntLevel;
return (OK);
}
/*******************************************************************************
*
* ppc860IntConnect - connect a routine to an interrupt
*
* This routine connects any C or assembly routine to one of the multiple
* sources of interrupts.
*
* The connected routine can be any normal C code, except that it must not
* invoke certain operating system functions that may block or perform I/O
* operations.
*
* <vector> types are defined in h/drv/intrClt/ppc860Intr.h.
*
* RETURNS: OK, or ERROR if <vector> is unknown.
*
* SEE ALSO: ppc860Intr.h
*/
LOCAL STATUS ppc860IntConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
/* test the vector */
if (IVEC_TO_INUM(vector) >= NUM_VEC_MAX)
return (ERROR);
intrVecTable[IVEC_TO_INUM(vector)].vec = routine;
intrVecTable[IVEC_TO_INUM(vector)].arg = parameter;
return (OK);
}
/*******************************************************************************
*
* ppc860IntDisconnect - disconnect a routine from an interrupt
*
* This routine disconnects a routine from one of the multiple sources of
* interrupts.
*
* <vector> types are defined in h/drv/intrClt/ppc860Intr.h.
*
* RETURNS: OK, or ERROR if <vector> is unknown.
*
* SEE ALSO: ppc860Intr.h
*/
LOCAL STATUS ppc860IntDisconnect
(
VOIDFUNCPTR * vector, /* interrupt vector to detach from */
VOIDFUNCPTR routine, /* routine to be disconnected */
int parameter /* parameter to be matched */
)
{
/* test the vector */
if (IVEC_TO_INUM(vector) >= NUM_VEC_MAX)
return (ERROR);
intrVecTable[IVEC_TO_INUM(vector)].vec = defaultVec;
intrVecTable[IVEC_TO_INUM(vector)].arg = 0;
return (OK);
}
/*******************************************************************************
*
* ppc860IntrDeMux - SIU interrupt demultiplexer
*
* This routine must be bound to external interrupt exception (vector 0x500).
* It is used to call the appropriate handler with its argument when an
* interrupt occurs.
*
* The interrupts are prioritized in the following order:
*
* NOTE: when this function is called the interrupts are still locked. It's
* this function's responsibility to unlock the interrupt.
*
* RETURNS: N/A
*/
LOCAL void ppc860IntrDeMux (void)
{
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
UINT32 evtIntNum; /* windview interrupt vector */
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
UINT8 intVec; /* interrupt vector */
UINT32 regBase; /* register Base Address */
UINT32 intMask; /* current interrupt mask */
regBase = vxImmrGet();
/* read the interrupt vector register */
intVec = (* SIVEC(regBase)) >> 26;
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
/*
* if it is a cpm interrupt we need to know the corresponding cpm
* level, that we should get from the CPM demultiplexer. But we
* need the value here and the value can be read only once. We
* save the value here so that once the CPM demultiplexer is called,
* it will read the value from the global variable cpmIntNum.
*
* Since we do not know the CPM level a priori, we have to leave
* enough space for the cpm interrupts in the windview list.
* Therefore, any interrupt number bigger than the CPM level will
* be increased of 15 so to leave those spots to the corresponding
* CPM interrupts.
*/
if (intVec == cpmVecNum)
{
/* acknowledge the interrupt */
*CIVR(regBase) = CIVR_IACK;
CACHE_PIPE_FLUSH ();
cpmIntNum = * CIVR(regBase) >> 11;
evtIntNum = cpmIntNum + 32;
}
else
evtIntNum = intVec;
WV_EVT_INT_ENT(evtIntNum)
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
/* save the current interrupt mask */
intMask = * SIMASK(regBase);
/* lock all levels inferior to the interrupt detected */
* SIMASK(regBase) &= (0xffffffff << (32 - intVec));
/* unlock the interrupt */
intUnlock (_PPC_MSR_EE);
/* call the Interrupt Handler */
intrVecTable[intVec].vec (intrVecTable[intVec].arg);
/*
* lock interrupts to ensure no equal or lower priority interrupts
* occur prior to exiting the isr. SPR 106795
*/
intLock();
/* restore the interrupt mask */
* SIMASK(regBase) = intMask;
return;
}
/*******************************************************************************
*
* ppc860CpmIntrDeMux - CPM interrupt demultiplexer
*
* This routine must be bound to external interrupt exception (vector 0x500).
* It is used to call the appropriate handler with its argument when an
* interrupt occurs.
*
* The interrupts are prioritized in the following order:
*
* RETURNS: N/A
*/
LOCAL void ppc860CpmIntrDeMux
(
int simaskLevel
)
{
int intNum; /* interrupt number */
UINT32 regBase; /* register Base Address */
UINT32 intOldMask; /* interrupt mask before the interrupt*/
/* get the device register base address */
regBase = vxImmrGet();
/* get the interrupt vector */
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
intNum = cpmIntNum;
#else
/* acknowledge the interrupt */
* CIVR(regBase) = CIVR_IACK;
intNum = * CIVR(regBase) >> 11;
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
/* save the interrupt mask before the interrupt */
intOldMask = * CIMR(regBase);
/* lock all levels inferior to the interrupt detected */
* CIMR(regBase) &= (0xffffffff << (intNum + 1));
/* enable the CPM interrupt in the SIU controller */
* SIMASK(regBase) |= simaskLevel;
/* call the Interrupt Handler */
intrVecTable[intNum + 32].vec (intrVecTable[intNum + 32].arg);
/* clear the bit in the CISR */
* CISR(regBase) = (1 << intNum);
/* restore the interrupt mask */
* CIMR(regBase) = intOldMask;
}
/*******************************************************************************
*
* ppc860IntEnable - enable one of the Level or IRQ interrupts into the SIU
*
* This routine will unmask the bit in the SIMASK register corresponding to
* the requested interrupt level. The interrupt level must be in the range
* of 0 - 31.
*
* RETURNS: 0, always.
*/
LOCAL int ppc860IntEnable
(
int intNum /* interrupt level to enable (0 - 31) */
)
{
UINT32 regBase;
regBase = vxImmrGet();
if ((intNum >= 0) && (intNum < 32))
* SIMASK(regBase) |= (1 << (31 - intNum));
return 0;
}
/*******************************************************************************
*
* ppc860IntDisable - Disable one of the Level or IRQ interrupts into the SIU
*
* This routine will mask the bit in the SIMASK register corresponding to
* the requested interrupt level. The interrupt level must be in the range
* of 0 - 31.
*
* RETURNS: 0, always.
*/
LOCAL int ppc860IntDisable
(
int intNum /* interrupt level to disable (0 - 31) */
)
{
UINT32 regBase;
regBase = vxImmrGet();
if ((intNum >= 0) && (intNum < 32))
* SIMASK(regBase) &= ~(1 << (31 - intNum));
return 0;
}
@@ -0,0 +1,485 @@
/* qeIntrCtl.c - Quicc Engine interrupt controller driver */
/*
* Copyright (c) 2008-2009 Wind River Systems, Inc.
*
* The right to copy, distribute, modify, or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01e,09oct09,rgo Fix quicc interrupt range for both enable/disable func(
CQ:156433 )
01d,27aug08,jpb Renamed VSB header file
01c,18jul08,kk added inclusion of private/vsbConfigP.h to pick up macros
01b,14may08,jpb Modifications for source build. Renamed
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
01a,20sep07,z_l Fix interrupt number error(WIND00105278)
*/
/*
DESCRIPTION
INCLUDE FILES: qeIntrCtl.h
*/
/* includes */
#include <vsbConfig.h>
#include <intLib.h>
#include <iv.h>
#include <drv/intrCtl/quiccIntrCtl.h>
#include <drv/intrCtl/qeIntrCtl.h>
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
#include "private/funcBindP.h"
#include "private/eventP.h"
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
/* defines */
#define QE_CIMR_MASK_GTEQ_L 0
#define QE_CIMR_MASK_LTEQ_L 15
#define QE_CIMR_MASK_GTEQ_U 32
#define QE_CIMR_MASK_LTEQ_U 47
#error "included"
/* local */
LOCAL QE_INTR_HANDLER qeIntrVecTable[QE_IVEC_MAX+1]; /* Intr vector table */
/* SIU Interrupt Mask structure; a value for the high and low parts */
typedef struct qe_siu_int_mask
{
UINT32 crimr;
UINT32 cimr;
} QE_SIU_INT_MASK;
/*
* for now do not allow interruption of interrupt processing
*/
LOCAL QE_SIU_INT_MASK qeEnableHighPriInts[] =
{
{0x00000000, 0x00000000}, /* interrupt 0 error - enable nothing */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000}, /* */
{0x00000000, 0x00000000},
{0x00000000, 0x00000000}
};
LOCAL UINT32 qeINumToMaskPattern[] =
{
0x00000000, /* interrupt number 0: Error */
0x00008000, /* interrupt number 1: I2C */
0x00004000, /* interrupt number 2: SPI */
0x00002000, /* interrupt number 3: Risc Timer Table */
0x00000000, /* interrupt number 4: */
0x00000000, /* interrupt number 5: */
0x00000000, /* interrupt number 6: */
0x00000000, /* interrupt number 7: */
0x00000000, /* interrupt number 8: */
0x00000000, /* interrupt number 9: */
0x00000040, /* interrupt number 10: SDMA */
0x00000020, /* interrupt number 11: USB */
0x00000010, /* interrupt number 12: Timer 1 */
0x00000008, /* interrupt number 13: Timer 2 */
0x00000004, /* interrupt number 14: Timer 3 */
0x00000002, /* interrupt number 15: Timer 4 */
0x00000000, /* interrupt number 16: */
0x00000000, /* interrupt number 17: */
0x00000000, /* interrupt number 18: */
0x00000000, /* interrupt number 19: */
0x10000000, /* interrupt number 20: VT*/
0x00000000, /* interrupt number 21: */
0x00000000, /* interrupt number 22: */
0x00000000, /* interrupt number 23: */
0x00000000, /* interrupt number 24: */
0x00800000, /* interrupt number 25: EXT1 */
0x00400000, /* interrupt number 26: EXT2 */
0x00200000, /* interrupt number 27: EXT3 */
0x00100000, /* interrupt number 28: EXT4 */
0x00000000, /* interrupt number 29: */
0x00000000, /* interrupt number 30: */
0x00000000, /* interrupt number 31: */
0x80000000, /* interrupt number 32: UCC1 */
0x40000000, /* interrupt number 33: UCC2 */
0x20000000, /* interrupt number 34: UCC3 */
0x10000000, /* interrupt number 35: UCC4 */
0x08000000, /* interrupt number 36: MCC1 */
0x00000000, /* interrupt number 37: */
0x00000000, /* interrupt number 38: */
0x00000000, /* interrupt number 39: */
0x00800000, /* interrupt number 40: UCC5 */
0x00400000, /* interrupt number 41: UCC6 */
0x00200000, /* interrupt number 42: UCC7 */
0x00100000, /* interrupt number 43: UCC8 */
0x00000000, /* interrupt number 44: */
0x00000000, /* interrupt number 45: */
0x00000000, /* interrupt number 46: */
0x00000000, /* interrupt number 47: */
0x00000000, /* interrupt number 48: */
0x00000000, /* interrupt number 49: */
0x00000000, /* interrupt number 50: */
0x00000000, /* interrupt number 51: */
0x00000000, /* interrupt number 52: */
0x00000000, /* interrupt number 53: */
0x00000000, /* interrupt number 54: */
0x00000000, /* interrupt number 55: */
0x00000000, /* interrupt number 56: reserved */
0x00000000, /* interrupt number 57: reserved */
0x00000000, /* interrupt number 58: reserved */
0x00000000, /* interrupt number 59: reserved */
0x00000000, /* interrupt number 60: reserved */
0x00000000, /* interrupt number 61: reserved */
0x00000000, /* interrupt number 62: reserved */
0x00000000 /* interrupt number 63: reserved */
};
/* forward declarations */
LOCAL void qeIntrDeMux (void);
LOCAL STATUS qeIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
LOCAL BOOL qeIntFirstTime = TRUE;
void qeDefaultISR(int vector)
{
logMsg("Spurious interrupt 0x%x\n",vector,0,0,0,0,0);
}
BOOL qeTest1=0;
BOOL qeTest2=0;
/*******************************************************************************
*
* qeIntrInit - initialize the interrupt manager for the PowerPC 8260
*
* This routine connects the default demultiplexer, qeIntrDeMux(), to the
* external interrupt vector and associates all
* interrupt sources with the default interrupt handler. This routine is
* called by sysHwInit() in sysLib.c.
*
* NOTE: All interrupt from the SIU unit are enabled, CICR is setup so
* that SCC1 has the highest relative interrupt priority, through SCC4 with the
* lowest.
*
* RETURN : OK always
*/
STATUS qeIntrInit
(
)
{
VOIDFUNCPTR defaultVec; /* INTR3 default vector */
int vector;
/* Get the default vector connected to the External Interrupt (0x500) */
defaultVec = qeDefaultISR;
/* disable all interrupts */
*QE_CIMR(CCSBAR) = 0x00000000;
*QE_CRIMR(CCSBAR) = 0x00000000;
/* Set all vectors to default handler */
memset (qeIntrVecTable,0,(sizeof(QE_INTR_HANDLER) * QE_IVEC_MAX));
/* Set all vectors to default handler */
for (vector = 0; vector < QE_IVEC_MAX; vector++)
qeIntConnect ((VOIDFUNCPTR*)vector, (VOIDFUNCPTR) defaultVec, 0);
return (OK);
}
/*******************************************************************************
*
* qeIntConnect - connect a routine to an interrupt
*
* This routine connects any C or assembly routine to one of the multiple
* sources of interrupts.
*
* The connected routine can be any normal C code, except that it must not
* invoke certain operating system functions that may block or perform I/O
* operations.
*
* <vector> types are defined in h/drv/intrClt/qeIntr.h.
*
* RETURNS: OK, or ERROR if <vector> is unknown.
*
* SEE ALSO: qeIntr.h
*/
LOCAL STATUS qeIntConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
if ((int)(vector) >= QE_IVEC_MAX)
return (ERROR);
/* test the vector */
if(qeIntFirstTime)
{
intConnect((VOIDFUNCPTR*)INUM_QE_HIGH,qeIntrDeMux,0);
intConnect((VOIDFUNCPTR*)INUM_QE_LOW,qeIntrDeMux,0);
intEnable(INUM_QE_HIGH);
intEnable(INUM_QE_LOW);
qeIntFirstTime=FALSE;
}
qeIntrVecTable[(int)(vector)].vec = routine;
qeIntrVecTable[(int)(vector)].arg = parameter;
return (OK);
}
/*******************************************************************************
*
* qeIntrDeMux - SIU interrupt demultiplexer
*
* This routine must be bound to external interrupt exception (vector 0x500).
* It is used to call the appropriate handler with its argument when an
* interrupt occurs.
*
* The interrupts are prioritized in the following order:
*
* NOTE: when this function is called the interrupts are still locked. It's
* this function responsability to unlock the interrupt.
*
* RETURNS: N/A
*/
LOCAL void qeIntrDeMux (void)
{
VINT32 intVec; /* interrupt vector */
UINT32 oldIntMask_L; /* current interrupt mask */
UINT32 oldIntMask_H; /* current interrupt mask */
UINT32 intLevel = _PPC_MSR_EE;
/* read the interrupt vector register */
intVec = (0x0000003f & *QE_CIVEC(CCSBAR));
*(VUINT32*)(0x3000) = intVec;
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
WV_EVT_INT_ENT(intVec)
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
if ( intVec != 0 )
{
/* save the current interrupt mask */
oldIntMask_L = * QE_CIMR(CCSBAR);
oldIntMask_H = * QE_CRIMR(CCSBAR);
/* enable only the higher priority interrupts */
* QE_CIMR(CCSBAR)&=
qeEnableHighPriInts[QE_IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].cimr;
* QE_CRIMR(CCSBAR)&=
qeEnableHighPriInts[QE_IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].crimr;
intUnlock (_PPC_MSR_EE);
/* call the Interrupt Handler */
/* table is indexed by vector */
qeIntrVecTable[intVec].vec (qeIntrVecTable[intVec].arg);
/* restore the interrupt mask */
intLevel = intLock ();
/* restore the interrupt mask */
* QE_CIMR(CCSBAR) = oldIntMask_L;
* QE_CRIMR(CCSBAR) = oldIntMask_H;
}
return;
}
/*******************************************************************************
*
* qeIntEnable - enable the indicated interrupt
*
* This routine will enable the indicated interrupt by setting the appropriate
* bit in the SIU Interrupt Mask Registers.
*
* The design of the 8260 presents the following design requirements:
*
* 1. the mapping from interrupt number to mask bit can not be represented by
* a function. An array, indexed by interrupt number (QE_INUM), is used to map
* the interrupt number to the appropriate mask.
*
* 2. There are two 32 bit mask registers (CIMR and CRIMR). The interrupt
* number must be compared to 4 ranges to determine which register contains
* its mask bit:
*
* .CS
* interrupt number
* in qeIntrCtl.h register
* ---------------- -------
* 0-15 CIMR
* 16-31 CRIMR
* 32-47 CIMR
* 48-63 CRIMR
* .CE
*
* RETURNS: 0, always.
*/
int qeIntEnable
(
int intNum /* interrupt level to enable */
)
{
if ((intNum > 0) && (intNum <= QE_IVEC_MAX))
{
if (((intNum >= QE_CIMR_MASK_GTEQ_L) && (intNum <= QE_CIMR_MASK_LTEQ_L)) ||
((intNum >= QE_CIMR_MASK_GTEQ_U) && (intNum <= QE_CIMR_MASK_LTEQ_U)))
*QE_CIMR(CCSBAR) |= qeINumToMaskPattern[intNum];
else
*QE_CRIMR(CCSBAR) |= qeINumToMaskPattern[intNum];
}
return 0;
}
/*******************************************************************************
*
* qeIntDisable - Disable one of the Level or IRQ interrupts into the SIU
*
* This routine will mask the bit in the SIMASK register corresponding to
* the requested interrupt level.
*
* RETURNS: 0, always.
*/
int qeIntDisable
(
int intNum /* interrupt level to disable */
)
{
if ((intNum >= 0) && (intNum <= QE_IVEC_MAX))
{
if (((intNum >= QE_CIMR_MASK_GTEQ_L) && (intNum <= QE_CIMR_MASK_LTEQ_L)) ||
((intNum >= QE_CIMR_MASK_GTEQ_U) && (intNum <= QE_CIMR_MASK_LTEQ_U)))
*QE_CIMR(CCSBAR) &= ~qeINumToMaskPattern[intNum];
else
*QE_CRIMR(CCSBAR) &= ~qeINumToMaskPattern[intNum];
}
return 0;
}
VOIDFUNCPTR * qeInumToIvec
(
int intNum
)
{
return((void*)intNum);
}
/*******************************************************************************
*
* qeIvecToInum - get the relevant interrupt number
*
* This routine finds out the interrupt number associated with the vector
* in <vector>.
*
* <vector> types are defined in h/drv/intrClt/qeIntr.h.
*
* RETURNS: the interrupt number for the vector
*
* SEE ALSO: qeIntr.h
*/
int qeIvecToInum
(
VOIDFUNCPTR * vector /* interrupt vector to attach to */
)
{
return ((int)vector);
}
@@ -0,0 +1,721 @@
/* quiccIntrCtl.c - Motorola MPC 83XX interrupt controller driver */
/*
* Copyright (c) 2005-2009, 2011, 2013 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01l,13jun13,d_l restore TSECn interrupt priority. (WIND00414331)
01k,19may11,swu Fix interrupt mask enableHighPriInts[].(WIND00270355)
01j,05feb09,jc0 removed internal interrupt acknowledge which does no effect
01i,07jan09,jc0 fix WIND00148619
01h,27aug08,jpb Renamed VSB header file
01g,18jul08,kk added inclusion of private/vsbConfigP.h to pick up macros
01f,14may08,jpb Modifications for source build. Renamed
INCLUDE_WINDVIEW to _WRS_CONFIG_SV_INSTRUMENTATION.
01e,05sep07,dtr WIND0092393 - Fix GTM masks.
01d,21mar06,mdo Fix overrun of array
01d,25may06,dtr Add support for 8360 processor.
01c,16may05,dtr IRQ0 mask in wrong vector - SPR 109357.
01b,19apr05,dtr Fix mask for USB - SPR 108220.
01a,10jan05,dtr adapted from m8260IntrCtl.
*/
/*
DESCRIPTION
The PowerPC 83XX CPU is divided in three units: PowerPC core, System
Interface Unit (SIU) and Communication Engine (CE). The PowerPC
core accepts only one external interrupt exception (vector 0x500). The SIU
provides an interrupt controller which provides 92 interrupt sources
The Interrupt controller is connected to the PowerPC core external
interrupt. This library provides the routines to manage this interrupt
controllers.
quiccIntrInit() connects the default demultiplexer, quiccIntrDeMux(), to the
external interrupt vector and initializes a table containing a function pointer
and an associated parameter for each interrupt source. quiccIntrInit() is called
by sysHwInit() from sysLib.c.
The default demultimplexer, quiccIntrDeMux() detects which peripheral or
controller has raised an interrupt and calls the associated routine with its
parameter.
INCLUDE FILES: quiccIntrCtl.h
*/
/* includes */
#include <vsbConfig.h>
#include <intLib.h>
#include <iv.h>
#include <drv/intrCtl/quiccIntrCtl.h>
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
#include <private/funcBindP.h>
#include <private/eventP.h>
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
/* local */
INTR_HANDLER intrVecTable[IVEC_MAX+1]; /* Intr vector table */
/* SIU Interrupt Mask structure; a value for the high and low parts */
typedef struct siu_int_mask
{
UINT32 simr_h;
UINT32 simr_l;
UINT32 semr;
} SIU_INT_MASK;
/*
* For a give inum, return a pair of masks, one for SIMR_H and one for SIMR_L,
* which enables only higher priority interrupts.
*/
LOCAL SIU_INT_MASK enableHighPriInts[] =
{
{0x00000000, 0x00000000, 0x00000000}, /* interrupt 0 error - enable nothing */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0xFF000000, 0xFF000000, 0xFF000000}, /* UART1 */
{0xFF000080, 0xFF000000, 0xFF000000}, /* UART2 */
{0xFF0000C0, 0xFF000000, 0xFF000000}, /* SEC */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0xFF0000E0, 0xFF000000, 0xFF000000}, /* I2C1 */
{0xFF0000E4, 0xFF000000, 0xFF000000}, /* I2C2 */
{0xFF0000E6, 0xFF000000, 0xFF000000}, /* SPI */
{0xFF000000, 0xFF000000, 0x80000000}, /* IRQ1 */
{0xFF000000, 0xFF000000, 0xC0000000}, /* IRQ2 */
{0xFF000000, 0xFF000000, 0xE0000000}, /* IRQ3 */
{0xFF000000, 0xFF000000, 0xF0000000}, /* IRQ4 */
{0xFF000000, 0xFF000000, 0xF8000000}, /* IRQ5 */
{0xFF000000, 0xFF000000, 0xFC000000}, /* IRQ6 */
{0xFF000000, 0xFF000000, 0xFE000000}, /* IRQ7 **23**/
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
#ifndef QUICC_ENGINE
{0x00000000, 0x00000000, 0x00000000}, /* TSEC1 Tx */
{0x00000000, 0x00000000, 0x00000000}, /* TSEC1 Rx */
{0x00000000, 0x00000000, 0x00000000}, /* TSEC1 Err */
{0x00000000, 0x00000000, 0x00000000}, /* TSEC2 Tx */
{0x00000000, 0x00000000, 0x00000000}, /* TSEC2 Rx */
{0x00000000, 0x00000000, 0x00000000}, /* TSEC2 Err */
#else
{0x00000000, 0x00000000, 0x00000000}, /* QE HOGH */
{0x00000000, 0x00000000, 0x00000000}, /* QE LOW */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved*/
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
#endif /* !QUICC_ENGINE */
{0xFC000000, 0xFF000000, 0x00000000}, /* USB2 DR */
{0xFE000000, 0xFF000000, 0x00000000}, /* USB2 MPH */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0xFF000000, 0xFF000000, 0x00000000}, /* IRQ0 ***48**/
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* RTC SEC */
{0x00000000, 0x80000000, 0x00000000}, /* PIT */
{0x00000000, 0xC0000000, 0x00000000}, /* PCI1 */
#ifndef QUICC_ENGINE
{0x00000000, 0xE0000000, 0x00000000}, /* PCI2 */
#else
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
#endif /* !QUICC_ENGINE */
{0x00000000, 0xF0000000, 0x00000000}, /* RTC ALR */
{0x00000000, 0xF8000000, 0x00000000}, /* MU */
{0x00000000, 0xFC000000, 0x00000000}, /* SBA */
{0x00000000, 0xFE000000, 0x00000000}, /* DMA */
{0xFF0000E7, 0xFF000000, 0xFF000000}, /* GTM4 */
{0xFF0000E7, 0xFF800000, 0xFF000000}, /* GTM8 */
{0xFF0000E7, 0xFFC00000, 0xFF000000}, /* CPIO1 */
{0xFF0000E7, 0xFFE00000, 0xFF000000}, /* GPIO2 */
{0xFF0000E7, 0xFFF00000, 0xFF000000}, /* DDR */
{0xFF0000E7, 0xFFF80000, 0xFF000000}, /* LBC */
{0xFF0000E7, 0xFFFC0000, 0xFF000000}, /* GTM2 */
{0xFF0000E7, 0xFFFE0000, 0xFF000000}, /* GTM6 */
{0xFF0000E7, 0xFFFF0000, 0xFF000000}, /* PMC */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0xFF0000E7, 0xFFFF8000, 0xFF000000}, /* GTM3 */
{0xFF0000E7, 0xFFFF8800, 0xFF000000}, /* GTM7 */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0xFF0000E7, 0xFFFF8C00, 0xFF000000}, /* GTM1 */
{0xFF0000E7, 0xFFFF8C20, 0xFF000000}, /* GTM5 */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000}, /* Reserved */
{0x00000000, 0x00000000, 0x00000000} /* Reserved */
};
LOCAL UINT32 iNumToMaskPattern[] =
{
0x00000000, /* interrupt number 0: Error */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000080, /* UART1 */
0x00000040, /* UART2 */
0x00000020, /* SEC */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000004, /* I2C1 */
0x00000002, /* I2C2 */
0x00000001, /* SPI */
0x40000000, /* IRQ1 */
0x20000000, /* IRQ2 */
0x10000000, /* IRQ3 */
0x08000000, /* IRQ4 */
0x04000000, /* IRQ5 */
0x02000000, /* IRQ6 */
0x01000000, /* IRQ7 **23**/
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x80000000, /* TSEC1 Tx */
0x40000000, /* TSEC1 Rx */
0x20000000, /* TSEC1 Err */
0x10000000, /* TSEC2 Tx */
0x08000000, /* TSEC2 Rx */
0x04000000, /* TSEC2 Err */
0x02000000, /* USB2 DR */
0x01000000, /* USB2 MPH */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x80000000, /* IRQ0 ***48**/
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x80000000, /* RTC SEC */
0x40000000, /* PIT */
0x20000000, /* PCI1 */
0x10000000, /* PCI2 */
0x08000000, /* RTC ALR */
0x04000000, /* MU */
0x02000000, /* SBA */
0x01000000, /* DMA */
0x00800000, /* GTM4 */
0x00400000, /* GTM8 */
0x00200000, /* CPIO1 */
0x00100000, /* GPIO2 */
0x00080000, /* DDR */
0x00040000, /* LBC */
0x00020000, /* GTM2 */
0x00010000, /* GTM6 */
0x00008000, /* PMC */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000800, /* GTM3 */
0x00000400, /* GTM7 */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000020, /* GTM1 */
0x00000010, /* GTM5 */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000, /* Reserved */
0x00000000 /* Reserved */
};
/* forward declarations */
LOCAL void quiccIntrDeMux (void);
LOCAL STATUS quiccIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR, int);
LOCAL VOIDFUNCPTR defaultVec; /* INTR3 default vector */
void defaultISR(int vector)
{
logMsg("Spurious interrupt 0x%x\n",vector,0,0,0,0,0);
}
/**************************************************************************
*
* quiccIntrInit - initialize the interrupt manager for the PowerPC 83XX
*
* This routine connects the default demultiplexer, quiccIntrDeMux(), to the
* external interrupt vector and associates all
* interrupt sources with the default interrupt handler. This routine is
* called by sysHwInit() in sysLib.c.
*
* NOTE: All interrupt from the SIU unit are enabled, CICR is setup so
* that SCC1 has the highest relative interrupt priority, through SCC4 with the
* lowest.
*
* RETURNS: OK always
*
* ERRNO
*/
STATUS quiccIntrInit (void)
{
int vector;
/* Get the default vector connected to the External Interrupt (0x500) */
defaultVec = defaultISR;
/* Connect the interrupt demultiplexer to External Interrupt (0x500) */
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, quiccIntrDeMux);
#ifndef USE_MUX_LAYER
/* Install `system' intConnect routine */
if (_func_intConnectRtn == NULL)
_func_intConnectRtn = quiccIntConnect;
if (_func_intEnableRtn == NULL)
_func_intEnableRtn = quiccIntEnable;
if (_func_intDisableRtn == NULL)
_func_intDisableRtn = quiccIntDisable;
#endif /* !USE_MUX_LAYER */
/* Set all vectors to default handler */
memset (intrVecTable,0,(sizeof(INTR_HANDLER) * (IVEC_MAX + 1)));
for (vector = 0; vector <= IVEC_MAX; vector++)
quiccIntConnect (INUM_TO_IVEC(vector), (VOIDFUNCPTR) defaultVec, vector);
/* disable all interrupts */
*QUICC_SIMR_L(CCSBAR) = 0x00000000;
*QUICC_SIMR_H(CCSBAR) = 0x00000000;
*QUICC_SEMSR(CCSBAR) = 0x00000000;
return(OK);
}
/*************************************************************************
*
* quiccIntConnect - connect a routine to an interrupt
*
* This routine connects any C or assembly routine to one of the multiple
* sources of interrupts.
*
* The connected routine can be any normal C code, except that it must not
* invoke certain operating system functions that may block or perform I/O
* operations.
*
* <vector> types are defined in h/drv/intrClt/quiccIntr.h.
*
* RETURNS: OK, or ERROR if <vector> is unknown or memory can't be allocated.
*
* ERRNO
*
* SEE ALSO: quiccIntr.h
*/
LOCAL STATUS quiccIntConnect
(
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
VOIDFUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
)
{
/* test the vector */
if ((int)(vector) > IVEC_MAX)
return(ERROR);
if ((intrVecTable[(int)(vector)].vec == defaultVec) ||
(intrVecTable[(int)(vector)].vec == NULL))
{
intrVecTable[(int)(vector)].vec = routine;
intrVecTable[(int)(vector)].arg = parameter;
}
else
{
if (intrVecTable[(int)(vector)].pNext!=NULL)
{
INTR_HANDLER *temp1Next,*temp2Next;
temp2Next = (INTR_HANDLER*)intrVecTable[(int)(vector)].pNext;
temp1Next = (INTR_HANDLER*)intrVecTable[(int)(vector)].pNext;
while (temp1Next !=NULL)
{
temp2Next = temp1Next;
temp1Next = (INTR_HANDLER*)temp2Next->pNext;
}
temp2Next->pNext = (void*)malloc (sizeof(INTR_HANDLER));
if (temp2Next->pNext == NULL)
return(ERROR);
((INTR_HANDLER*)temp2Next->pNext)->vec = routine;
((INTR_HANDLER*)temp2Next->pNext)->arg = parameter;
}
}
return(OK);
}
/**************************************************************************
*
* quiccIntrDeMux - SIU interrupt demultiplexer
*
* This routine must be bound to external interrupt exception (vector 0x500).
* It is used to call the appropriate handler with its argument when an
* interrupt occurs.
*
* The interrupts are prioritized in the following order:
*
* NOTE: when this function is called the interrupts are still locked. It's
* this function responsibility to unlock the interrupt.
*
* RETURNS: N/A
*
* ERRNO
*/
LOCAL void quiccIntrDeMux (void)
{
VINT32 intVec; /* interrupt vector */
UINT32 oldIntMask_L; /* current interrupt mask */
UINT32 oldIntMask_H; /* current interrupt mask */
UINT32 oldIntMask_E; /* current interrupt mask */
/* read the interrupt vector register */
intVec = (0x0000007f & (*QUICC_SIVEC(CCSBAR)));
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
WV_EVT_INT_ENT(intVec)
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
if ( intVec != 0 )
{
/* save the current interrupt mask */
oldIntMask_L = * QUICC_SIMR_L(CCSBAR);
oldIntMask_H = * QUICC_SIMR_H(CCSBAR);
oldIntMask_E = * QUICC_SEMSR(CCSBAR);
/* enable only the higher priority interrupts */
* QUICC_SIMR_L(CCSBAR) = oldIntMask_L &
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].simr_l;
* QUICC_SIMR_H(CCSBAR) = oldIntMask_H &
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].simr_h;
* QUICC_SEMSR(CCSBAR) = oldIntMask_E &
enableHighPriInts[IVEC_TO_INUM((VOIDFUNCPTR *)intVec)].semr;
/* ensure the interrupt mask registers are updated */
_WRS_ASM ("eieio");
intUnlock (_PPC_MSR_EE);
/* call the Interrupt Handler */
/* table is indexed by vector */
intrVecTable[intVec].vec (intrVecTable[intVec].arg);
if (intrVecTable[intVec].pNext !=NULL)
{
INTR_HANDLER *pNext;
pNext = (INTR_HANDLER*)intrVecTable[intVec].pNext;
while (pNext !=NULL)
{
pNext->vec (pNext->arg);
pNext = (INTR_HANDLER*)pNext->pNext;
}
}
if ( ((intVec >= 17) && (intVec <= 23)) || (intVec == 48) )
{
*QUICC_SEPNR(CCSBAR) = iNumToMaskPattern[intVec] ;
}
/* restore the interrupt mask */
intLock ();
* QUICC_SIMR_L(CCSBAR) = oldIntMask_L;
* QUICC_SIMR_H(CCSBAR) = oldIntMask_H;
* QUICC_SEMSR(CCSBAR) = oldIntMask_E;
/*
* Ensure the external interrupt is acknowledged and the
* interrupt mask registers are restored.
*/
_WRS_ASM ("eieio");
}
return;
}
/************************************************************************
*
* quiccIntEnable - enable the indicated interrupt
*
* This routine will enable the indicated interrupt by setting the appropriate
* bit in the SIU Interrupt Mask Registers.
*
* The design of the 83XX presents the following design requirements:
*
* 1. the mapping from interrupt number to mask bit can not be represented by
* a function. An array, indexed by interrupt number (INUM), is used to map
* the interrupt number to the appropriate mask.
*
* 2. There are two 32 bit mask registers (SIMR_L and SIMR_H). The interrupt
* number must be compared to 4 ranges to determine which register contains
* its mask bit:
*
* \cs
* interrupt number
* in quiccIntrCtl.h register
* ---------------- -------
* 0-15 SIMR_L
* 16-31 SIMR_H
* 32-47 SIMR_L
* 48-63 SIMR_H
* \ce
*
* RETURNS: 0, always.
*/
int quiccIntEnable
(
int intNum /* interrupt level to enable */
)
{
if ((intNum >= 0) && (intNum < IVEC_MAX))
{
if ((intNum >= 64) && (intNum < 128))
*QUICC_SIMR_L(CCSBAR) |= iNumToMaskPattern[intNum];
else
{
if ( ((intNum>=17) && (intNum<=31)) || (intNum == 48))
{
/* Use as external Mask */
*QUICC_SEMSR(CCSBAR) |= iNumToMaskPattern[intNum];
}
else
{
*QUICC_SIMR_H(CCSBAR) |= iNumToMaskPattern[intNum];
}
}
}
return 0;
}
/**************************************************************************
*
* quiccIntDisable - Disable one of the Level or IRQ interrupts into the SIU
*
* This routine will mask the bit in the SIMASK register corresponding to
* the requested interrupt level.
*
* RETURNS: 0, always.
*
* ERRNO
*/
int quiccIntDisable
(
int intNum /* interrupt level to disable */
)
{
if ((intNum >= 0) && (intNum < IVEC_MAX))
{
if ((intNum >= 64) && (intNum < 128))
*QUICC_SIMR_L(CCSBAR) &= ~iNumToMaskPattern[intNum];
else
{
if ( ((intNum>=17) && (intNum<=31)) || (intNum == 48))
{
/* Use as external Mask */
*QUICC_SEMSR(CCSBAR) &= ~iNumToMaskPattern[intNum];
}
else
{
*QUICC_SIMR_H(CCSBAR) &= ~iNumToMaskPattern[intNum];
}
}
}
return 0;
}
VOIDFUNCPTR * quiccInumToIvec
(
int intNum
)
{
return ((VOIDFUNCPTR *) intNum);
}
/**************************************************************************
*
* quiccIvecToInum - get the relevant interrupt number
*
* This routine finds out the interrupt number associated with the vector
* in <vector>.
*
* <vector> types are defined in h/drv/intrClt/quiccIntr.h.
*
* RETURNS: the interrupt number for the vector
*
* ERRNO
*
* SEE ALSO: quiccIntr.h
*/
int quiccIvecToInum
(
VOIDFUNCPTR * vector /* interrupt vector to attach to */
)
{
/* test the vector */
return ((int) vector);
}
@@ -0,0 +1,422 @@
/* templateIntrCtl.c - template interrupt controller driver */
/* Copyright 1984-1997, Wind River Systems, Inc. */
/*
TODO - Remove the template modification history and begin a new history
starting with version 01a and growing the history upward with
each revision.
modification history
--------------------
01e,23nov97,dat suggestions from Chris and arm code review.
01d,12aug97,dat more suggestions from Chris
01c,05aug97,dat suggestions from Chris Partington at CSD.
01b,06may97,dat added more documentation
01a,03apr97,dat written
*/
/*
TODO - This is a template driver for an interrupt controller. Each hardware
dependent function, variable, or macro name begins with TEMPLATE or template.
These names should be changed to a name based upon the final module name.
TODO - If this device is a sub-section of a larger device, describe the
entire larger device in one paragraph.
TODO - Describe this device including all possible operating modes and
limitations.
TODO - Describe the device modes and any limitations applicable to this driver.
If this driver interacts with any other driver describe that interaction.
TODO - Update the remainder of this documentation as appropriate.
This template driver presents a standard interface between the architecture
level interrupt system, and the BSP and hardware level functions. One
purpose of this interface model is to make it easy for BSPs to use standard
interrupt controller devices in both simple and complex situations. Previous
interfaces assumed that the device driver would be the only device in the
system. We need more flexibility than that. This model allows the BSP
to provide complex wrapper functions around any of the hardware level
routines supporting the architecture level functions (see templateIntr.c).
In a simple system with only one controller device, the BSP would initialize
the single device. The driver will attach itself to the sysIntLvlXXX
entry points used by the higher level functions to call the hardware layer.
Nothing else would be needed by such a simple BSP.
In a complex system the BSP would initialize all the controller devices
individually. It would then declare a special version of each function
and install those special versions into the entry point variables. An
example would be a system using 8259's for ISA bus interrupts and had a
separate device for handling VMEbus interrupts. The BSP would initialize
the two individual drivers. For each hardware function, sysIntLvlXXX,
the BSP would create a routine that would interact with both drivers
as needed. This new wrapper routine would be installed as the actual
sysIntLvlXXX routine that is called from the architecture layer.
In this template driver, priority level 0 is lowest, and priority level
16 is the highest. A priority level of 0 indicates all 16 levels enabled.
The order of interrupt level is undefined at the architecture level.
Whether it goes upward from 0 to 16, or downward is immaterial. We presume
that the BSP will define the necessary level numbers and will enable them
individually as needed. The architecture should take no notice of their
numeric values per se.
If the hardware device implements a different scheme from above,
then some of the logic of this template driver will have to be changed
to reflect lower numeric values representing higher priority levels.
The template chip has a TEMPLATE_CSR_ENB register where each bit enables
a specific level, the bit pattern 0x1 enables interrupt level 1, the lowest
level real interrupt. Level 0 is artificial and indicates all levels
enabled. Level 16 is the highest level, and all levels are disabled.
Not all devices will support individual interrupt level enabling. If that
is the case, then templateLvlEnable() should always return OK, and
templateLvlDisable() should always return ERROR.
We presume that config.h or <bsp>.h has defined the addresses of the
template chips registers: TEMPLATE_CSR_PEND, TEMPLATE_CSR_ENB, and
TEMPLATE_CSR_ACK. This template code presumes that the chip is memory
mapped and does direct memory accesses to the registers. If a different
access method is needed, the BSP can redefine the macros
TEMPLATE_REG_READ(addr,result) and TEMPLATE_REG_WRITE(addr,data).
This template chip driver presumes that interrupt vector numbers are
calculated and not the result of a special cycle on the bus. Vector
numbers are generated by adding the current interrupt level number to
TEMPLATE_VEC_BASE to generate a vector number which the architecture
level will use to invoke the proper handling routine. If a different
mapping scheme, or a special hardware routine is needed, then the BSP
should redefine the macro TEMPLATE_LVL_VEC_MAP(level,vector).
This driver was designed to support a single instance of a real device.
At some point it should be upgraded to operate on an object model and to
support any number of real devices.
The BSP will initialize this driver in sysHwInit2(), after initializing
the main interrupt library, usually intLibInit(). The initialization
routine, templateDevInit() will setup the interrupt controller device,
it will mask off all individual interrupt sources and then set the
interrupt level to enable all interrupts. See templateDevInit
for more information.
All of the functions in this library are global. This allows them to be
used by the BSP if it is necessary to create wrapper routines or to
incorporate several drivers together as one.
*/
#include "vxWorks.h"
#include "config.h"
/*
* TODO - These declarations should come from an architecture level
* header file
*/
IMPORT FUNCPTR sysIntLvlVecChkRtn;
IMPORT FUNCPTR sysIntLvlVecAckRtn;
IMPORT FUNCPTR sysIntLvlChgRtn;
IMPORT FUNCPTR sysIntLvlEnableRtn;
IMPORT FUNCPTR sysIntLvlDisableRtn;
/* Defines from config.h, or <bsp>.h */
#define TEMPLATE_CSR_PEND (0x0)
#define TEMPLATE_CSR_ENB (0x1)
#define TEMPLATE_CSR_ACK (0x2)
#define TEMPLATE_VEC_BASE (0x0)
/* hardware access methods */
#ifndef TEMPLATE_REG_READ
# define TEMPLATE_REG_READ(x,result) \
((result) = *(volatile UINT16 *)(x))
#endif /*TEMPLATE_REG_READ*/
#ifndef TEMPLATE_REG_WRITE
# define TEMPLATE_REG_WRITE(x,data) \
(*((volatile UINT16 *)(x)) = (data))
#endif /*TEMPLATE_REG_WRITE*/
/* Convert level number to vector number */
#ifndef TEMPLATE_LVL_VEC_MAP
# define TEMPLATE_LVL_VEC_MAP(level, vector) \
((vector) = ((level) + TEMPLATE_VEC_BASE))
#endif
/* Convert pending register value, to a level number */
#ifndef TEMPLATE_PEND_LVL_MAP
# define TEMPLATE_PEND_LVL_MAP(pendReg, level) \
((level) = (pendReg))
#endif
/* driver constants */
#define TEMPLATE_NUM_LEVELS 16
#define TEMPLATE_ALL_ENABLED (TEMPLATE_NUM_LEVELS)
#define TEMPLATE_ALL_DISABLED 0
/* Local data */
/* Current interrupt level setting (templateLvlChg). */
LOCAL UINT32 templateLvlCurrent = TEMPLATE_ALL_DISABLED; /* all levels disabled */
/*
* A mask word. Bits are set in this word when a specific level
* is enabled. It is used to mask off individual levels that have
* not been explicitly enabled.
*/
LOCAL UINT32 templateLvlEnabled;
/*
* This array maps interrupt levels to mask patterns. The interrupt level
* is the index, the data is the mask value. A mask bit enables one
* level. The mask value is 'and'd with the templateLvlEnabled value
* before writing to the chip.
*/
LOCAL UINT32 templateLvlMask[TEMPLATE_NUM_LEVELS + 1] = /* int level mask */
{
0x0000, /* level 0, all disabled */
0x0001, 0x0003, 0x0007, 0x000f,
0x001f, 0x003f, 0x007f, 0x00ff,
0x01ff, 0x03ff, 0x07ff, 0x0fff,
0x1fff, 0x3fff, 0x7fff, 0xffff /* level 16, all enabled */
};
/* forward declarations */
STATUS templateLvlVecChk (int*, int*);
STATUS templateLvlVecAck (int, int);
int templateLvlChg (int);
STATUS templateLvlEnable (int);
STATUS templateLvlDisable (int);
/*******************************************************************************
*
* templateDevInit - initialize the interrupt controller
*
* This routine will initialize the interrupt controller device, disabling all
* interrupt sources. It will also connect the device driver specific routines
* into the architecture level hooks. If the BSP needs to create a wrapper
* routine around any of the arhitecture level routines, it should install the
* pointer to the wrapper routine after calling this routine.
*
* RETURNS: N/A.
*/
void templateDevInit (void)
{
/* install the driver routines in the architecture hooks */
sysIntLvlVecChkRtn = templateLvlVecChk;
sysIntLvlVecAckRtn = templateLvlVecAck;
sysIntLvlChgRtn = templateLvlChg;
sysIntLvlEnableRtn = templateLvlEnable;
sysIntLvlDisableRtn = templateLvlDisable;
templateLvlEnabled = 0; /* all sources disabled */
templateLvlChg (TEMPLATE_ALL_ENABLED); /* enable all levels */
}
/*******************************************************************************
*
* templateLvlVecChk - check for and return any pending interrupts
*
* This routine interrogates the hardware to determine the highest priority
* interrupt pending. It returns the vector associated with that interrupt, and
* also the interrupt priority level prior to the interrupt (not the
* level of the interrupt). The current interrupt priority level is then
* raised to the level of the current interrupt so that only higher priority
* interrupts will be accepted until this interrupt is finished.
*
* The return value ERROR indicates that no pending interrupt was found and
* that the level and vector values were not returned.
*
* RETURNS: OK or ERROR if no interrupt is pending.
*/
STATUS templateLvlVecChk
(
int* pLevel, /* ptr to receive old interrupt level */
int* pVector /* ptr to receive current interrupt vector */
)
{
int newLevel;
/* Read pending interrupt register */
TEMPLATE_REG_READ (TEMPLATE_CSR_PEND, newLevel);
/* If no interrupt is pending, return ERROR */
if (newLevel == 0)
return ERROR;
/* map the return value to an interrupt level number */
TEMPLATE_PEND_LVL_MAP (newLevel, newLevel);
/* change to new interrupt level, returning previous level to caller */
*pLevel = templateLvlChg (newLevel);
/* fetch, or compute the interrupt vector number */
TEMPLATE_LVL_VEC_MAP (newLevel, *pVector);
return OK;
}
/*******************************************************************************
*
* templateLvlVecAck - acknowledge the current interrupt
*
* Acknowledge the current interrupt cycle. The level and vector values are
* those generated during the templateLvlVecChk() routine for this interrupt
* cycle. The basic action is to reset the current interrupt and return
* the interrupt level to its previous setting.
*
* RETURNS: OK or ERROR if a hardware fault is detected.
* ARGSUSED
*/
STATUS templateLvlVecAck
(
int level, /* old interrupt level to be restored */
int vector /* current interrupt vector, if needed */
)
{
/* acknowledge the current interrupt cycle */
TEMPLATE_REG_WRITE (TEMPLATE_CSR_ACK, (1 << (templateLvlCurrent)));
/* restore the previous interrupt level */
templateLvlChg (level);
return OK;
}
/*******************************************************************************
*
* templateLvlChg - change the interrupt level value
*
* This routine implements the overall interrupt setting. All levels
* up to and including the specifed level are disabled. All levels above
* the specified level will be enabled, but only if they were specifically
* enabled by the templateLvlEnable() routine.
*
* The specific priority level TEMPLATE_NUM_LEVELS is valid and represents
* all levels enabled.
*
* RETURNS: Previous interrupt level.
*/
int templateLvlChg
(
int level /* new interrupt level */
)
{
int oldLevel;
oldLevel = templateLvlCurrent;
if (level >= 0 &&
level <= TEMPLATE_NUM_LEVELS)
{
/* change current interrupt level */
templateLvlCurrent = level;
}
/* Activate the enabled interrupts */
TEMPLATE_REG_WRITE (TEMPLATE_CSR_ENB,
(templateLvlMask[templateLvlCurrent] & templateLvlEnabled));
return oldLevel;
}
/*******************************************************************************
*
* templateLvlEnable - enable a single interrupt level
*
* Enable a specific interrupt level. The enabled level will be allowed to
* generate an interrupt, when the overall interrupt level is set below the
* specified level. Without being enabled, the interrupt is blocked regardless
* of the overall interrupt level setting.
*
* RETURNS: OK or ERROR if the specified level cannot be enabled.
*/
STATUS templateLvlEnable
(
int level /* level to be enabled */
)
{
if (level < 0 ||
level > TEMPLATE_NUM_LEVELS)
return ERROR;
/* set bit in enable mask */
if (level > 0)
{
int key;
key = intLock ();
templateLvlEnabled |= (1 << level);
intUnlock (key);
}
templateLvlChg (-1); /* reset current mask */
return OK;
}
/*******************************************************************************
*
* templateLvlDisable - disable a single interrupt level
*
* Disable a specific interrupt level. The disabled level is prevented
* from generating an interrupt even if the overall interrupt level is set
* below the specified level.
*
* RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
*/
STATUS templateLvlDisable
(
int level /* level to be disabled */
)
{
if (level < 0 ||
level > TEMPLATE_NUM_LEVELS)
return ERROR;
/* clear bit in enable mask */
if (level > 0)
{
int key;
key = intLock ();
templateLvlEnabled &= ~(1 << level);
intUnlock (key);
}
templateLvlChg (-1); /* reset current mask */
return OK;
}
@@ -0,0 +1,27 @@
# Makefile - makefile for target/src/drv/manager
#
# Copyright 1984-2005 Wind River Systems, Inc.
#
# modification history
# --------------------
# 01a,15aug05,kkz Updating doc values
#
# DESCRIPTION
# This file contains the makefile rules for building the device manager library
#
TGT_DIR=$(WIND_BASE)/target
DOC_FILES= device.c
LIB_BASE_NAME = device
NODEPENDOBJS=
EXTRA_INCLUDE= -I$(TGT_DIR)/src/drv/
OBJS = device.o
include $(TGT_DIR)/h/make/rules.library
include $(TGT_DIR)/h/make/defs.drivers
+627
View File
@@ -0,0 +1,627 @@
/* device.c - Device Infrastructure Library */
/*
* Copyright (c) 2005-2009, 2011-2013, 2016 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01o,18may16,myt fix issue that fsmNameInstall cannot correctly add a XBD driver
name of which length is equal to MAX_DEVNAME (VXW6-85215)
01n,08oct13,dee eliminate unused local function
01m,28jun13,xwu fix WIND00424201 Coverity issue: remain high impact defect of FS
01l,24may13,xwu Replace mutex with spinlock for performance (WIND00337587)
01k,27aug12,clx fix ddDelete memory leak issue. (WIND00365416)
01j,13jan11,m_y Add devGetByName() (WIND00211541)
01i,15oct09,h_k cleaned up compiler warnings for LP64.
01h,29aug06,dee WIND00062547 - fix XBD resource limitation caused by queueing
problem
01g,01mar06,dee add unsafe devmap and unmap functions for coredump
01f,11jul05,rfr Mark the struct device when removal is complete
01e,04jul05,pcm added comments and sections for doc build
01d,28apr05,rfr Added setting the dv_dev member in devAttach()
01c,26apr05,rfr Fixed call to strncpy
01b,20apr05,rfr Added devName() function
01a,25mar05,rfr Removed prototype eventing system.
*/
/*
DESCRIPTION
This library provides the interface for the device infrastructure.
INCLUDE FILES: drv/manager/device.h
*/
/* includes */
#include <vxWorks.h>
#include <semLib.h>
#include <stdlib.h>
#include <string.h>
#include <intLib.h>
#include <taskLib.h>
#include <spinLockLib.h>
#include <stdio.h>
#include <drv/manager/device.h>
/* defines */
#define DEVICE_T_ITEM(d) (uint16_t)(((d) & 0xffff0000) >> 16)
#define DEVICE_T_GEN(d) ((d) & 0xffff)
#define DEVICE_T_MAP(index, d) ((index)->ddh_map[DEVICE_T_ITEM(d)])
#define ITEM_MAP(index, i) ((index)->ddh_map[(i)])
/* DEVICE_T_EXISTS() is nonzero if d is a legitimate device_t in index */
#define DEVICE_T_EXISTS(index, d) ((index) != NULL &&\
DEVICE_T_GEN(d) != 0 &&\
DEVICE_T_ITEM(d) < (index)->ddh_size)
/* DEVICE_T_VALID() is nonzero if d is a valid mapping in index */
#define DEVICE_T_VALID(index, d) (DEVICE_T_MAP((index), (d)).ddm_data != NULL &&\
DEVICE_T_GEN(d) == DEVICE_T_MAP((index), (d)).ddm_generation)
#define NULLINDEX 0xffff /* represents end of list for the free list */
/* typedefs */
/*
* struct ddMapRec represents individual mappings from device_t to struct device *
* Each mapping is specified by an index and a generation number
*/
struct ddMapRec
{
uint16_t ddm_generation; /* the generation of this mapping */
uint16_t ddm_next; /* Index of the next free mapping */
struct device *ddm_data; /* The Item of this mapping */
struct device *ddm_cache; /* Cached device for marking on removal complete */
unsigned ddm_refCount; /* The number of active devMap() */
};
/*
* struct ddHeader represents the entire mapping of device_t to struct device *
*/
struct ddHeader
{
uint16_t ddh_size; /* The number of slots */
uint16_t ddh_freeh; /* The head of the free list */
uint16_t ddh_freet; /* The tail of the free list */
spinlockTask_t ddh_lock; /* The lock of the mappings */
struct ddMapRec ddh_map[1]; /* First element of the mappings */
};
/* locals */
LOCAL struct ddHeader *dit_index = NULL;
/* forward declarations */
LOCAL void ddFinishRemoval(struct ddHeader *index, uint16_t item);
/***************************************************************************
*
* ddInit -
*
* \NOMANUAL
*/
LOCAL struct ddHeader *ddInit
(
uint16_t Size
)
{
uint16_t i, last;
struct ddHeader *retVal;
if (Size == 0)
{
errno = EINVAL;
return (NULL);
}
/* Allocate the index */
retVal = malloc (sizeof (*retVal) +
sizeof (struct ddMapRec) * (uint16_t)(Size - 1));
if (!retVal)
return (NULL);
SPIN_LOCK_TASK_INIT(&retVal->ddh_lock, 0);
last = (uint16_t)(Size - 1);
retVal->ddh_size = Size;
retVal->ddh_freeh = 0;
retVal->ddh_freet = last;
/* Thread the individual mapping records together */
for (i = 0; i <= last; i++)
{
retVal->ddh_map[i].ddm_generation = 1;
retVal->ddh_map[i].ddm_data = NULL;
retVal->ddh_map[i].ddm_refCount = 0;
retVal->ddh_map[i].ddm_next = (uint16_t)(i + 1);
}
retVal->ddh_map[last].ddm_next = NULLINDEX;
return (retVal);
}
/***************************************************************************
*
* ddInsert - allocate a device_t slot and put a struct device * in it
*
* This function must be called with the index mutex held. It only allocates
* the device_t and inserts the device. Modifications to the struct device must
* happen externally.
*
* RETURNS: 0 on success or an errno.h value on failure
*
* \NOMANUAL
*/
LOCAL int ddInsert
(
struct ddHeader *index,
struct device *dev,
device_t *result
)
{
uint16_t item;
if (index == NULL)
return (EINVAL);
if (dev == NULL)
return (EINVAL);
/* Get a free slot */
if (index->ddh_freeh == NULLINDEX)
{
/* nothing on the free list */
return (ENOMEM);
}
else
{
/* Get the first element of the free list */
item = index->ddh_freeh;
/* Link the free list to the next element */
index->ddh_freeh = index->ddh_map[item].ddm_next;
/* enforce empty condition on the other side of the list */
if (index->ddh_freeh == NULLINDEX)
index->ddh_freet = NULLINDEX;
}
/* item is the index of the new slot */
index->ddh_map[item].ddm_data = dev;
index->ddh_map[item].ddm_refCount = 0;
/* Make next point nowhere */
index->ddh_map[item].ddm_next = NULLINDEX;
/* generation stays the same - it is incremented on removal */
/* if result is NULL we're gonna lose this mapping */
if (result)
{
/* Roll up the device_t */
*result = (device_t)((item << 16) |
index->ddh_map[item].ddm_generation);
}
return (0);
}
/***************************************************************************
*
* ddRemove - remove a mapping from device_t to struct device *
*
* This function must be called with the index mutex held.
* This function only removes the mapping, it does not modify the contents of the
* struct device.
* If this function fails, it will leave the map unchanged.
*
* RETURNS: 0 on success or a value from errno.h on failure.
*
* \NOMANUAL
*/
LOCAL int ddRemove
(
struct ddHeader *index,
device_t dev
)
{
uint16_t item;
if (!DEVICE_T_EXISTS(index, dev))
return (EINVAL);
if (!DEVICE_T_VALID(index, dev))
return (ENOENT);
/* If we got here, then dev refers to a valid mapping */
item = DEVICE_T_ITEM(dev);
/* Cache the data so we can mark it when we're done */
ITEM_MAP(index, item).ddm_cache = ITEM_MAP(index, item).ddm_data;
/* Set the data to NULL - this effects the unmapping */
ITEM_MAP(index, item).ddm_data = NULL;
/*
* Now we test to see whether or not we complete the removal here. If the
* refCount is zero, the device_t is not in use, and we can undo it here.
* If not, then we must wait and let ddUnmap() do the final removal.
*/
if (ITEM_MAP(index, item).ddm_refCount == 0)
{
ddFinishRemoval(index, item);
}
return (OK);
}
/***************************************************************************
*
* ddFinishRemoval -
*
* \NOMANUAL
*/
LOCAL void ddFinishRemoval
(
struct ddHeader *index,
uint16_t item
)
{
uint16_t tail;
struct device *dev;
/* Get the cached dev out so that we can mark it */
dev = ITEM_MAP(index, item).ddm_cache;
/* We assume that ddh_mutex is held */
ITEM_MAP(index, item).ddm_generation ++;
/* get the tail of the free list */
tail = index->ddh_freet;
/* if its a valid item, link us into the free list */
if (tail != NULLINDEX)
{
ITEM_MAP(index, tail).ddm_next = item;
index->ddh_freet = item;
}
/* otherwise the list is empty - set head and tail */
else
{
index->ddh_freeh = index->ddh_freet = item;
}
/* terminate the list */
ITEM_MAP(index, item).ddm_next = NULLINDEX;
/* mark the device as no longer mapped */
if (dev)
dev->dv_dev = NULLDEV;
/* We're done */
}
/***************************************************************************
*
* ddMap -
*
* \NOMANUAL
*/
LOCAL struct device *ddMap
(
struct ddHeader *index,
device_t dev
)
{
uint16_t item;
if (!DEVICE_T_EXISTS(index, dev))
{
errno = EINVAL;
return (NULL);
}
if (!DEVICE_T_VALID(index, dev))
{
errno = ENOENT;
return (NULL);
}
item = DEVICE_T_ITEM(dev);
/* We have a good device_t, increment refCount */
ITEM_MAP(index, item).ddm_refCount ++;
/* We're done */
return (ITEM_MAP(index, item).ddm_data);
}
/***************************************************************************
*
* ddUnmap -
*
* \NOMANUAL
*/
LOCAL int ddUnmap
(
struct ddHeader *index,
struct device *dev
)
{
device_t d;
uint16_t item;
if (dev == NULL)
return (EINVAL);
d = dev->dv_dev;
if (!DEVICE_T_EXISTS(index, d))
return (EINVAL);
item = DEVICE_T_ITEM(d);
if (ITEM_MAP(index, item).ddm_generation != DEVICE_T_GEN(d))
return (ENOENT);
/* Check the Count */
if (ITEM_MAP(index, item).ddm_refCount == 0)
return (EACCES);
/* Decrement the count */
ITEM_MAP(index, item).ddm_refCount--;
/* Check to see if we have a pending delete */
if (!ITEM_MAP(index, item).ddm_refCount && !ITEM_MAP(index, item).ddm_data)
ddFinishRemoval(index, item);
return (0);
}
/***************************************************************************
*
* devInit - initialize the device manager
*
* This routine initializes the device manager for <ndevs> devices.
*
* RETURNS: OK upon success, ERROR otherwise
*
* ERRNO: EINVAL
*/
STATUS devInit
(
uint16_t ndevs /* number of devices */
)
{
/* Initialize the device index */
dit_index = ddInit (ndevs);
if (dit_index == NULL)
return (ERROR);
return (OK);
}
/***************************************************************************
*
* devAttach - attach a device
*
* RETURNS: 0 upon success, non-zero otherwise
*/
int devAttach
(
struct device *dev,
const char *name,
int type,
device_t *result
)
{
int error = 0;
/* Load dev with the appropriate values */
strncpy (dev->dv_xname, name, MAX_DEVNAME);
dev->dv_xname[MAX_DEVNAME] = '\0';
dev->dv_type = type;
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
error = ddInsert (dit_index, dev, &dev->dv_dev);
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
if (result != NULL)
*result = dev->dv_dev;
return (error);
}
/***************************************************************************
*
* devDetach - detach a device
*
* RETURNS: 0 upon success, non-zero otherwise
*/
STATUS devDetach
(
struct device *dev /* pointer to device to detach */
)
{
int error;
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
error = ddRemove (dit_index, dev->dv_dev);
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
return (error);
}
/***************************************************************************
*
* devMap - map a device
*
* RETURNS: pointer to device upon success, NULL otherwise
*/
struct device *devMap
(
device_t dev /* device to map */
)
{
struct device *retVal;
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
retVal = ddMap (dit_index, dev);
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
return (retVal);
}
/***************************************************************************
*
* devMapUnsafe - map a device unconditionally
*
* RETURNS: pointer to device upon success, NULL otherwise
*/
struct device *devMapUnsafe
(
device_t dev /* device to map */
)
{
struct device *retVal;
retVal = ddMap (dit_index, dev);
return (retVal);
}
/***************************************************************************
*
* devUnmap - unmap a device
*
* RETURNS: 0
*/
int devUnmap
(
struct device *dev /* pointer to device to unmap */
)
{
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
ddUnmap (dit_index, dev);
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
return (0);
}
/***************************************************************************
*
* devUnmapUnsafe - unmap a device unconditionally
*
* RETURNS: 0
*/
int devUnmapUnsafe
(
struct device *dev /* pointer to device to unmap */
)
{
ddUnmap (dit_index, dev);
return (0);
}
/***************************************************************************
*
* devName - name a device
*
* RETURNS: OK upon success, ERROR otherwise
*/
STATUS devName
(
device_t dev, /* device to name */
devname_t name /* name to assign */
)
{
struct device *d;
STATUS retVal;
d = devMap (dev);
if (d != NULL)
{
strncpy (name, d->dv_xname, sizeof(devname_t));
devUnmap (d);
retVal = OK;
}
else
{
retVal = ERROR;
}
return (retVal);
}
/***************************************************************************
*
* devGetByName - get a device handle by name
*
* RETURNS: device handle, NULLDEV otherwise
*/
device_t devGetByName
(
char *deviceName
)
{
int i;
device_t index;
struct device *pDev = NULL;
SPIN_LOCK_TASK_TAKE(&dit_index->ddh_lock);
for (i = 0; i < dit_index->ddh_size; i++)
{
index = (device_t)((i << 16) | dit_index->ddh_map[i].ddm_generation);
if ((pDev = ddMap (dit_index, index)) != NULL)
{
if (strcmp(deviceName, pDev->dv_xname) == 0)
{
ddUnmap(dit_index, pDev);
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
return index;
}
ddUnmap(dit_index, pDev);
}
}
SPIN_LOCK_TASK_GIVE(&dit_index->ddh_lock);
return NULLDEV;
}
@@ -0,0 +1,208 @@
/* amd29LV800TMem.c - AMD 29LV800T Flash Memory library */
/* Copyright 1984-2004 Wind River Systems, Inc. */
/*
modification history
--------------------
01d,13may04,rec move from wrPpmc74xx bsp to drivers
01c,22jun01,g_h move sysNvRamGet & sysNvRamSet to sysNvRam.c and make
amd29LV800TWrite() , amd29LV800TEraseBlock() & amd29LV800TEraseSector()
global.
01b,23may01,pch Fix initializations of rmasks[] and lmasks[]
01a,22apr01,g_h written
*/
/*
DESCRIPTION
This library contains routines to manipulate AMD 29LV800T Flash memory.
Read and write routines are included.
The macros NV_RAM_ADRS and NV_RAM_SIZE must be defined to indicate the
address and size of the Flash memory.
This module use the visionWare flash algorithm.
The AMD 29LV800 access is BITS:16 BUS:64 BOOT:TOP ACCESS:DOUBLE.
INCLUDES: amd29LV800TMem.h
*/
/* includes */
#include "drv/mem/amd29LV800TMem.h"
#include "memLib.h"
#include "stdlib.h"
/* locals */
LOCAL void iOSync(void){ }
LOCAL const tFLASH unlock1 = {{ 0xAA00AA, 0xAA00AA }};
LOCAL const tFLASH unlock2 = {{ 0x550055, 0x550055 }};
LOCAL const tFLASH erase1 = {{ 0x800080, 0x800080 }};
LOCAL const tFLASH erase2 = {{ 0x300030, 0x300030 }};
LOCAL const tFLASH program = {{ 0xA000A0, 0xA000A0 }};
LOCAL const tFLASH readArray = {{ 0xF000F0, 0xF000F0 }};
LOCAL const tFLASH erased = {{ (UINT32)-1, (UINT32)-1 }};
LOCAL const tFLASH rmasks[] = {
{{0xffffffff, 0xffffffff}},
{{0xffffffff, 0xffffff00}},
{{0xffffffff, 0xffff0000}},
{{0xffffffff, 0xff000000}},
{{0xffffffff, 0x00000000}},
{{0xffffff00, 0x00000000}},
{{0xffff0000, 0x00000000}},
{{0xff000000, 0x00000000}},
};
LOCAL const tFLASH lmasks[] = {
{{0xffffffff, 0xffffffff}},
{{0x00ffffff, 0xffffffff}},
{{0x0000ffff, 0xffffffff}},
{{0x000000ff, 0xffffffff}},
{{0x00000000, 0xffffffff}},
{{0x00000000, 0x00ffffff}},
{{0x00000000, 0x0000ffff}},
{{0x00000000, 0x000000ff}},
};
LOCAL tBLOCK blocks[] = {
{ 15, 256 },
{ 1, 128 },
{ 2, 32 },
{ 1, 64 }
};
/***************************************************************************
*
* amd29LV800TWrite - write data to the AMD 29LV800T
*
* This routine write given data to the AMD 29LV800T FLASH device.
*
* RETURNS: Number of byte writen
*
* SEE ALSO: amd29LV800TEraseBlock(), amd29LV800TEraseSector()
*/
UINT32 amd29LV800TWrite
(
volatile UINT8 * pDest,
UINT8 * pSource,
UINT32 length
)
{
unsigned int originalLength = length;
UINT64 mask;
tFLASH data;
unsigned short n;
volatile UINT8 *pChip = (volatile UINT8 *)((unsigned int)pDest & ~(0x400000 - 1));
while (length)
{
n = ((unsigned int)pDest & (8 - 1));
mask = lmasks[n].Integer;
if ((n + length) < 8)
mask &= rmasks[n + length].Integer;
data.Integer = readUnaligned(pSource) & mask;
data.Integer |= *(UINT64 *)pDest & (~mask);
pSource += 8;
*(volatile DOUBLE *)(pChip + 0x2AAA8) = unlock1.Float;
iOSync();
*(volatile DOUBLE *)(pChip + 0x15550) = unlock2.Float;
iOSync();
*(volatile DOUBLE *)(pChip + 0x2AAA8) = program.Float;
iOSync();
*(volatile DOUBLE *)pDest = data.Float;
while (*(volatile UINT64 *)pDest != data.Integer);
pDest += 8;
length -= min(8 - n, length);
}
*(volatile DOUBLE *)(pDest - 8) = readArray.Float;
return originalLength - length;
}
/***************************************************************************
*
* amd29LV800TEraseBlock - erase block in the AMD 29LV800T
*
* This routine erase a block in the AMD 29LV800T FLASH device.
*
* RETURNS: OK
*
* SEE ALSO: amd29LV800TWrite(), amd29LV800TEraseSector()
*/
UINT32 amd29LV800TEraseBlock
(
volatile UINT8 *pChip,
volatile UINT8 *pSector
)
{
*(volatile DOUBLE *)(pChip + 0x2AAA8) = unlock1.Float;
iOSync();
*(volatile DOUBLE *)(pChip + 0x15550) = unlock2.Float;
iOSync();
*(volatile DOUBLE *)(pChip + 0x2AAA8) = erase1.Float;
iOSync();
*(volatile DOUBLE *)(pChip + 0x2AAA8) = unlock1.Float;
iOSync();
*(volatile DOUBLE *)(pChip + 0x15550) = unlock2.Float;
iOSync();
*(volatile DOUBLE *)pSector = erase2.Float;
iOSync();
while (*(volatile UINT64 *)pSector != erased.Integer);
*(volatile DOUBLE *)pSector = readArray.Float;
return (OK);
}
/***************************************************************************
*
* amd29LV800TEraseSector - erase sector in the AMD 29LV800T
*
* This routine erase sector in the AMD 29LV800T FLASH device.
*
* RETURNS: OK
*
* SEE ALSO: amd29LV800TWrite(), amd29LV800TEraseBlock()
*/
UINT32 amd29LV800TEraseSector
(
volatile UINT8 *pSector
)
{
int i, j;
volatile UINT8 *pChip = (volatile UINT8 *)((unsigned int)pSector & ~(0x400000 - 1));
UINT32 n = pSector - pChip;
for (i = 0; i < BLOCKS; ++i)
{
if (n >= (blocks[i].Number * blocks[i].Size * 1024))
n -= (blocks[i].Number * blocks[i].Size * 1024);
else
break;
}
j = blocks[i].Number;
n = 0x40000;
while (n)
{
amd29LV800TEraseBlock (pChip, pSector);
pSector += blocks[i].Size * 1024;
n -= blocks[i].Size * 1024;
if (!--j)
{
j = blocks[++i].Number;
}
}
return (OK);
}
+157
View File
@@ -0,0 +1,157 @@
/* byteNvRam.c - byte-oriented generic NVRAM driver */
/* Copyright 1984-2004 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01c,22sep04,mdo Documentation fixes for apigen
01b,29oct96,wlf doc: cleanup.
01a,03jun96,dat written.
*/
/*
DESCRIPTION
This driver is for byte-oriented non-volatile RAM (NVRAM). Typical uses
are EEPROMs, static RAM, and any other byte-oriented device.
There are other generic drivers for block-oriented devices like flash memory,
and for boards that have no non-volatile memory at all.
This is boilerplate driver code. It is to be included in source form
into sysLib.c. Macros are used to provide the actual working elements
while this code provides the generic logic.
The following numeric value macros are required:
NV_RAM_ADRS - address of first non-volatile byte
NV_RAM_INTRVL - address interval between bytes
NV_RAM_SIZE - total number of bytes in device
NV_BOOT_OFFSET - Offset to first byte of boot line information
The following procedural macros are used. If not defined by the
specific BSP, then default procedures assuming static RAM with no
special read/write requirements will be used.
NV_RAM_READ(x) - Read and return one byte at offset (x).
NV_RAM_WRITE(x,y) - Write data (y) at offset (x).
NV_RAM_WR_ENBL - procedure to enable writing, if any
NV_RAM_WR_DSBL - procedure to disable writing, if any
*/
#include "vxWorks.h"
#include "config.h"
/* default procedures assume static ram with no special r/w routines */
#ifndef NV_RAM_WR_ENBL
# define NV_RAM_WR_ENBL /* no write enable procedure */
#endif /*NV_RAM_WR_ENBL*/
#ifndef NV_RAM_WR_DSBL
# define NV_RAM_WR_DSBL /* no write disable procedure */
#endif /*NV_RAM_WR_DSBL*/
#ifndef NV_RAM_READ
# define NV_RAM_READ(x) \
(*(UCHAR *)((int)NV_RAM_ADRS + ((x) * NV_RAM_INTRVL)))
#endif /*NV_RAM_READ*/
#ifndef NV_RAM_WRITE
# define NV_RAM_WRITE(x,y) \
(*(UCHAR *)((int)NV_RAM_ADRS + ((x) * NV_RAM_INTRVL)) = (y))
#endif /*NV_RAM_WRITE*/
/******************************************************************************
*
* sysNvRamGet - get the contents of non-volatile RAM
*
* This routine copies the contents of non-volatile memory into a specified
* string. The string is terminated with an EOS.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* ERRNO
*
* SEE ALSO: sysNvRamSet()
*/
STATUS sysNvRamGet
(
char *string, /* where to copy non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0)
|| (strLen < 0)
|| ((offset + strLen) > NV_RAM_SIZE))
return (ERROR);
while (strLen--)
{
*string = NV_RAM_READ (offset);
string++, offset++;
}
*string = EOS;
return (OK);
}
/*******************************************************************************
*
* sysNvRamSet - write to non-volatile RAM
*
* This routine copies a specified string into non-volatile RAM.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* ERRNO
*
* SEE ALSO: sysNvRamGet()
*/
STATUS sysNvRamSet
(
char *string, /* string to be copied into non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
STATUS result = OK;
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0) || (strLen < 0) ||
((offset + strLen) > NV_RAM_SIZE))
return ERROR;
NV_RAM_WR_ENBL;
while (strLen--)
{
char data;
data = *string; /* avoid any macro side effects */
NV_RAM_WRITE (offset, data);
/* verify data */
if (NV_RAM_READ (offset) != (UCHAR)data)
{
result = ERROR;
goto exit;
}
string++, offset++;
}
exit:
NV_RAM_WR_DSBL;
return result;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,251 @@
/* i28F640j3Mem.c - Intel 28F640J3 Flash Memory library */
/* Copyright 1984-1992 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01a,16apr01,gh written
*/
/*
DESCRIPTION
This library contains routines to manipulate Intel 28F640J3 Flash memory.
Read and write routines are included.
The macros NV_RAM_ADRS and NV_RAM_SIZE must be defined to indicate the
address and size of the Flash memory.
This module use the visionWare flash algorithm.
The Intel 28F640J3 access is BITS:8 BUS:8 ACCESS:INTEGER.
*/
/* includes */
#include "drv/mem/i28f640j3mem.h"
#include "memLib.h"
#include "stdlib.h"
/* LOCALs */
LOCAL void IOSync(void){ }
LOCAL UINT32 FlashWrite(volatile UINT8 *pDest, UINT8 *pSource, UINT32 Length);
LOCAL UINT32 FlashEraseSector(volatile UINT8 *pSector);
LOCAL const tFLASH Erase1 = { 0x20 };
LOCAL const tFLASH Erase2 = { 0xD0 };
LOCAL const tFLASH Program = { 0x40 };
LOCAL const tFLASH ReadArray = { 0xFF };
LOCAL const tFLASH ClearStatus = { 0x50 };
LOCAL const tFLASH Erased = { (UINT8)-1 };
LOCAL const tFLASH ReadyBits = { 0x80 };
LOCAL const tFLASH EraseBits = { 0x20 };
LOCAL const tFLASH ProgramBits = { 0x10 };
LOCAL const tFLASH BufferWrite = { 0xE8 };
LOCAL const tFLASH ConfirmWrite = { 0xD0 };
LOCAL const tFLASH BufferCount = { 0x1F };
/*****************************************************************************
*
* sysNvRamGet - get the contents of non-volatile RAM
*
* This routine copies the contents of non-volatile memory into a specified
* string. The string will be terminated with an EOS.
*
* INTERNAL
* The board has no NVRAM, so we've implemented some pseudo-NVRAM
* in the flash.
*
* RETURNS: OK or ERROR
*
* SEE ALSO: sysNvRamSet()
*/
STATUS sysNvRamGet
(
char * string, /* where to copy flash memory */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into flash memory */
)
{
char *pNvRam,*pString;
int i;
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
/* Check that the string is entirely within the NVRAM */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return ERROR;
pNvRam = (char *)(NV_RAM_ADRS + offset);
pString = (char *)string;
for (i = 0; i < strLen; i++)
*pString++ = *pNvRam++;
*pString = EOS; /* force EOS onto nvram string */
/* The generic boot-line code expects this function to check the contents
* and report any errors. The default boot line is only used if this
* function returns ERROR. So, we return ERROR if the first character
* copied is 0xFF (= erased flash).
*/
return ((*string == (char)0xff) ? ERROR : OK);
}
/******************************************************************************
*
* sysNvRamSet - write data to non-volatile RAM
*
* This routine copies the provided string to the non-volatile memory.
*
* INTERNAL
* The board has no NVRAM, so we've implemented some pseudo-NVRAM
* in the flash.
* The "NVRAM" is a small region at the very top of flash memory, and can
* thus be read using normal memory accesses. However, to write the data we
* have to read the entire top sector, modify its contents, erase the top
* sector, and then reprogram it.
*
* RETURNS: OK or ERROR
*
* SEE ALSO: sysNvRamGet()
*/
STATUS sysNvRamSet
(
char * string, /* string to be copied into flash memory */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into flash memory */
)
{
UINT32 blockOffs;
char *pBlock, *pTmpBuf;
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
/* Check that the string will fit entirely into the NVRAM */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return ERROR;
/* see if contents are actually changing */
if (bcmp ((char *) (NV_RAM_ADRS + offset), string, strLen) == 0)
return OK;
/* Allocate a temporary buffer for the operation */
pTmpBuf = (char *)malloc(FLASH_SECTOR_SIZE);
if ( pTmpBuf == NULL )
return ERROR;
pBlock = (UINT8 *)((UINT32)(NV_RAM_ADRS + offset) & ~(FLASH_SECTOR_SIZE-1));
/* Copy current contents of flash (entire sector) to the buffer */
memcpy(pTmpBuf,(void*)pBlock,FLASH_SECTOR_SIZE);
/* Now erase the flash sector */
FlashEraseSector((volatile UINT8 *)pBlock);
blockOffs = (NV_RAM_ADRS + offset) & (FLASH_SECTOR_SIZE-1);
/* Overwrite buffer contents with specified string */
memcpy((void*)(pTmpBuf + blockOffs),string,strLen);
/* Now program the flash sector */
FlashWrite((volatile UINT8 *)pBlock, pTmpBuf, FLASH_SECTOR_SIZE);
free (pTmpBuf);
return OK;
}
/******************************************************************************
*
* FlashWrite - write data to the Intel 29F640J3
*
* RETURNS: Number of byte writen
*
* NOMANUAL
*/
LOCAL UINT32 FlashWrite(volatile UINT8 *pDest, UINT8 *pSource, UINT32 Length)
{
unsigned int OriginalLength = Length;
tFLASH Data;
unsigned int n;
volatile UINT8 *pBlock = (UINT8 *)((UINT32)pDest & ~0x1FFFF);
UINT8 TempBuffer[0x20];
while(Length)
{
*(volatile UINT8 *)pDest = ReadArray.Float;
if ((((UINT32)pDest & 0x1F) == 0) && (Length >= 0x20))
{
memcpy((char *)&TempBuffer, pSource, 0x20);
*pBlock = BufferWrite.Float;
IOSync();
if (*pBlock == ReadyBits.Integer)
{
*pBlock = BufferCount.Float;
for (n = 0; n < 0x20; ++n)
((volatile UINT8 *)pDest)[n] = TempBuffer[n];
*pBlock = ConfirmWrite.Float;
while (*(volatile UINT8 *)pDest != ReadyBits.Integer)
;
pDest += 0x20;
pSource += 0x20;
Length -= 0x20;
continue;
}
*(volatile UINT8 *)pDest = ReadArray.Float;
}
Data.Integer = *(UINT8 *)pSource++;
*(volatile UINT8 *)pDest = ClearStatus.Float;
IOSync();
*(volatile UINT8 *)pDest = Program.Float;
IOSync();
*(volatile UINT8 *)pDest = Data.Float;
IOSync();
while (*(volatile UINT8 *)pDest != ReadyBits.Integer)
;
++pDest;
--Length;
}
*(volatile UINT8 *)(pDest - 1) = ReadArray.Float;
return OriginalLength - Length;
}
/******************************************************************************
*
* FlashEraseSector - erase sector in the Intel 29F640J3
*
* RETURNS: N/A
*
* NOMANUAL
*/
LOCAL UINT32 FlashEraseSector(volatile UINT8 *pSector)
{
*(volatile UINT8 *)pSector = ClearStatus.Float;
IOSync();
*(volatile UINT8 *)pSector = Erase1.Float;
IOSync();
*(volatile UINT8 *)pSector = Erase2.Float;
IOSync();
while (*(volatile UINT8 *)pSector != ReadyBits.Integer);
*(volatile UINT8 *)pSector = ReadArray.Float;
return 0;
}
+246
View File
@@ -0,0 +1,246 @@
/* iFlashMem.c - Intel 28F256A Flash Memory library */
/* Copyright 1984-1992 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01b,28jan93,caf made boot line begin at offset 0 (SPR #1933).
01a,30oct92,ccc created.
*/
/*
DESCRIPTION
This library contains routines to manipulate Intel 28F256A Flash memory.
Read and write routines are included.
The Intel 28F256A provides 32K bytes of non-volatile RAM, thus providing
64K bytes with 2 devices.
The macros NV_RAM_ADRS and NV_RAM_SIZE must be defined to indicate the
address and size of the Flash memory.
INTERNAL
The routine sysFlashDelay() is to delay 1uS. It has not been timed, and
should be timed because faster boards may have a problem.
*/
#include "drv/mem/iFlash.h"
#include "memLib.h"
#include "stdlib.h"
/******************************************************************************
*
* sysNvRamGet - get the contents of non-volatile RAM
*
* This routine copies the contents of non-volatile memory into a specified
* string. The string will be terminated with an EOS.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* SEE ALSO: sysNvRamSet()
*
* INTERNAL
* If multiple tasks are calling sysNvRamSet() and sysNvRamGet(),
* they should use a semaphore to ensure mutually exclusive access.
*/
STATUS sysNvRamGet
(
char *string, /* where to copy non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return (ERROR);
bcopyBytes (NV_RAM_ADRS + offset, string, strLen);
string [strLen] = EOS;
return (OK);
}
/******************************************************************************
*
* sysFlashDelay - delay for 1uS
*
* RETURNS: N/A
*
* NOMANUAL
*/
void sysFlashDelay
(
int delayCount /* number of uS to delay */
)
{
int ix;
volatile int bump = 0;
for (ix = 0; ix < delayCount; ix++)
{
bump++;
}
}
/******************************************************************************
*
* sysFlashErase - erase the Intel 28F256A
*
* RETURNS: N/A
*
* NOMANUAL
*/
void sysFlashErase (void)
{
int address;
int ix = 0;
volatile unsigned short * pFlashAdrs;
for (address = 0; address < NV_RAM_SIZE; address += 2)
{
pFlashAdrs = (unsigned short *) (NV_RAM_ADRS + address);
for (ix = 0; ix < 25; ix++)
{
*pFlashAdrs = FLASH_CMD_PROG_SETUP; /* write setup */
*pFlashAdrs = 0x0000; /* data to write */
sysFlashDelay (10); /* wait for write */
*pFlashAdrs = FLASH_CMD_PROG_VERIFY; /* verify command */
sysFlashDelay (6); /* wait for verify */
if (*pFlashAdrs == 0) /* done? */
break;
}
}
/* now it is all zeros - time to erase */
address = 0;
pFlashAdrs = (unsigned short *) NV_RAM_ADRS;
for (ix = 0; ix < 3000; ix++)
{
*pFlashAdrs = FLASH_CMD_ERASE_SETUP; /* erase setup */
*pFlashAdrs = FLASH_CMD_ERASE; /* erase */
sysFlashDelay (1000);
while (address < NV_RAM_SIZE)
{
*pFlashAdrs = FLASH_CMD_ERASE_VERIFY; /* erase verify */
sysFlashDelay (6); /* wait for verify */
if (*pFlashAdrs != 0xffff) /* erased ? */
break;
address += 2; /* next address */
pFlashAdrs = (unsigned short *) (NV_RAM_ADRS + address);
}
if (address == NV_RAM_SIZE)
break; /* done */
}
pFlashAdrs = (unsigned short *) NV_RAM_ADRS;
*pFlashAdrs = FLASH_CMD_RESET;
*pFlashAdrs = FLASH_CMD_RESET;
*pFlashAdrs = FLASH_CMD_READ_MEM;
}
/******************************************************************************
*
* sysFlashWrite - write data to the Intel 28F256A Flash Memory
*
* RETURNS: N/A
*/
void sysFlashWrite
(
unsigned short *pFlashBuffer /* string to be copied */
)
{
int address;
int ix = 0;
volatile unsigned short * pFlashAdrs;
for (address = 0; address < NV_RAM_SIZE; address += 2)
{
pFlashAdrs = (unsigned short *) (NV_RAM_ADRS + address);
for (ix = 0; ix < 25; ix++)
{
*pFlashAdrs = FLASH_CMD_PROG_SETUP; /* write setup */
*pFlashAdrs = *pFlashBuffer; /* data to write */
sysFlashDelay (10); /* wait for write */
*pFlashAdrs = FLASH_CMD_PROG_VERIFY; /* verify command */
sysFlashDelay (6); /* wait for verify */
if (*pFlashAdrs == *pFlashBuffer) /* done? */
break;
}
pFlashBuffer ++;
}
pFlashAdrs = (unsigned short *) NV_RAM_ADRS;
*pFlashAdrs = FLASH_CMD_RESET;
*pFlashAdrs = FLASH_CMD_RESET;
*pFlashAdrs = FLASH_CMD_READ_MEM;
}
/******************************************************************************
*
* sysNvRamSet - write to non-volatile RAM
*
* This routine copies a specified string into non-volatile RAM.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* SEE ALSO: sysNvRamGet()
*
* INTERNAL
* The Intel 28F256 is rated for 10,000 erase/program cycles minimum.
* If multiple tasks are calling sysNvRamSet() and sysNvRamGet(),
* they should use a semaphore to ensure mutually exclusive access to EEPROM.
*/
STATUS sysNvRamSet
(
char *string, /* string to be copied into non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
char *tempBuffer; /* temp buffer for existing data */
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return (ERROR);
/* see if contents are actually changing */
if (bcmp (NV_RAM_ADRS + offset, string, strLen) == 0)
return (OK);
/* first read existing data */
tempBuffer = (char *) malloc (NV_RAM_SIZE);
bcopyBytes (NV_RAM_ADRS, tempBuffer, NV_RAM_SIZE);
sysFlashErase (); /* first erase device */
bcopyBytes (string, tempBuffer + offset, strLen);
sysFlashWrite ((unsigned short *) tempBuffer); /* write new buffer */
free (tempBuffer); /* return memory */
return (OK);
}
@@ -0,0 +1,198 @@
/* m48t18NvRam.c - non-volatile RAM library for m48t18 */
/*
* Copyright (c) 1995, 2012 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01c,26nov12,ylu prevent context switch when read/write NvRam. (WIND00076071)
01b,25jan95,vin made it generic for both I/O mapped as well as memory mapped.
01a,24jan95,kvk created from 01d of nvRam.c.
*/
/*
DESCRIPTION
This library contains routines to manipulate non-volatile RAM which is
accessed as normal RAM (e.g. battery backed RAM). Read and write routines
are included. All non-volatile RAM accesses are byte wide.
The macro NV_RAM_ADRS must be defined to point to the first byte of
non-volatile memory. The macro NV_RAM_SIZE must be defined to provide parameter
checking for sysNvRamSet() and sysNvRamGet().
*/
/* local defines */
#define NV_RAM_ADRS_MASK 0x0000FFFF
/* forward declarations */
#ifdef NV_RAM_IO_MAPPED
static void m4818Read (char * string, int strLen, USHORT addr);
static void m4818Write (char * string, int strLen, USHORT addr);
#endif /* NV_RAM_IO_MAPPED */
/******************************************************************************
*
* sysNvRamGet - get the contents of non-volatile RAM
*
* This routine copies the contents of non-volatile memory into a specified
* string. The string will be terminated with an EOS.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* SEE ALSO: sysNvRamSet()
*/
STATUS sysNvRamGet
(
char *string, /* where to copy non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return (ERROR);
#ifdef NV_RAM_IO_MAPPED /* nvram is io mapped */
m4818Read (string, strLen, (USHORT)((ULONG)(NV_RAM_ADRS + offset) &
NV_RAM_ADRS_MASK));
#else /* nvram is memory mapped */
bcopyBytes (NV_RAM_ADRS + offset, string, strLen);
#endif /* NV_RAM_IO_MAPPED */
string [strLen] = EOS;
return (OK);
}
/*******************************************************************************
*
* sysNvRamSet - write to non-volatile RAM
*
* This routine copies a specified string into non-volatile RAM.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* SEE ALSO: sysNvRamGet()
*/
STATUS sysNvRamSet
(
char *string, /* string to be copied into non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return (ERROR);
#ifdef NV_RAM_IO_MAPPED /* nvram is iomapped */
m4818Write (string, strLen, (USHORT)((ULONG)(NV_RAM_ADRS + offset) &
NV_RAM_ADRS_MASK));
#else /* nvram is memory mapped */
bcopyBytes (string, NV_RAM_ADRS + offset, strLen);
#endif /* NV_RAM_IO_MAPPED */
return (OK);
}
#ifdef NV_RAM_IO_MAPPED
/*******************************************************************************
*
* m4818Read - read from I/O mapped non-volatile RAM
*
* This routine copies non-volatile RAM to a specified string.
*
* RETURNS: N/A
*
* NOMANUAL
*/
static void m4818Read
(
char * string, /* string to copy to non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
USHORT offset /* byte offset into non-volatile RAM */
)
{
int ix;
taskCpuLock(); /* prevent context switch */
for(ix = 0; ix < strLen; offset++, ix++)
{
sysOutByte (NV_RAM_LSB_REG, LSB(offset));
sysOutByte (NV_RAM_MSB_REG, MSB(offset));
*string++ = (char)sysInByte (NV_RAM_DAT_REG);
}
taskCpuUnlock();
}
/*******************************************************************************
*
* m4818Write - Write to I/O mapped non-volatile RAM
*
* This routine copies a specified string to non-volatile RAM.
*
* RETURNS: N/A
*
* NOMANUAL
*/
static void m4818Write
(
char * string, /* string to copy to non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
USHORT offset /* byte offset into non-volatile RAM */
)
{
int ix;
taskCpuLock(); /* prevent context switch */
for(ix = 0; ix < strLen; string++, offset++, ix++)
{
sysOutByte (NV_RAM_LSB_REG, LSB(offset));
sysOutByte (NV_RAM_MSB_REG, MSB(offset));
sysOutByte (NV_RAM_DAT_REG, *string);
}
taskCpuUnlock();
}
#endif /* NV_RAM_IO_MAPPED */
+333
View File
@@ -0,0 +1,333 @@
/* m8260Flash.c - Flash memory device driver for 28F016 flash devices */
/* Copyright 1984-1999 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01d,15jul99,ms_ make compliant with our coding standards
01c,05jun99,cn added sysFlashUpdate, updated documentation, removed
unnecessary code.
01b,28may99,ms_ get flash28.h locally, not from the driver include location
01a,05may99,cn derived from version 01k of mem/flashMem.c.
*/
/*
DESCRIPTION
This library contains routines to manipulate the 28F016 flash memory. Read
and write routines are included.
The macro values FLASH_ADRS, FLASH_SIZE, and FLASH_WIDTH must be defined to
indicate the address, size (in bytes), and the data-access width (in bytes) of
the flash memory. Besides, the macro FLASH_SIZE_WRITEABLE should be defined
to a reasonable amount of flash-memory that needs to be modified. In fact,
the user is not likely to need to change the entire contents of the device.
*/
#include "drv/mem/flash28.h"
/* defines */
#define FLASH_DEF UINT32
#define FLASH_CAST (UINT32 *)
#define FLASH_BLK_SZ 0x10000
#define FLASH_ALIGN_SZ (FLASH_BLK_SZ * FLASH_WIDTH)
#ifdef FLASH_SIZE_WRITEABLE
# define FLASH_MEM_SIZE FLASH_SIZE_WRITEABLE
#else
# define FLASH_MEM_SIZE FLASH_SIZE
#endif /* FLASH_SIZE_WRITEABLE */
/* globals */
/* forward declarations */
STATUS sysFlashErase (UINT32 offset);
STATUS sysFlashWrite (FLASH_DEF * pFB, UINT32 size, UINT32 offset,
FLASH_DEF value);
STATUS sysFlashGet (UCHAR * string, UINT32 strLen, UINT32 offset);
UINT8 sysFlashTypeGet (void);
STATUS sysFlashUpdate (UCHAR * filename);
/******************************************************************************
*
* sysFlashGet - get the contents of flash memory
*
* This routine copies the contents of flash memory into a specified
* string. The string is terminated with an EOS.
*
* RETURNS: OK, or ERROR if access is outside the flash memory range.
*
* SEE ALSO: sysFlashSet()
*
* INTERNAL
* If multiple tasks are calling sysFlashSet() and sysFlashGet(),
* they should use a semaphore to ensure mutually exclusive access.
*/
STATUS sysFlashGet
(
UCHAR * string, /* where to copy flash memory */
UINT32 strLen, /* maximum number of bytes to copy */
UINT32 offset /* byte offset into flash memory */
)
{
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > FLASH_MEM_SIZE))
return (ERROR);
bcopyBytes ((char *) (FLASH_ADRS + offset), string, strLen);
string [strLen] = EOS;
return (OK);
}
/******************************************************************************
*
* sysFlashErase - erase the contents of flash memory
*
* This routine clears the contents of flash memory from the specified
* <offset> up to the top.
*
* Flash 28F016 devices support block erase mode. This means each of the 32
* 64-KByte blocks is erased by writing a flash erase command to
* the device at any address within the target block, and verifying that
* the operation completed successfully.
*
* RETURNS: OK, or ERROR if the contents of flash memory cannot be erased.
*/
STATUS sysFlashErase
(
UINT32 offset /* offset from flash base address */
)
{
volatile FLASH_DEF * pFA = FLASH_CAST (offset + FLASH_ADRS);
STATUS retVal = OK;
*pFA = FLASH28_CMD_RESET;
for (; (pFA <= FLASH_CAST (FLASH_ADRS + ((UINT32) FLASH_MEM_SIZE - 1)))
&& (retVal == OK); pFA += FLASH_BLK_SZ)
{
*pFA = FLASH28_CMD_ERASE_SETUP; /* setup */
*pFA = FLASH28F008_CMD_ERASE; /* erase */
/* Check Write State Machine Status */
do
*pFA = FLASH28F008_CMD_READ_STATUS;
while ((*pFA & FLASH28F008_STAT_WSMS) != FLASH28F008_STAT_WSMS);
/* Check Erase Error Status */
if ((*pFA & FLASH28F008_STAT_EWS) != 0)
{
*pFA = FLASH28F008_CMD_CLEAR_STATUS;
retVal = ERROR;
}
/* check we are at the last block */
if (pFA >= FLASH_CAST (FLASH_ADRS + (FLASH_MEM_SIZE - FLASH_ALIGN_SZ)))
break;
}
pFA = FLASH_CAST (FLASH_ADRS);
*pFA = FLASH28_CMD_RESET;
return (retVal);
}
/******************************************************************************
*
* sysFlashWrite - write data to flash memory
*
* This routine copies specified data of a specified length, <size>, into a
* specified offset, <offset>, in the flash memory. Data is passed as a string,
* <pFB>, if not NULL. If NULL, data is taken as a repeated sequence of
* <value>.
* The parameter <offset> must be appropriately aligned for the width of
* the Flash devices in use.
*
* Flash 28F016 devices are programmed by a sequence of operations:
* .iP
* set up device to write
* .iP
* perform write
* .iP
* verify the write
* .LP
*
* RETURNS: OK, or ERROR if the write operation fails.
*
* SEE ALSO: sysFlashSet()
*/
STATUS sysFlashWrite
(
FLASH_DEF * pFB, /* string to be copied; use <value> if NULL */
UINT32 size, /* size to program in bytes */
UINT32 offset, /* byte offset into flash memory */
FLASH_DEF value /* value to program */
)
{
volatile FLASH_DEF * pFA = FLASH_CAST (FLASH_ADRS); /* flash address */
STATUS retVal = OK;
*pFA = FLASH28_CMD_RESET;
for (pFA = FLASH_CAST (FLASH_ADRS + offset); (pFA < FLASH_CAST
(FLASH_ADRS + size + offset)) && (retVal == OK); pFA++)
{
if (pFB != NULL)
value = *pFB++;
*pFA = FLASH28_CMD_PROG_SETUP; /* write setup */
*pFA = value; /* data to write */
/* Check Write State Machine Status */
do
{
*pFA = FLASH28F008_CMD_READ_STATUS;
}
while ((*pFA & FLASH28F008_STAT_WSMS) != FLASH28F008_STAT_WSMS);
/* Check Byte Write Error Status */
if ((*pFA & FLASH28F008_STAT_BWS) != 0)
{
*pFA = FLASH28F008_CMD_CLEAR_STATUS;
retVal = ERROR;
}
}
pFA = FLASH_CAST (FLASH_ADRS);
*pFA = FLASH28_CMD_RESET;
return (retVal);
}
/******************************************************************************
*
* sysFlashTypeGet - determine the device type of on-board flash memory
*
* This routine uses the `read identifier code' command to determine the
* device type of * on-board flash memory. The returned value should be
* the one in drv/mem/flash28.h
*
* RETURNS: An integer indicating the device type of on-board flash memory.
*/
UINT8 sysFlashTypeGet (void)
{
volatile FLASH_DEF * pFA = FLASH_CAST (FLASH_ADRS); /* flash address */
UINT8 retVal;
UINT32 temp;
*pFA = FLASH28_CMD_RESET;
*pFA = FLASH28_CMD_READ_ID;
temp = (UINT32) *++pFA;
retVal = (UINT8) temp;
*pFA = FLASH28_CMD_RESET;
return (retVal);
}
/******************************************************************************
*
* sysFlashUpdate - update the contents of the flash device
*
* This code allows the user to overwrite the flash device with data from
* a file. It will copy data from "filename" to the flash device. It first
* erase the device, and it attempts to write data to the flash device
* via sysFlashWrite ().
*
* The user should pass a binary bootrom file, for example
* to update the bootrom with a VxWorks BSP bootrom image:
* .CS
* % make bootrom
* make: `bootrom' is up to date.
* % elfToBin < bootrom > bootrom.bin
*
* -> sysUpdateFlash ("hostname:/tmp/bootrom.bin")
* The flash has been updated without error.
* .CE
*
* RETURNS: OK, or ERROR: if the file was not accessable, the
* file was too large to fit into the flash, the buffers cannot
* be allocated, sysFlashErase () or sysFlashWrite () returned error.
*
* SEE ALSO: sysFlashErase(), sysFlashGet(), sysFlashTypeGet(), sysFlashWrite()
*
* INTERNAL
* If multiple tasks are calling sysFlashSet() and sysFlashGet(),
* they should use a semaphore to ensure mutually exclusive access to flash
* memory.
*/
STATUS sysFlashUpdate
(
UCHAR * filename /* file to be copied into flash memory */
)
{
UCHAR * pMemBuf; /* holds the flash data */
int fd; /* the bootrom image fd */
int statReturn; /* return values */
/* first step is to open the file */
if ((fd = open (filename, O_RDONLY, 0444)) == ERROR)
return (ERROR);
/* now we read it */
pMemBuf = calloc (FLASH_MEM_SIZE, 1);
if (pMemBuf == NULL)
{
printErr ("sysFlashUpdate: ");
printErr ("Could not allocate 0x%x bytes.\n", (long) FLASH_MEM_SIZE);
close (fd);
return (ERROR);
}
statReturn = read (fd, pMemBuf, FLASH_MEM_SIZE);
if ((statReturn > FLASH_MEM_SIZE) || (statReturn <= 0))
{
printErr ("Failed to read from file \n");
close (fd);
free (pMemBuf);
return (ERROR);
}
/* see if contents are actually changing */
if (bcmp ((char *) (FLASH_ADRS), pMemBuf, FLASH_MEM_SIZE) == 0)
return (OK);
/* now we can erase the device */
if (sysFlashErase (0) == ERROR)
return (ERROR);
/* write to the device */
if (sysFlashWrite ((FLASH_DEF *) pMemBuf, statReturn, 0, 0) == ERROR)
{
printErr ("Failed to write to the device \n");
close (fd);
free (pMemBuf);
return (ERROR);
}
return (OK);
}
@@ -0,0 +1,455 @@
/* m82xxDpramLib.c - 82xx DPRAM memory allocation driver */
/*
* Copyright (c) 1984-2005 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01g,26aug05,mil Converted memset to bzero.
01f,23mar05,dtr Merged from T2.2.1.
01e,22sep04,mdo Documentation fixes for apigen
01e,28jan04,dtr Make DPRAM size and offsets configurable in BSP.
01d,26nov01,rcs renamed m82xxDpramLib.c and moved to target/src/drv/mem
01c,12oct01,g_h Cleaning for T2.2
01b,17jul01,g_h Cleaning and renaming to sys82xxDpramLib.c
01a,16jul01,p_h Created
*/
/*
DESCRIPTION
This module contains 82xx DPRAM memory allocation driver.
INCLUDES: m82xxDpramLib.h
*/
/* include */
#include <drv/mem/m82xxDpramLib.h>
/* globals */
#ifndef M82XX_STANDARD_DPRAM_START
#define M82XX_STANDARD_DPRAM_START 0x100
#endif
#ifndef M82XX_STANDARD_DPRAM_LIMIT
#define M82XX_STANDARD_DPRAM_LIMIT 0x4000
#endif
#ifndef M82XX_FCC_DPRAM_START
#define M82XX_FCC_DPRAM_START 0xb000
#endif
#ifndef M82XX_FCC_DPRAM_LIMIT
#define M82XX_FCC_DPRAM_LIMIT 0xc000
#endif
/* external */
IMPORT UINT32 vxImmrGet(void);
/* local */
LOCAL ADDR_RESOURCE addrResPool[ALLOCTABLESIZE];
LOCAL POOL dprMainPool;
LOCAL POOL dprFccPool;
/* forward declaration */
/*******************************************************************************
*
* m82xxDpramAlignedAddr - aligns a given address
*
* This routine aligns a given address.
*
* RETURNS: new aligned address
*
* ERRNO
*
* SEE ALSO: m82xxDpramAllocRange(), m82xxDpramFindFreeEntry(),
* m82xxDpramAllocateRange(), m82xxDpramReleaseRenage(),
* m82xxDpramLibInit(), m82xxDpramMalloc(),
* m82xxDpramAlignedMalloc(), m82xxDpramFree(),
* m82xxDpramFccMalloc(), m82xxDpramFccFree()
*/
LOCAL UINT32 m82xxDpramAlignedAddr
(
UINT32 addr,
UINT32 alignment
)
{
if (alignment)
{
return((addr + alignment - 1) & ~(alignment - 1));
}
return (addr);
}
/*******************************************************************************
*
* m82xxDpramAllocRange - alloc aligned memory
*
* This routine alloc aligned memory
*
* RETURNS: OK
*
* ERRNO
*
* SEE ALSO: m82xxDpramAlignedAddr(), m82xxDpramFindFreeEntry(),
* m82xxDpramAllocateRange(), m82xxDpramReleaseRenage(),
* m82xxDpramLibInit(), m82xxDpramMalloc(),
* m82xxDpramAlignedMalloc(), m82xxDpramFree(),
* m82xxDpramFccMalloc(), m82xxDpramFccFree()
*/
LOCAL void * m82xxDpramAllocRange
(
ADDR_RESOURCE * pNew,
UINT32 length,
UINT32 alignment,
POOL * pPool
)
{
ADDR_RESOURCE * pPrev;
ADDR_RESOURCE * pCurr;
UINT32 gapEnd;
UINT32 gapStart = 0;
pCurr = pPool->pHead;
pPrev = 0;
do
{
if (pPrev)
{
gapStart = m82xxDpramAlignedAddr (pPrev->start + pPrev->size, alignment);
}
else
{
gapStart = m82xxDpramAlignedAddr (pPool->start, alignment);
}
if (pCurr)
{
gapEnd = pCurr->start;
}
else
{
gapEnd = pPool->limit;
}
if (gapEnd > gapStart)
{
if ((gapEnd - gapStart) >= length)
{
pNew->start = gapStart;
pNew->size = length;
pNew->pNext = pCurr;
if (pPrev)
{
pPrev->pNext = pNew;
}
if (!pPool->pHead)
{
pPool->pHead = pNew;
}
return((void*)(pNew->start));
}
}
pPrev = pCurr;
if (pCurr)
{
pCurr = pCurr->pNext;
}
} while (pCurr || pPrev);
return (OK);
}
/*******************************************************************************
*
* m82xxDpramFindFreeEntry - find first free entry in the linked list
*
* This routine locates the first free entry in the linked list.
*
* RETURNS: pointer to first free entry or 0 if every thing full
*
* ERRNO
*
* SEE ALSO: m82xxDpramAlignedAddr(), m82xxDpramAllocRange(),
* m82xxDpramAllocateRange(), m82xxDpramReleaseRenage(),
* m82xxDpramLibInit(), m82xxDpramMalloc(),
* m82xxDpramAlignedMalloc(), m82xxDpramFree(),
* m82xxDpramFccMalloc(), m82xxDpramFccFree()
*/
LOCAL ADDR_RESOURCE * m82xxDpramFindFreeEntry
(
void
)
{
int index;
for (index=0;index<ALLOCTABLESIZE;index++)
{
if (addrResPool[index].start == 0)
{
return &addrResPool[index];
}
}
return (0);
}
/*******************************************************************************
*
* m82xxDpramAllocateRange - allocate a range of memory
*
* This routine allocates a range of memory from the DPRAM.
*
* RETURNS: pointer to allocated memory or 0 if the is no free memory
*
* ERRNO
*
* SEE ALSO: m82xxDpramAlignedAddr(), m82xxDpramAllocRange(),
* m82xxDpramFindFreeEntry(), m82xxDpramReleaseRenage(),
* m82xxDpramLibInit(), m82xxDpramMalloc(),
* m82xxDpramAlignedMalloc(), m82xxDpramFree(),
* m82xxDpramFccMalloc(), m82xxDpramFccFree()
*/
LOCAL void * m82xxDpramAllocateRange
(
UINT32 requestedLength,
UINT32 alignment,
POOL * pPool
)
{
ADDR_RESOURCE * pNew;
if ((pNew = m82xxDpramFindFreeEntry ()) != NULL)
{
return m82xxDpramAllocRange (pNew, requestedLength, alignment ,pPool);
}
return 0;
}
/*******************************************************************************
*
* m82xxDpramReleaseRenage - release allocated range of memory
*
* This routine releases an allocated range of memory from the DPRAM.
*
* RETURNS: N/A
*
* ERRNO
*
* SEE ALSO: m82xxDpramAlignedAddr(), m82xxDpramAllocRange(),
* m82xxDpramFindFreeEntry(), m82xxDpramAllocateRange(),
* m82xxDpramLibInit(), m82xxDpramMalloc(),
* m82xxDpramAlignedMalloc(), m82xxDpramFree(),
* m82xxDpramFccMalloc(), m82xxDpramFccFree()
*/
LOCAL void m82xxDpramReleaseRenage
(
UINT32 start,
POOL * pPool
)
{
ADDR_RESOURCE *pCurr, *pPrev;
pCurr = pPool->pHead;
pPrev = 0;
while (pCurr)
{
if (pCurr->start == start)
{
if (pPrev)
{
pPrev->pNext = pCurr->pNext;
}
else
{
pPool->pHead = pCurr->pNext;
}
/* clear the released AddrResource structure */
bzero ((void *)pCurr, sizeof(ADDR_RESOURCE));
return;
}
pPrev = pCurr;
pCurr = pCurr->pNext;
}
return;
}
/*******************************************************************************
*
* m82xxDpramLibInit - init DPRAM memory allocation driver
*
* This routine initializes the DPRAM memory allocation driver.
*
* RETURNS: N/A
*
* ERRNO
*
* SEE ALSO: m82xxDpramMalloc(), m82xxDpramAlignedMalloc(),
* m82xxDpramFree(), m82xxDpramFccMalloc(),
* m82xxDpramFccFree()
*/
void m82xxDpramLibInit
(
void
)
{
UINT32 immr = vxImmrGet (); /* find the DPRAM start address */
/* check for uCode */
UINT32 rccr = (*(UINT32 *)(immr + 0x119C4) & 0xE000) >> 2;
/* init the main dpram memory pool */
dprMainPool.start = immr + rccr + M82XX_STANDARD_DPRAM_START;
dprMainPool.limit = immr + M82XX_STANDARD_DPRAM_LIMIT -1;
dprMainPool.pHead = 0;
/* init the special section memory pool (need for FCC in ATM or ETH mode)*/
dprFccPool.start = immr + M82XX_FCC_DPRAM_START;
dprFccPool.limit = immr + M82XX_FCC_DPRAM_LIMIT - 1;
dprFccPool.pHead = 0;
/* clear the AddrResource pool */
bzero ((void *)addrResPool, sizeof(ADDR_RESOURCE) * ALLOCTABLESIZE);
}
/*******************************************************************************
*
* m82xxDpramMalloc - allocate memory from DPRAM main pool
*
* This routine allocates memory from the DPRAM main pool.
*
* RETURNS: pointer to allocated memory
*
* ERRNO
*
* SEE ALSO: m82xxDpramLibInit(), m82xxDpramAlignedMalloc(),
* m82xxDpramFree(), m82xxDpramFccMalloc(),
* m82xxDpramFccFree()
*/
void * m82xxDpramMalloc
(
size_t length
)
{
return (m82xxDpramAllocateRange (length,0,&dprMainPool));
}
/*******************************************************************************
*
* m82xxDpramAlignedMalloc - allocate aligned memory from DPRAM main pool
*
* This routine allocates aligned memory from the DPRAM main pool.
*
* RETURNS: pointer to allocated aligned memory
*
* ERRNO
*
* SEE ALSO: m82xxDpramLibInit(), m82xxDpramMalloc(),
* m82xxDpramFree(), m82xxDpramFccMalloc(),
* m82xxDpramFccFree()
*/
void * m82xxDpramAlignedMalloc
(
size_t length,
size_t alignment
)
{
return (m82xxDpramAllocateRange (length, alignment,&dprMainPool));
}
/*******************************************************************************
*
* m82xxDpramFree - free allocated memory from DPRAM main pool
*
* This routine frees allocated memory from the DPRAM main pool.
*
* RETURNS: N/A
*
* ERRNO
*
* SEE ALSO: m82xxDpramLibInit(), m82xxDpramMalloc(),
* m82xxDpramAlignedMalloc(), m82xxDpramFccMalloc(),
* m82xxDpramFccFree()
*/
void m82xxDpramFree
(
void * addr
)
{
m82xxDpramReleaseRenage ((UINT32)addr,&dprMainPool);
}
/*******************************************************************************
*
* m82xxDpramFccMalloc - allocate memory from DPRAM FCC special pool
*
* This routine allocates memory from the DPRAM FCC special pool.
*
* RETURNS: pointer to allocated memory
*
* ERRNO
*
* SEE ALSO: m82xxDpramLibInit(), m82xxDpramMalloc(),
* m82xxDpramAlignedMalloc(), m82xxDpramFree(),
* m82xxDpramFccFree()
*/
void * m82xxDpramFccMalloc
(
size_t length,
size_t alignment
)
{
return (m82xxDpramAllocateRange(length, alignment,&dprFccPool));
}
/*******************************************************************************
*
* m82xxDpramFccFree - free allocated memory from DPRAM FCC special pool
*
* This routine free allocated memory from DPRAM FCC special pool.
*
* RETURNS: pointer to allocated memory
*
* ERRNO
*
* SEE ALSO: m82xxDpramLibInit(), m82xxDpramMalloc(),
* m82xxDpramAlignedMalloc(), m82xxDpramFree(),
* m82xxDpramFccMalloc()
*/
void m82xxDpramFccFree
(
void * addr
)
{
m82xxDpramReleaseRenage ((UINT32)addr,&dprFccPool);
}
@@ -0,0 +1,73 @@
/* nullNvRam.c - null non-volatile RAM library */
/* Copyright 1984-1996 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01g,25jun96,wlf doc: cleanup.
01f,04jun96,wlf doc: cleanup.
01e,24may96,wlf doc: cleanup.
01d,15dec92,caf reinstated version 01b.
01c,21oct92,ccc fixed ansi warnings.
01b,17jul92,caf changed nullNvram.c to nullNvRam.c.
01a,26jun92,caf created.
*/
/*
DESCRIPTION
This library contains non-volatile RAM manipulation routines for targets
lacking non-volatile RAM. Read and write routines that return ERROR
are included.
The macro NV_RAM_SIZE should be defined as NONE for targets lacking
non-volatile RAM.
*/
/******************************************************************************
*
* sysNvRamGet - get the contents of non-volatile RAM
*
* This routine copies the contents of non-volatile memory into a specified
* string. The string is terminated with an EOS.
*
* NOTE: This routine has no effect, since there is no non-volatile RAM.
*
* RETURNS: ERROR, always.
*
* SEE ALSO: sysNvRamSet()
*/
STATUS sysNvRamGet
(
char *string, /* where to copy non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
return (ERROR);
}
/*******************************************************************************
*
* sysNvRamSet - write to non-volatile RAM
*
* This routine copies a specified string into non-volatile RAM.
*
* NOTE: This routine has no effect, since there is no non-volatile RAM.
*
* RETURNS: ERROR, always.
*
* SEE ALSO: sysNvRamGet()
*/
STATUS sysNvRamSet
(
char *string, /* string to be copied into non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
return (ERROR);
}
+86
View File
@@ -0,0 +1,86 @@
/* nvRam.c - non-volatile RAM library */
/* Copyright 1984-1996 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01f,18jun96,wlf doc: cleanup.
01e,24may96,wlf doc: cleanup.
01d,28jan93,caf made boot line begin at offset 0 (SPR #1933).
01c,02sep92,caf changed nvRamLib.c to nvRam.c. changed NV_BOOT_LINE to
NV_RAM_ADRS. tweaked documentation.
01b,29jun92,caf changed bbRamLib.c to nvRamLib.c. tweaked documentation.
01a,26jun92,caf derived from sysNvRamSet() and sysNvRamGet() in PortKit.
*/
/*
DESCRIPTION
This library contains routines to manipulate non-volatile RAM which is
accessed as normal RAM (e.g., battery backed RAM). Read and write routines
are included. All non-volatile RAM accesses are byte wide.
The macro NV_RAM_ADRS must be defined to point to the first byte of
non-volatile memory. The macro NV_RAM_SIZE must be defined to provide parameter
checking for sysNvRamSet() and sysNvRamGet().
*/
/******************************************************************************
*
* sysNvRamGet - get the contents of non-volatile RAM
*
* This routine copies the contents of non-volatile memory into a specified
* string. The string is terminated with an EOS.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* SEE ALSO: sysNvRamSet()
*/
STATUS sysNvRamGet
(
char *string, /* where to copy non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return (ERROR);
bcopyBytes (NV_RAM_ADRS + offset, string, strLen);
string [strLen] = EOS;
return (OK);
}
/*******************************************************************************
*
* sysNvRamSet - write to non-volatile RAM
*
* This routine copies a specified string into non-volatile RAM.
*
* RETURNS: OK, or ERROR if access is outside the non-volatile RAM range.
*
* SEE ALSO: sysNvRamGet()
*/
STATUS sysNvRamSet
(
char *string, /* string to be copied into non-volatile RAM */
int strLen, /* maximum number of bytes to copy */
int offset /* byte offset into non-volatile RAM */
)
{
offset += NV_BOOT_OFFSET; /* boot line begins at <offset> = 0 */
if ((offset < 0) || (strLen < 0) || ((offset + strLen) > NV_RAM_SIZE))
return (ERROR);
bcopyBytes (string, NV_RAM_ADRS + offset, strLen);
return (OK);
}

Some files were not shown because too many files have changed in this diff Show More