Index: head/sys/contrib/ncsw/inc/xx_ext.h =================================================================== --- head/sys/contrib/ncsw/inc/xx_ext.h (revision 358321) +++ head/sys/contrib/ncsw/inc/xx_ext.h (revision 358322) @@ -1,798 +1,797 @@ /* Copyright (c) 2008-2012 Freescale Semiconductor, Inc * 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 Freescale Semiconductor nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * * ALTERNATIVELY, this software may be distributed under the terms of the * GNU General Public License ("GPL") as published by the Free Software * Foundation, either version 2 of that License or (at your option) any * later version. * * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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. */ /**************************************************************************//** @File xx_ext.h @Description Prototypes, externals and typedefs for system-supplied (external) routines *//***************************************************************************/ #ifndef __XX_EXT_H #define __XX_EXT_H #include "std_ext.h" #include "xx_common.h" #include "part_ext.h" /**************************************************************************//** @Group xx_id XX Interface (System call hooks) @Description Prototypes, externals and typedefs for system-supplied (external) routines @{ *//***************************************************************************/ #ifdef DEBUG_XX_MALLOC void * XX_MallocDebug(uint32_t size, char *fname, int line); void * XX_MallocSmartDebug(uint32_t size, int memPartitionId, uint32_t alignment, char *fname, int line); #define XX_Malloc(sz) \ XX_MallocDebug((sz), __FILE__, __LINE__) #define XX_MallocSmart(sz, memt, al) \ XX_MallocSmartDebug((sz), (memt), (al), __FILE__, __LINE__) #else /* not DEBUG_XX_MALLOC */ /**************************************************************************//** @Function XX_Malloc @Description allocates contiguous block of memory. @Param[in] size - Number of bytes to allocate. @Return The address of the newly allocated block on success, NULL on failure. *//***************************************************************************/ void * XX_Malloc(uint32_t size); /**************************************************************************//** @Function XX_MallocSmart @Description Allocates contiguous block of memory in a specified alignment and from the specified segment. @Param[in] size - Number of bytes to allocate. @Param[in] memPartitionId - Memory partition ID; The value zero must be mapped to the default heap partition. @Param[in] alignment - Required memory alignment (in bytes). @Return The address of the newly allocated block on success, NULL on failure. *//***************************************************************************/ void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment); int XX_MallocSmartInit(void); #endif /* not DEBUG_XX_MALLOC */ /**************************************************************************//** @Function XX_FreeSmart @Description Frees the memory block pointed to by "p". Only for memory allocated by XX_MallocSmart @Param[in] p_Memory - pointer to the memory block. @Return None. *//***************************************************************************/ void XX_FreeSmart(void *p_Memory); /**************************************************************************//** @Function XX_Free @Description frees the memory block pointed to by "p". @Param[in] p_Memory - pointer to the memory block. @Return None. *//***************************************************************************/ void XX_Free(void *p_Memory); /**************************************************************************//** @Function XX_Print @Description print a string. @Param[in] str - string to print. @Return None. *//***************************************************************************/ void XX_Print(char *str, ...); /**************************************************************************//** @Function XX_SetIntr @Description Set an interrupt service routine for a specific interrupt source. @Param[in] irq - Interrupt ID (system-specific number). @Param[in] f_Isr - Callback routine that will be called when the interrupt occurs. @Param[in] handle - The argument for the user callback routine. @Return E_OK on success; error code otherwise.. *//***************************************************************************/ t_Error XX_SetIntr(uintptr_t irq, t_Isr *f_Isr, t_Handle handle); /**************************************************************************//** @Function XX_FreeIntr @Description Free a specific interrupt and a specific callback routine. @Param[in] irq - Interrupt ID (system-specific number). @Return E_OK on success; error code otherwise.. *//***************************************************************************/ t_Error XX_FreeIntr(uintptr_t irq); /**************************************************************************//** @Function XX_EnableIntr @Description Enable a specific interrupt. @Param[in] irq - Interrupt ID (system-specific number). @Return E_OK on success; error code otherwise.. *//***************************************************************************/ t_Error XX_EnableIntr(uintptr_t irq); /**************************************************************************//** @Function XX_DisableIntr @Description Disable a specific interrupt. @Param[in] irq - Interrupt ID (system-specific number). @Return E_OK on success; error code otherwise.. *//***************************************************************************/ t_Error XX_DisableIntr(uintptr_t irq); /**************************************************************************//** @Function XX_DisableAllIntr @Description Disable all interrupts by masking them at the CPU. @Return A value that represents the interrupts state before the operation, and should be passed to the matching XX_RestoreAllIntr() call. *//***************************************************************************/ uint32_t XX_DisableAllIntr(void); /**************************************************************************//** @Function XX_RestoreAllIntr @Description Restore previous state of interrupts level at the CPU. @Param[in] flags - A value that represents the interrupts state to restore, as returned by the matching call for XX_DisableAllIntr(). @Return None. *//***************************************************************************/ void XX_RestoreAllIntr(uint32_t flags); t_Error XX_PreallocAndBindIntr(device_t dev, uintptr_t irq, unsigned int cpu); t_Error XX_DeallocIntr(uintptr_t irq); /**************************************************************************//** @Function XX_Exit @Description Stop execution and report status (where it is applicable) @Param[in] status - exit status *//***************************************************************************/ void XX_Exit(int status); /*****************************************************************************/ /* Tasklet Service Routines */ /*****************************************************************************/ typedef t_Handle t_TaskletHandle; /**************************************************************************//** @Function XX_InitTasklet @Description Create and initialize a tasklet object. @Param[in] routine - A routine to be ran as a tasklet. @Param[in] data - An argument to pass to the tasklet. @Return Tasklet handle is returned on success. NULL is returned otherwise. *//***************************************************************************/ t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data); /**************************************************************************//** @Function XX_FreeTasklet @Description Free a tasklet object. @Param[in] h_Tasklet - A handle to a tasklet to be free. @Return None. *//***************************************************************************/ void XX_FreeTasklet (t_TaskletHandle h_Tasklet); /**************************************************************************//** @Function XX_ScheduleTask @Description Schedule a tasklet object. @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. @Param[in] immediate - Indicate whether to schedule this tasklet on the immediate queue or on the delayed one. @Return 0 - on success. Error code - otherwise. *//***************************************************************************/ int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate); /**************************************************************************//** @Function XX_FlushScheduledTasks @Description Flush all tasks there are in the scheduled tasks queue. @Return None. *//***************************************************************************/ void XX_FlushScheduledTasks(void); /**************************************************************************//** @Function XX_TaskletIsQueued @Description Check if task is queued. @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. @Return 1 - task is queued. 0 - otherwise. *//***************************************************************************/ int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet); /**************************************************************************//** @Function XX_SetTaskletData @Description Set data to a scheduled task. Used to change data of already scheduled task. @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. @Param[in] data - Data to be set. *//***************************************************************************/ void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data); /**************************************************************************//** @Function XX_GetTaskletData @Description Get the data of scheduled task. @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. @Return handle to the data of the task. *//***************************************************************************/ t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet); /**************************************************************************//** @Function XX_BottomHalf @Description Bottom half implementation, invoked by the interrupt handler. This routine handles all bottom-half tasklets with interrupts enabled. @Return None. *//***************************************************************************/ void XX_BottomHalf(void); /*****************************************************************************/ /* Spinlock Service Routines */ /*****************************************************************************/ /**************************************************************************//** @Function XX_InitSpinlock @Description Creates a spinlock. @Return Spinlock handle is returned on success; NULL otherwise. *//***************************************************************************/ t_Handle XX_InitSpinlock(void); /**************************************************************************//** @Function XX_FreeSpinlock @Description Frees the memory allocated for the spinlock creation. @Param[in] h_Spinlock - A handle to a spinlock. @Return None. *//***************************************************************************/ void XX_FreeSpinlock(t_Handle h_Spinlock); /**************************************************************************//** @Function XX_LockSpinlock @Description Locks a spinlock. @Param[in] h_Spinlock - A handle to a spinlock. @Return None. *//***************************************************************************/ void XX_LockSpinlock(t_Handle h_Spinlock); /**************************************************************************//** @Function XX_UnlockSpinlock @Description Unlocks a spinlock. @Param[in] h_Spinlock - A handle to a spinlock. @Return None. *//***************************************************************************/ void XX_UnlockSpinlock(t_Handle h_Spinlock); /**************************************************************************//** @Function XX_LockIntrSpinlock @Description Locks a spinlock (interrupt safe). @Param[in] h_Spinlock - A handle to a spinlock. @Return A value that represents the interrupts state before the operation, and should be passed to the matching XX_UnlockIntrSpinlock() call. *//***************************************************************************/ uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock); /**************************************************************************//** @Function XX_UnlockIntrSpinlock @Description Unlocks a spinlock (interrupt safe). @Param[in] h_Spinlock - A handle to a spinlock. @Param[in] intrFlags - A value that represents the interrupts state to restore, as returned by the matching call for XX_LockIntrSpinlock(). @Return None. *//***************************************************************************/ void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags); /*****************************************************************************/ /* Timers Service Routines */ /*****************************************************************************/ /**************************************************************************//** @Function XX_CurrentTime @Description Returns current system time. @Return Current system time (in milliseconds). *//***************************************************************************/ uint32_t XX_CurrentTime(void); /**************************************************************************//** @Function XX_CreateTimer @Description Creates a timer. @Return Timer handle is returned on success; NULL otherwise. *//***************************************************************************/ t_Handle XX_CreateTimer(void); /**************************************************************************//** @Function XX_FreeTimer @Description Frees the memory allocated for the timer creation. @Param[in] h_Timer - A handle to a timer. @Return None. *//***************************************************************************/ void XX_FreeTimer(t_Handle h_Timer); /**************************************************************************//** @Function XX_StartTimer @Description Starts a timer. The user can select to start the timer as periodic timer or as one-shot timer. The user should provide a callback routine that will be called when the timer expires. @Param[in] h_Timer - A handle to a timer. @Param[in] msecs - Timer expiration period (in milliseconds). @Param[in] periodic - TRUE for a periodic timer; FALSE for a one-shot timer.. @Param[in] f_TimerExpired - A callback routine to be called when the timer expires. @Param[in] h_Arg - The argument to pass in the timer-expired callback routine. @Return None. *//***************************************************************************/ void XX_StartTimer(t_Handle h_Timer, uint32_t msecs, bool periodic, void (*f_TimerExpired)(t_Handle h_Arg), t_Handle h_Arg); /**************************************************************************//** @Function XX_StopTimer @Description Frees the memory allocated for the timer creation. @Param[in] h_Timer - A handle to a timer. @Return None. *//***************************************************************************/ void XX_StopTimer(t_Handle h_Timer); /**************************************************************************//** @Function XX_ModTimer @Description Updates the expiration time of a timer. This routine adds the given time to the current system time, and sets this value as the new expiration time of the timer. @Param[in] h_Timer - A handle to a timer. @Param[in] msecs - The new interval until timer expiration (in milliseconds). @Return None. *//***************************************************************************/ void XX_ModTimer(t_Handle h_Timer, uint32_t msecs); /**************************************************************************//** @Function XX_Sleep @Description Non-busy wait until the desired time (in milliseconds) has passed. @Param[in] msecs - The requested sleep time (in milliseconds). @Return Zero if the requested time has elapsed; Otherwise, the value returned will be the unslept amount) in milliseconds. @Cautions This routine enables interrupts during its wait time. *//***************************************************************************/ uint32_t XX_Sleep(uint32_t msecs); /**************************************************************************//** @Function XX_UDelay @Description Busy-wait until the desired time (in microseconds) has passed. @Param[in] usecs - The requested delay time (in microseconds). @Return None. @Cautions It is highly unrecommended to call this routine during interrupt time, because the system time may not be updated properly during the delay loop. The behavior of this routine during interrupt time is unexpected. *//***************************************************************************/ void XX_UDelay(uint32_t usecs); /*****************************************************************************/ /* Other Service Routines */ /*****************************************************************************/ /**************************************************************************//** @Function XX_PhysToVirt @Description Translates a physical address to the matching virtual address. @Param[in] addr - The physical address to translate. @Return Virtual address. *//***************************************************************************/ void * XX_PhysToVirt(physAddress_t addr); /**************************************************************************//** @Function XX_VirtToPhys @Description Translates a virtual address to the matching physical address. @Param[in] addr - The virtual address to translate. @Return Physical address. *//***************************************************************************/ physAddress_t XX_VirtToPhys(void *addr); /**************************************************************************//** @Group xx_ipc XX Inter-Partition-Communication API @Description The following API is to be used when working with multiple partitions configuration. @{ *//***************************************************************************/ #define XX_IPC_MAX_ADDR_NAME_LENGTH 16 /**< Maximum length of an endpoint name string; The IPC service can use this constant to limit the storage space for IPC endpoint names. */ /**************************************************************************//** @Function t_IpcMsgCompletion @Description Callback function used upon IPC non-blocking transaction completion to return message buffer to the caller and to forward reply if available. This callback function may be attached by the source endpoint to any outgoing IPC message to indicate a non-blocking send (see also XX_IpcSendMessage() routine). Upon completion of an IPC transaction (consisting of a message and an optional reply), the IPC service invokes this callback routine to return the message buffer to the sender and to provide the received reply, if requested. User provides this function. Driver invokes it. @Param[in] h_Module - Abstract handle to the sending module - the same handle as was passed in the XX_IpcSendMessage() function; This handle is typically used to point to the internal data structure of the source endpoint. @Param[in] p_Msg - Pointer to original (sent) message buffer; The source endpoint can free (or reuse) this buffer when message completion callback is called. @Param[in] p_Reply - Pointer to (received) reply buffer; This pointer is the same as was provided by the source endpoint in XX_IpcSendMessage(). @Param[in] replyLength - Length (in bytes) of actual data in the reply buffer. @Param[in] status - Completion status - E_OK or failure indication, e.g. IPC transaction completion timeout. @Return None *//***************************************************************************/ typedef void (t_IpcMsgCompletion)(t_Handle h_Module, uint8_t *p_Msg, uint8_t *p_Reply, uint32_t replyLength, t_Error status); /**************************************************************************//** @Function t_IpcMsgHandler @Description Callback function used as IPC message handler. The IPC service invokes message handlers for each IPC message received. The actual function pointer should be registered by each destination endpoint via the XX_IpcRegisterMsgHandler() routine. User provides this function. Driver invokes it. @Param[in] h_Module - Abstract handle to the message handling module - the same handle as was passed in the XX_IpcRegisterMsgHandler() function; this handle is typically used to point to the internal data structure of the destination endpoint. @Param[in] p_Msg - Pointer to message buffer with data received from peer. @Param[in] msgLength - Length (in bytes) of message data. @Param[in] p_Reply - Pointer to reply buffer, to be filled by the message handler and then sent by the IPC service; The reply buffer is allocated by the IPC service with size equals to the replyLength parameter provided in message handler registration (see XX_IpcRegisterMsgHandler() function); If replyLength was initially specified as zero during message handler registration, the IPC service may set this pointer to NULL and assume that a reply is not needed; The IPC service is also responsible for freeing the reply buffer after the reply has been sent or dismissed. @Param[in,out] p_ReplyLength - Pointer to reply length, which has a dual role in this function: [In] equals the replyLength parameter provided in message handler registration (see XX_IpcRegisterMsgHandler() function), and [Out] should be updated by message handler to the actual reply length; if this value is set to zero, the IPC service must assume that a reply should not be sent; Note: If p_Reply is not NULL, p_ReplyLength must not be NULL as well. @Return E_OK on success; Error code otherwise. *//***************************************************************************/ typedef t_Error (t_IpcMsgHandler)(t_Handle h_Module, uint8_t *p_Msg, uint32_t msgLength, uint8_t *p_Reply, uint32_t *p_ReplyLength); /**************************************************************************//** @Function XX_IpcRegisterMsgHandler @Description IPC mailbox registration. This function is used for registering an IPC message handler in the IPC service. This function is called by each destination endpoint to indicate that it is ready to handle incoming messages. The IPC service invokes the message handler upon receiving a message addressed to the specified destination endpoint. @Param[in] addr - The address name string associated with the destination endpoint; This address must be unique across the IPC service domain to ensure correct message routing. @Param[in] f_MsgHandler - Pointer to the message handler callback for processing incoming message; invoked by the IPC service upon receiving a message addressed to the destination endpoint specified by the addr parameter. @Param[in] h_Module - Abstract handle to the message handling module, passed unchanged to f_MsgHandler callback function. @Param[in] replyLength - The maximal data length (in bytes) of any reply that the specified message handler may generate; the IPC service provides the message handler with buffer for reply according to the length specified here (refer also to the description of #t_IpcMsgHandler callback function type); This size shall be zero if the message handler never generates replies. @Return E_OK on success; Error code otherwise. *//***************************************************************************/ t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH], t_IpcMsgHandler *f_MsgHandler, t_Handle h_Module, uint32_t replyLength); /**************************************************************************//** @Function XX_IpcUnregisterMsgHandler @Description Release IPC mailbox routine. This function is used for unregistering an IPC message handler from the IPC service. This function is called by each destination endpoint to indicate that it is no longer capable of handling incoming messages. @Param[in] addr - The address name string associated with the destination endpoint; This address is the same as was used when the message handler was registered via XX_IpcRegisterMsgHandler(). @Return E_OK on success; Error code otherwise. *//***************************************************************************/ t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]); /**************************************************************************//** @Function XX_IpcInitSession @Description This function is used for creating an IPC session between the source endpoint and the destination endpoint. The actual implementation and representation of a session is left for the IPC service. The function returns an abstract handle to the created session. This handle shall be used by the source endpoint in subsequent calls to XX_IpcSendMessage(). The IPC service assumes that before this function is called, no messages are sent from the specified source endpoint to the specified destination endpoint. The IPC service may use a connection-oriented approach or a connectionless approach (or both) as described below. @par Connection-Oriented Approach The IPC service may implement a session in a connection-oriented approach - when this function is called, the IPC service should take the necessary steps to bring up a source-to-destination channel for messages and a destination-to-source channel for replies. The returned handle should represent the internal representation of these channels. @par Connectionless Approach The IPC service may implement a session in a connectionless approach - when this function is called, the IPC service should not perform any particular steps, but it must store the pair of source and destination addresses in some session representation and return it as a handle. When XX_IpcSendMessage() shall be called, the IPC service may use this handle to provide the necessary identifiers for routing the messages through the connectionless medium. @Param[in] destAddr - The address name string associated with the destination endpoint. @Param[in] srcAddr - The address name string associated with the source endpoint. @Return Abstract handle to the initialized session, or NULL on error. *//***************************************************************************/ t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH], char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]); /**************************************************************************//** @Function XX_IpcFreeSession @Description This function is used for terminating an existing IPC session between a source endpoint and a destination endpoint. The IPC service assumes that after this function is called, no messages shall be sent from the associated source endpoint to the associated destination endpoint. @Param[in] h_Session - Abstract handle to the IPC session - the same handle as was originally returned by the XX_IpcInitSession() function. @Return E_OK on success; Error code otherwise. *//***************************************************************************/ t_Error XX_IpcFreeSession(t_Handle h_Session); /**************************************************************************//** @Function XX_IpcSendMessage @Description IPC message send routine. This function may be used by a source endpoint to send an IPC message to a destination endpoint. The source endpoint cannot send a message to the destination endpoint without first initiating a session with that destination endpoint via XX_IpcInitSession() routine. The source endpoint must provide the buffer pointer and length of the outgoing message. Optionally, it may also provide a buffer for an expected reply. In the latter case, the transaction is not considered complete by the IPC service until the reply has been received. If the source endpoint does not provide a reply buffer, the transaction is considered complete after the message has been sent. The source endpoint must keep the message (and optional reply) buffers valid until the transaction is complete. @par Non-blocking mode The source endpoint may request a non-blocking send by providing a non-NULL pointer to a message completion callback function (f_Completion). Upon completion of the IPC transaction (consisting of a message and an optional reply), the IPC service invokes this callback routine to return the message buffer to the sender and to provide the received reply, if requested. @par Blocking mode The source endpoint may request a blocking send by setting f_Completion to NULL. The function is expected to block until the IPC transaction is complete - either the reply has been received or (if no reply was requested) the message has been sent. @Param[in] h_Session - Abstract handle to the IPC session - the same handle as was originally returned by the XX_IpcInitSession() function. @Param[in] p_Msg - Pointer to message buffer to send. @Param[in] msgLength - Length (in bytes) of actual data in the message buffer. @Param[in] p_Reply - Pointer to reply buffer - if this buffer is not NULL, the IPC service fills this buffer with the received reply data; In blocking mode, the reply data must be valid when the function returns; In non-blocking mode, the reply data is valid when f_Completion is called; If this pointer is NULL, no reply is expected. @Param[in,out] p_ReplyLength - Pointer to reply length, which has a dual role in this function: [In] specifies the maximal length (in bytes) of the reply buffer pointed by p_Reply, and [Out] in non-blocking mode this value is updated by the IPC service to the actual reply length (in bytes). @Param[in] f_Completion - Pointer to a completion callback to be used in non-blocking send mode; The completion callback is invoked by the IPC service upon completion of the IPC transaction (consisting of a message and an optional reply); If this pointer is NULL, the function is expected to block until the IPC transaction is complete. @Param[in] h_Arg - Abstract handle to the sending module; passed unchanged to the f_Completion callback function as the first argument. @Return E_OK on success; Error code otherwise. *//***************************************************************************/ t_Error XX_IpcSendMessage(t_Handle h_Session, uint8_t *p_Msg, uint32_t msgLength, uint8_t *p_Reply, uint32_t *p_ReplyLength, t_IpcMsgCompletion *f_Completion, t_Handle h_Arg); /** @} */ /* end of xx_ipc group */ /** @} */ /* end of xx_id group */ void XX_PortalSetInfo(device_t dev); -void XX_FmanFixIntr(int irq); #endif /* __XX_EXT_H */ Index: head/sys/contrib/ncsw/user/env/xx.c =================================================================== --- head/sys/contrib/ncsw/user/env/xx.c (revision 358321) +++ head/sys/contrib/ncsw/user/env/xx.c (revision 358322) @@ -1,798 +1,766 @@ /*- * Copyright (c) 2011 Semihalf. * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "error_ext.h" #include "std_ext.h" #include "list_ext.h" #include "mm_ext.h" /* Configuration */ /* Define the number of dTSEC ports active in system */ #define MALLOCSMART_DTSEC_IN_USE 4 /* * Calculate malloc's pool size for dTSEC's buffers. * We reserve 1MB pool for each dTSEC port. */ #define MALLOCSMART_POOL_SIZE \ (MALLOCSMART_DTSEC_IN_USE * 1024 * 1024) #define MALLOCSMART_SLICE_SIZE (PAGE_SIZE / 2) /* 2kB */ /* Defines */ #define MALLOCSMART_SIZE_TO_SLICE(x) \ (((x) + MALLOCSMART_SLICE_SIZE - 1) / MALLOCSMART_SLICE_SIZE) #define MALLOCSMART_SLICES \ MALLOCSMART_SIZE_TO_SLICE(MALLOCSMART_POOL_SIZE) /* Malloc Pool for NetCommSW */ MALLOC_DEFINE(M_NETCOMMSW, "NetCommSW", "NetCommSW software stack"); MALLOC_DEFINE(M_NETCOMMSW_MT, "NetCommSWTrack", "NetCommSW software allocation tracker"); /* MallocSmart data structures */ static void *XX_MallocSmartPool; static int XX_MallocSmartMap[MALLOCSMART_SLICES]; static struct mtx XX_MallocSmartLock; static struct mtx XX_MallocTrackLock; MTX_SYSINIT(XX_MallocSmartLockInit, &XX_MallocSmartLock, "NetCommSW MallocSmart Lock", MTX_DEF); MTX_SYSINIT(XX_MallocTrackLockInit, &XX_MallocTrackLock, "NetCommSW MallocTrack Lock", MTX_DEF); /* Interrupt info */ #define XX_INTR_FLAG_PREALLOCATED (1 << 0) -#define XX_INTR_FLAG_FMAN_FIX (1 << 1) struct XX_IntrInfo { driver_intr_t *handler; void *arg; int cpu; int flags; void *cookie; }; static struct XX_IntrInfo XX_IntrInfo[INTR_VECTORS]; /* Portal type identifiers */ enum XX_PortalIdent{ BM_PORTAL = 0, QM_PORTAL, }; /* Structure to store portals' properties */ struct XX_PortalInfo { vm_paddr_t portal_ce_pa[2][MAXCPU]; vm_paddr_t portal_ci_pa[2][MAXCPU]; uint32_t portal_ce_size[2][MAXCPU]; uint32_t portal_ci_size[2][MAXCPU]; vm_offset_t portal_ce_va[2]; vm_offset_t portal_ci_va[2]; uintptr_t portal_intr[2][MAXCPU]; }; static struct XX_PortalInfo XX_PInfo; void XX_Exit(int status) { panic("NetCommSW: Exit called with status %i", status); } void XX_Print(char *str, ...) { va_list ap; va_start(ap, str); vprintf(str, ap); va_end(ap); } void * XX_Malloc(uint32_t size) { void *p = (malloc(size, M_NETCOMMSW, M_NOWAIT)); return (p); } static int XX_MallocSmartMapCheck(unsigned int start, unsigned int slices) { unsigned int i; mtx_assert(&XX_MallocSmartLock, MA_OWNED); for (i = start; i < start + slices; i++) if (XX_MallocSmartMap[i]) return (FALSE); return (TRUE); } static void XX_MallocSmartMapSet(unsigned int start, unsigned int slices) { unsigned int i; mtx_assert(&XX_MallocSmartLock, MA_OWNED); for (i = start; i < start + slices; i++) XX_MallocSmartMap[i] = ((i == start) ? slices : -1); } static void XX_MallocSmartMapClear(unsigned int start, unsigned int slices) { unsigned int i; mtx_assert(&XX_MallocSmartLock, MA_OWNED); for (i = start; i < start + slices; i++) XX_MallocSmartMap[i] = 0; } int XX_MallocSmartInit(void) { int error; error = E_OK; mtx_lock(&XX_MallocSmartLock); if (XX_MallocSmartPool) goto out; /* Allocate MallocSmart pool */ XX_MallocSmartPool = contigmalloc(MALLOCSMART_POOL_SIZE, M_NETCOMMSW, M_NOWAIT, 0, 0xFFFFFFFFFull, MALLOCSMART_POOL_SIZE, 0); if (!XX_MallocSmartPool) { error = E_NO_MEMORY; goto out; } out: mtx_unlock(&XX_MallocSmartLock); return (error); } void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment) { unsigned int i; vm_offset_t addr; addr = 0; /* Convert alignment and size to number of slices */ alignment = MALLOCSMART_SIZE_TO_SLICE(alignment); size = MALLOCSMART_SIZE_TO_SLICE(size); /* Lock resources */ mtx_lock(&XX_MallocSmartLock); /* Allocate region */ for (i = 0; i + size <= MALLOCSMART_SLICES; i += alignment) { if (XX_MallocSmartMapCheck(i, size)) { XX_MallocSmartMapSet(i, size); addr = (vm_offset_t)XX_MallocSmartPool + (i * MALLOCSMART_SLICE_SIZE); break; } } /* Unlock resources */ mtx_unlock(&XX_MallocSmartLock); return ((void *)addr); } void XX_FreeSmart(void *p) { unsigned int start, slices; /* Calculate first slice of region */ start = MALLOCSMART_SIZE_TO_SLICE((vm_offset_t)(p) - (vm_offset_t)XX_MallocSmartPool); /* Lock resources */ mtx_lock(&XX_MallocSmartLock); KASSERT(XX_MallocSmartMap[start] > 0, ("XX_FreeSmart: Double or mid-block free!\n")); /* Free region */ slices = XX_MallocSmartMap[start]; XX_MallocSmartMapClear(start, slices); /* Unlock resources */ mtx_unlock(&XX_MallocSmartLock); } void XX_Free(void *p) { free(p, M_NETCOMMSW); } uint32_t XX_DisableAllIntr(void) { return (intr_disable()); } void XX_RestoreAllIntr(uint32_t flags) { intr_restore(flags); } static bool XX_IsPortalIntr(uintptr_t irq) { int cpu, type; /* Check interrupt numbers of all available portals */ for (type = 0; type < 2; type++) for (cpu = 0; cpu < MAXCPU; cpu++) if (irq == XX_PInfo.portal_intr[type][cpu]) return (1); return (0); } -void -XX_FmanFixIntr(int irq) -{ - - XX_IntrInfo[irq].flags |= XX_INTR_FLAG_FMAN_FIX; -} - -static bool -XX_FmanNeedsIntrFix(int irq) -{ - - if (XX_IntrInfo[irq].flags & XX_INTR_FLAG_FMAN_FIX) - return (1); - - return (0); -} - static void XX_Dispatch(void *arg) { struct XX_IntrInfo *info; info = arg; if (info->handler == NULL) { printf("%s(): IRQ handler is NULL!\n", __func__); return; } info->handler(info->arg); } t_Error XX_PreallocAndBindIntr(device_t dev, uintptr_t irq, unsigned int cpu) { struct resource *r; unsigned int inum; t_Error error; r = (struct resource *)irq; inum = rman_get_start(r); error = XX_SetIntr(irq, XX_Dispatch, &XX_IntrInfo[inum]); if (error != 0) return (error); error = bus_bind_intr(dev, r, cpu); if (error != 0) return (error); XX_IntrInfo[inum].flags = XX_INTR_FLAG_PREALLOCATED; XX_IntrInfo[inum].cpu = cpu; return (E_OK); } t_Error XX_DeallocIntr(uintptr_t irq) { struct resource *r; unsigned int inum; r = (struct resource *)irq; inum = rman_get_start(r); if ((XX_IntrInfo[inum].flags & XX_INTR_FLAG_PREALLOCATED) == 0) return (E_INVALID_STATE); XX_IntrInfo[inum].flags = 0; return (XX_FreeIntr(irq)); } t_Error XX_SetIntr(uintptr_t irq, t_Isr *f_Isr, t_Handle handle) { device_t dev; struct resource *r; unsigned int flags; int err; r = (struct resource *)irq; dev = rman_get_device(r); irq = rman_get_start(r); /* Handle preallocated interrupts */ if (XX_IntrInfo[irq].flags & XX_INTR_FLAG_PREALLOCATED) { if (XX_IntrInfo[irq].handler != NULL) return (E_BUSY); XX_IntrInfo[irq].handler = f_Isr; XX_IntrInfo[irq].arg = handle; return (E_OK); } flags = INTR_TYPE_NET | INTR_MPSAFE; /* BMAN/QMAN Portal interrupts must be exlusive */ if (XX_IsPortalIntr(irq)) flags |= INTR_EXCL; err = bus_setup_intr(dev, r, flags, NULL, f_Isr, handle, &XX_IntrInfo[irq].cookie); - if (err) - goto finish; - /* - * XXX: Bind FMan IRQ to CPU0. Current interrupt subsystem directs each - * interrupt to all CPUs. Race between an interrupt assertion and - * masking may occur and interrupt handler may be called multiple times - * per one interrupt. FMan doesn't support such a situation. Workaround - * is to bind FMan interrupt to one CPU0 only. - */ -#ifdef SMP - if (XX_FmanNeedsIntrFix(irq)) - err = powerpc_bind_intr(irq, 0); -#endif -finish: return (err); } t_Error XX_FreeIntr(uintptr_t irq) { device_t dev; struct resource *r; r = (struct resource *)irq; dev = rman_get_device(r); irq = rman_get_start(r); /* Handle preallocated interrupts */ if (XX_IntrInfo[irq].flags & XX_INTR_FLAG_PREALLOCATED) { if (XX_IntrInfo[irq].handler == NULL) return (E_INVALID_STATE); XX_IntrInfo[irq].handler = NULL; XX_IntrInfo[irq].arg = NULL; return (E_OK); } return (bus_teardown_intr(dev, r, XX_IntrInfo[irq].cookie)); } t_Error XX_EnableIntr(uintptr_t irq) { struct resource *r; r = (struct resource *)irq; irq = rman_get_start(r); powerpc_intr_unmask(irq); return (E_OK); } t_Error XX_DisableIntr(uintptr_t irq) { struct resource *r; r = (struct resource *)irq; irq = rman_get_start(r); powerpc_intr_mask(irq); return (E_OK); } t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data) { /* Not referenced */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); return (NULL); } void XX_FreeTasklet (t_TaskletHandle h_Tasklet) { /* Not referenced */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); } int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate) { /* Not referenced */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); return (0); } void XX_FlushScheduledTasks(void) { /* Not referenced */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); } int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet) { /* Not referenced */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); return (0); } void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data) { /* Not referenced */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); } t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet) { /* Not referenced */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); return (NULL); } t_Handle XX_InitSpinlock(void) { struct mtx *m; m = malloc(sizeof(*m), M_NETCOMMSW, M_NOWAIT | M_ZERO); if (!m) return (0); mtx_init(m, "NetCommSW Lock", NULL, MTX_DEF | MTX_DUPOK); return (m); } void XX_FreeSpinlock(t_Handle h_Spinlock) { struct mtx *m; m = h_Spinlock; mtx_destroy(m); free(m, M_NETCOMMSW); } void XX_LockSpinlock(t_Handle h_Spinlock) { struct mtx *m; m = h_Spinlock; mtx_lock(m); } void XX_UnlockSpinlock(t_Handle h_Spinlock) { struct mtx *m; m = h_Spinlock; mtx_unlock(m); } uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock) { XX_LockSpinlock(h_Spinlock); return (0); } void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags) { XX_UnlockSpinlock(h_Spinlock); } uint32_t XX_Sleep(uint32_t msecs) { XX_UDelay(1000 * msecs); return (0); } void XX_UDelay(uint32_t usecs) { DELAY(usecs); } t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH], t_IpcMsgHandler *f_MsgHandler, t_Handle h_Module, uint32_t replyLength) { /* * This function returns fake E_OK status and does nothing * as NetCommSW IPC is not used by FreeBSD drivers. */ return (E_OK); } t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]) { /* * This function returns fake E_OK status and does nothing * as NetCommSW IPC is not used by FreeBSD drivers. */ return (E_OK); } t_Error XX_IpcSendMessage(t_Handle h_Session, uint8_t *p_Msg, uint32_t msgLength, uint8_t *p_Reply, uint32_t *p_ReplyLength, t_IpcMsgCompletion *f_Completion, t_Handle h_Arg) { /* Should not be called */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); return (E_OK); } t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH], char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]) { /* Should not be called */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); return (NULL); } t_Error XX_IpcFreeSession(t_Handle h_Session) { /* Should not be called */ printf("NetCommSW: Unimplemented function %s() called!\n", __func__); return (E_OK); } physAddress_t XX_VirtToPhys(void *addr) { vm_paddr_t paddr; int cpu; cpu = PCPU_GET(cpuid); /* Handle NULL address */ if (addr == NULL) return (-1); /* Check CCSR */ if ((vm_offset_t)addr >= ccsrbar_va && (vm_offset_t)addr < ccsrbar_va + ccsrbar_size) return (((vm_offset_t)addr - ccsrbar_va) + ccsrbar_pa); /* Handle BMAN mappings */ if (((vm_offset_t)addr >= XX_PInfo.portal_ce_va[BM_PORTAL]) && ((vm_offset_t)addr < XX_PInfo.portal_ce_va[BM_PORTAL] + XX_PInfo.portal_ce_size[BM_PORTAL][cpu])) return (XX_PInfo.portal_ce_pa[BM_PORTAL][cpu] + (vm_offset_t)addr - XX_PInfo.portal_ce_va[BM_PORTAL]); if (((vm_offset_t)addr >= XX_PInfo.portal_ci_va[BM_PORTAL]) && ((vm_offset_t)addr < XX_PInfo.portal_ci_va[BM_PORTAL] + XX_PInfo.portal_ci_size[BM_PORTAL][cpu])) return (XX_PInfo.portal_ci_pa[BM_PORTAL][cpu] + (vm_offset_t)addr - XX_PInfo.portal_ci_va[BM_PORTAL]); /* Handle QMAN mappings */ if (((vm_offset_t)addr >= XX_PInfo.portal_ce_va[QM_PORTAL]) && ((vm_offset_t)addr < XX_PInfo.portal_ce_va[QM_PORTAL] + XX_PInfo.portal_ce_size[QM_PORTAL][cpu])) return (XX_PInfo.portal_ce_pa[QM_PORTAL][cpu] + (vm_offset_t)addr - XX_PInfo.portal_ce_va[QM_PORTAL]); if (((vm_offset_t)addr >= XX_PInfo.portal_ci_va[QM_PORTAL]) && ((vm_offset_t)addr < XX_PInfo.portal_ci_va[QM_PORTAL] + XX_PInfo.portal_ci_size[QM_PORTAL][cpu])) return (XX_PInfo.portal_ci_pa[QM_PORTAL][cpu] + (vm_offset_t)addr - XX_PInfo.portal_ci_va[QM_PORTAL]); if (PMAP_HAS_DMAP && (vm_offset_t)addr >= DMAP_BASE_ADDRESS && (vm_offset_t)addr <= DMAP_MAX_ADDRESS) return (DMAP_TO_PHYS((vm_offset_t)addr)); else paddr = pmap_kextract((vm_offset_t)addr); if (paddr == 0) printf("NetCommSW: " "Unable to translate virtual address %p!\n", addr); else pmap_track_page(kernel_pmap, (vm_offset_t)addr); return (paddr); } void * XX_PhysToVirt(physAddress_t addr) { struct pv_entry *pv; vm_page_t page; int cpu; /* Check CCSR */ if (addr >= ccsrbar_pa && addr < ccsrbar_pa + ccsrbar_size) return ((void *)((vm_offset_t)(addr - ccsrbar_pa) + ccsrbar_va)); cpu = PCPU_GET(cpuid); /* Handle BMAN mappings */ if ((addr >= XX_PInfo.portal_ce_pa[BM_PORTAL][cpu]) && (addr < XX_PInfo.portal_ce_pa[BM_PORTAL][cpu] + XX_PInfo.portal_ce_size[BM_PORTAL][cpu])) return ((void *)(XX_PInfo.portal_ci_va[BM_PORTAL] + (vm_offset_t)(addr - XX_PInfo.portal_ci_pa[BM_PORTAL][cpu]))); if ((addr >= XX_PInfo.portal_ci_pa[BM_PORTAL][cpu]) && (addr < XX_PInfo.portal_ci_pa[BM_PORTAL][cpu] + XX_PInfo.portal_ci_size[BM_PORTAL][cpu])) return ((void *)(XX_PInfo.portal_ci_va[BM_PORTAL] + (vm_offset_t)(addr - XX_PInfo.portal_ci_pa[BM_PORTAL][cpu]))); /* Handle QMAN mappings */ if ((addr >= XX_PInfo.portal_ce_pa[QM_PORTAL][cpu]) && (addr < XX_PInfo.portal_ce_pa[QM_PORTAL][cpu] + XX_PInfo.portal_ce_size[QM_PORTAL][cpu])) return ((void *)(XX_PInfo.portal_ce_va[QM_PORTAL] + (vm_offset_t)(addr - XX_PInfo.portal_ce_pa[QM_PORTAL][cpu]))); if ((addr >= XX_PInfo.portal_ci_pa[QM_PORTAL][cpu]) && (addr < XX_PInfo.portal_ci_pa[QM_PORTAL][cpu] + XX_PInfo.portal_ci_size[QM_PORTAL][cpu])) return ((void *)(XX_PInfo.portal_ci_va[QM_PORTAL] + (vm_offset_t)(addr - XX_PInfo.portal_ci_pa[QM_PORTAL][cpu]))); page = PHYS_TO_VM_PAGE(addr); pv = TAILQ_FIRST(&page->md.pv_list); if (pv != NULL) return ((void *)(pv->pv_va + ((vm_offset_t)addr & PAGE_MASK))); if (PMAP_HAS_DMAP) return ((void *)(uintptr_t)PHYS_TO_DMAP(addr)); printf("NetCommSW: " "Unable to translate physical address 0x%09jx!\n", (uintmax_t)addr); return (NULL); } void XX_PortalSetInfo(device_t dev) { char *dev_name; struct dpaa_portals_softc *sc; int i, type, len; dev_name = malloc(sizeof(*dev_name), M_TEMP, M_WAITOK | M_ZERO); len = strlen("bman-portals"); strncpy(dev_name, device_get_name(dev), len); if (strncmp(dev_name, "bman-portals", len) && strncmp(dev_name, "qman-portals", len)) goto end; if (strncmp(dev_name, "bman-portals", len) == 0) type = BM_PORTAL; else type = QM_PORTAL; sc = device_get_softc(dev); for (i = 0; sc->sc_dp[i].dp_ce_pa != 0; i++) { XX_PInfo.portal_ce_pa[type][i] = sc->sc_dp[i].dp_ce_pa; XX_PInfo.portal_ci_pa[type][i] = sc->sc_dp[i].dp_ci_pa; XX_PInfo.portal_ce_size[type][i] = sc->sc_dp[i].dp_ce_size; XX_PInfo.portal_ci_size[type][i] = sc->sc_dp[i].dp_ci_size; XX_PInfo.portal_intr[type][i] = sc->sc_dp[i].dp_intr_num; } XX_PInfo.portal_ce_va[type] = rman_get_bushandle(sc->sc_rres[0]); XX_PInfo.portal_ci_va[type] = rman_get_bushandle(sc->sc_rres[1]); end: free(dev_name, M_TEMP); } Index: head/sys/dev/dpaa/fman.c =================================================================== --- head/sys/dev/dpaa/fman.c (revision 358321) +++ head/sys/dev/dpaa/fman.c (revision 358322) @@ -1,566 +1,559 @@ /*- * Copyright (c) 2011-2012 Semihalf. * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "opt_platform.h" #include #include #include #include #include "fman.h" static MALLOC_DEFINE(M_FMAN, "fman", "fman devices information"); /** * @group FMan private defines. * @{ */ enum fman_irq_enum { FMAN_IRQ_NUM = 0, FMAN_ERR_IRQ_NUM = 1 }; enum fman_mu_ram_map { FMAN_MURAM_OFF = 0x0, FMAN_MURAM_SIZE = 0x28000 }; struct fman_config { device_t fman_device; uintptr_t mem_base_addr; uintptr_t irq_num; uintptr_t err_irq_num; uint8_t fm_id; t_FmExceptionsCallback *exception_callback; t_FmBusErrorCallback *bus_error_callback; }; /** * @group FMan private methods/members. * @{ */ /** * Frame Manager firmware. * We use the same firmware for both P3041 and P2041 devices. */ const uint32_t fman_firmware[] = FMAN_UC_IMG; const uint32_t fman_firmware_size = sizeof(fman_firmware); int fman_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { struct fman_softc *sc; bus_space_tag_t bt; bus_space_handle_t bh; int i, rv; sc = device_get_softc(bus); if (type != SYS_RES_IRQ) { for (i = 0; i < sc->sc_base.nranges; i++) { if (rman_is_region_manager(res, &sc->rman) != 0) { bt = rman_get_bustag(sc->mem_res); rv = bus_space_subregion(bt, rman_get_bushandle(sc->mem_res), rman_get_start(res) - rman_get_start(sc->mem_res), rman_get_size(res), &bh); if (rv != 0) return (rv); rman_set_bustag(res, bt); rman_set_bushandle(res, bh); return (rman_activate_resource(res)); } } return (EINVAL); } return (bus_generic_activate_resource(bus, child, type, rid, res)); } int fman_release_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { struct fman_softc *sc; struct resource_list *rl; struct resource_list_entry *rle; int passthrough, rv; passthrough = (device_get_parent(child) != bus); rl = BUS_GET_RESOURCE_LIST(bus, child); sc = device_get_softc(bus); if (type != SYS_RES_IRQ) { if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){ rv = bus_deactivate_resource(child, type, rid, res); if (rv != 0) return (rv); } rv = rman_release_resource(res); if (rv != 0) return (rv); if (!passthrough) { rle = resource_list_find(rl, type, rid); KASSERT(rle != NULL, ("%s: resource entry not found!", __func__)); KASSERT(rle->res != NULL, ("%s: resource entry is not busy", __func__)); rle->res = NULL; } return (0); } return (resource_list_release(rl, bus, child, type, rid, res)); } struct resource * fman_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct fman_softc *sc; struct resource_list *rl; struct resource_list_entry *rle = NULL; struct resource *res; int i, isdefault, passthrough; isdefault = RMAN_IS_DEFAULT_RANGE(start, end); passthrough = (device_get_parent(child) != bus); sc = device_get_softc(bus); rl = BUS_GET_RESOURCE_LIST(bus, child); switch (type) { case SYS_RES_MEMORY: KASSERT(!(isdefault && passthrough), ("%s: passthrough of default allocation", __func__)); if (!passthrough) { rle = resource_list_find(rl, type, *rid); if (rle == NULL) return (NULL); KASSERT(rle->res == NULL, ("%s: resource entry is busy", __func__)); if (isdefault) { start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } } res = NULL; /* Map fman ranges to nexus ranges. */ for (i = 0; i < sc->sc_base.nranges; i++) { if (start >= sc->sc_base.ranges[i].bus && end < sc->sc_base.ranges[i].bus + sc->sc_base.ranges[i].size) { start += rman_get_start(sc->mem_res); end += rman_get_start(sc->mem_res); res = rman_reserve_resource(&sc->rman, start, end, count, flags & ~RF_ACTIVE, child); if (res == NULL) return (NULL); rman_set_rid(res, *rid); if ((flags & RF_ACTIVE) != 0 && bus_activate_resource( child, type, *rid, res) != 0) { rman_release_resource(res); return (NULL); } break; } } if (!passthrough) rle->res = res; return (res); case SYS_RES_IRQ: return (resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags)); } return (NULL); } static int fman_fill_ranges(phandle_t node, struct simplebus_softc *sc) { int host_address_cells; cell_t *base_ranges; ssize_t nbase_ranges; int err; int i, j, k; err = OF_searchencprop(OF_parent(node), "#address-cells", &host_address_cells, sizeof(host_address_cells)); if (err <= 0) return (-1); nbase_ranges = OF_getproplen(node, "ranges"); if (nbase_ranges < 0) return (-1); sc->nranges = nbase_ranges / sizeof(cell_t) / (sc->acells + host_address_cells + sc->scells); if (sc->nranges == 0) return (0); sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), M_DEVBUF, M_WAITOK); base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); OF_getencprop(node, "ranges", base_ranges, nbase_ranges); for (i = 0, j = 0; i < sc->nranges; i++) { sc->ranges[i].bus = 0; for (k = 0; k < sc->acells; k++) { sc->ranges[i].bus <<= 32; sc->ranges[i].bus |= base_ranges[j++]; } sc->ranges[i].host = 0; for (k = 0; k < host_address_cells; k++) { sc->ranges[i].host <<= 32; sc->ranges[i].host |= base_ranges[j++]; } sc->ranges[i].size = 0; for (k = 0; k < sc->scells; k++) { sc->ranges[i].size <<= 32; sc->ranges[i].size |= base_ranges[j++]; } } free(base_ranges, M_DEVBUF); return (sc->nranges); } static t_Handle fman_init(struct fman_softc *sc, struct fman_config *cfg) { phandle_t node; t_FmParams fm_params; t_Handle muram_handle, fm_handle; t_Error error; t_FmRevisionInfo revision_info; uint16_t clock; uint32_t tmp, mod; /* MURAM configuration */ muram_handle = FM_MURAM_ConfigAndInit(cfg->mem_base_addr + FMAN_MURAM_OFF, FMAN_MURAM_SIZE); if (muram_handle == NULL) { device_printf(cfg->fman_device, "couldn't init FM MURAM module" "\n"); return (NULL); } sc->muram_handle = muram_handle; /* Fill in FM configuration */ fm_params.fmId = cfg->fm_id; /* XXX we support only one partition thus each fman has master id */ fm_params.guestId = NCSW_MASTER_ID; fm_params.baseAddr = cfg->mem_base_addr; fm_params.h_FmMuram = muram_handle; /* Get FMan clock in Hz */ if ((tmp = fman_get_clock(sc)) == 0) return (NULL); /* Convert FMan clock to MHz */ clock = (uint16_t)(tmp / 1000000); mod = tmp % 1000000; if (mod >= 500000) ++clock; fm_params.fmClkFreq = clock; fm_params.f_Exception = cfg->exception_callback; fm_params.f_BusError = cfg->bus_error_callback; fm_params.h_App = cfg->fman_device; fm_params.irq = cfg->irq_num; fm_params.errIrq = cfg->err_irq_num; fm_params.firmware.size = fman_firmware_size; fm_params.firmware.p_Code = (uint32_t*)fman_firmware; fm_handle = FM_Config(&fm_params); if (fm_handle == NULL) { device_printf(cfg->fman_device, "couldn't configure FM " "module\n"); goto err; } FM_ConfigResetOnInit(fm_handle, TRUE); error = FM_Init(fm_handle); if (error != E_OK) { device_printf(cfg->fman_device, "couldn't init FM module\n"); goto err2; } error = FM_GetRevision(fm_handle, &revision_info); if (error != E_OK) { device_printf(cfg->fman_device, "couldn't get FM revision\n"); goto err2; } device_printf(cfg->fman_device, "Hardware version: %d.%d.\n", revision_info.majorRev, revision_info.minorRev); /* Initialize the simplebus part of things */ simplebus_init(sc->sc_base.dev, 0); node = ofw_bus_get_node(sc->sc_base.dev); fman_fill_ranges(node, &sc->sc_base); sc->rman.rm_type = RMAN_ARRAY; sc->rman.rm_descr = "FMan range"; rman_init_from_resource(&sc->rman, sc->mem_res); for (node = OF_child(node); node > 0; node = OF_peer(node)) { simplebus_add_device(sc->sc_base.dev, node, 0, NULL, -1, NULL); } return (fm_handle); err2: FM_Free(fm_handle); err: FM_MURAM_Free(muram_handle); return (NULL); } static void fman_exception_callback(t_Handle app_handle, e_FmExceptions exception) { struct fman_softc *sc; sc = app_handle; device_printf(sc->sc_base.dev, "FMan exception occurred.\n"); } static void fman_error_callback(t_Handle app_handle, e_FmPortType port_type, uint8_t port_id, uint64_t addr, uint8_t tnum, uint16_t liodn) { struct fman_softc *sc; sc = app_handle; device_printf(sc->sc_base.dev, "FMan error occurred.\n"); } /** @} */ /** * @group FMan driver interface. * @{ */ int fman_get_handle(device_t dev, t_Handle *fmh) { struct fman_softc *sc = device_get_softc(dev); *fmh = sc->fm_handle; return (0); } int fman_get_muram_handle(device_t dev, t_Handle *muramh) { struct fman_softc *sc = device_get_softc(dev); *muramh = sc->muram_handle; return (0); } int fman_get_bushandle(device_t dev, vm_offset_t *fm_base) { struct fman_softc *sc = device_get_softc(dev); *fm_base = rman_get_bushandle(sc->mem_res); return (0); } int fman_attach(device_t dev) { struct fman_softc *sc; struct fman_config cfg; pcell_t qchan_range[2]; phandle_t node; sc = device_get_softc(dev); sc->sc_base.dev = dev; /* Check if MallocSmart allocator is ready */ if (XX_MallocSmartInit() != E_OK) { device_printf(dev, "could not initialize smart allocator.\n"); return (ENXIO); } node = ofw_bus_get_node(dev); if (OF_getencprop(node, "fsl,qman-channel-range", qchan_range, sizeof(qchan_range)) <= 0) { device_printf(dev, "Missing QMan channel range property!\n"); return (ENXIO); } sc->qman_chan_base = qchan_range[0]; sc->qman_chan_count = qchan_range[1]; sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE | RF_SHAREABLE); if (!sc->mem_res) { device_printf(dev, "could not allocate memory.\n"); return (ENXIO); } sc->irq_rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE); if (!sc->irq_res) { device_printf(dev, "could not allocate interrupt.\n"); goto err; } - /* - * XXX: Fix FMan interrupt. This is workaround for the issue with - * interrupts directed to multiple CPUs by the interrupts subsystem. - * Workaround is to bind the interrupt to only one CPU0. - */ - XX_FmanFixIntr(rman_get_start(sc->irq_res)); - sc->err_irq_rid = 1; sc->err_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->err_irq_rid, RF_ACTIVE | RF_SHAREABLE); if (!sc->err_irq_res) { device_printf(dev, "could not allocate error interrupt.\n"); goto err; } /* Set FMan configuration */ cfg.fman_device = dev; cfg.fm_id = device_get_unit(dev); cfg.mem_base_addr = rman_get_bushandle(sc->mem_res); cfg.irq_num = (uintptr_t)sc->irq_res; cfg.err_irq_num = (uintptr_t)sc->err_irq_res; cfg.exception_callback = fman_exception_callback; cfg.bus_error_callback = fman_error_callback; sc->fm_handle = fman_init(sc, &cfg); if (sc->fm_handle == NULL) { device_printf(dev, "could not be configured\n"); return (ENXIO); } return (bus_generic_attach(dev)); err: fman_detach(dev); return (ENXIO); } int fman_detach(device_t dev) { struct fman_softc *sc; sc = device_get_softc(dev); if (sc->muram_handle) { FM_MURAM_Free(sc->muram_handle); } if (sc->fm_handle) { FM_Free(sc->fm_handle); } if (sc->mem_res) { bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); } if (sc->irq_res) { bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); } if (sc->irq_res) { bus_release_resource(dev, SYS_RES_IRQ, sc->err_irq_rid, sc->err_irq_res); } return (0); } int fman_suspend(device_t dev) { return (0); } int fman_resume_dev(device_t dev) { return (0); } int fman_shutdown(device_t dev) { return (0); } int fman_qman_channel_id(device_t dev, int port) { struct fman_softc *sc; int qman_port_id[] = {0x31, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; int i; sc = device_get_softc(dev); for (i = 0; i < sc->qman_chan_count; i++) { if (qman_port_id[i] == port) return (sc->qman_chan_base + i); } return (0); } /** @} */