diff options
author | Mandy Lavi <mandy.lavi@freescale.com> | 2013-03-24 16:40:18 (GMT) |
---|---|---|
committer | Fleming Andrew-AFLEMING <AFLEMING@freescale.com> | 2013-04-08 23:07:26 (GMT) |
commit | 3cc514986cb4e457458cc826288b6c2107c97907 (patch) | |
tree | 2985e48afc5dd20f44d51ef6aafdae917ce2698f /drivers/net/ethernet/freescale/fman/etc | |
parent | 5767d52cec831b0e2927d34e91acd738cc1cb0ef (diff) | |
download | linux-fsl-qoriq-3cc514986cb4e457458cc826288b6c2107c97907.tar.xz |
fmd: fmd19 integration
Add fmd19 codebase, plus a minimal set of sources from dpaa-eth,
necessary for bare compilation
Change-Id: I390df8717671204e3d98a987135393bef4534e95
Signed-off-by: Mandy Lavi <mandy.lavi@freescale.com>
Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com>
Reviewed-on: http://git.am.freescale.net:8181/1029
Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Diffstat (limited to 'drivers/net/ethernet/freescale/fman/etc')
-rw-r--r-- | drivers/net/ethernet/freescale/fman/etc/Makefile | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fman/etc/error.c | 95 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fman/etc/list.c | 71 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fman/etc/memcpy.c | 601 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fman/etc/mm.c | 1142 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fman/etc/mm.h | 105 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fman/etc/sprint.c | 81 |
7 files changed, 2107 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/fman/etc/Makefile b/drivers/net/ethernet/freescale/fman/etc/Makefile new file mode 100644 index 0000000..5e7c382 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/etc/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the Freescale Ethernet controllers +# +EXTRA_CFLAGS += -DVERSION=\"\" +# +#Include netcomm SW specific definitions + +include $(srctree)/drivers/net/ethernet/freescale/fman/ncsw_config.mk + +obj-y += fsl-ncsw-etc.o + +fsl-ncsw-etc-objs := mm.o memcpy.o sprint.o list.o error.o diff --git a/drivers/net/ethernet/freescale/fman/etc/error.c b/drivers/net/ethernet/freescale/fman/etc/error.c new file mode 100644 index 0000000..fead7f50 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/etc/error.c @@ -0,0 +1,95 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * 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 error.c + + @Description General errors and events reporting utilities. +*//***************************************************************************/ +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +#include "error_ext.h" + + +const char *dbgLevelStrings[] = +{ + "CRITICAL" + ,"MAJOR" + ,"MINOR" + ,"WARNING" + ,"INFO" + ,"TRACE" +}; + + +char * ErrTypeStrings (e_ErrorType err) +{ + switch (err) + { + case (E_OK): return "OK"; + case (E_WRITE_FAILED): return "Write Access Failed"; + case (E_NO_DEVICE): return "No Device"; + case (E_NOT_AVAILABLE): return "Resource Is Unavailable"; + case (E_NO_MEMORY): return "Memory Allocation Failed"; + case (E_INVALID_ADDRESS): return "Invalid Address"; + case (E_BUSY): return "Resource Is Busy"; + case (E_ALREADY_EXISTS): return "Resource Already Exists"; + case (E_INVALID_OPERATION): return "Invalid Operation"; + case (E_INVALID_VALUE): return "Invalid Value"; + case (E_NOT_IN_RANGE): return "Value Out Of Range"; + case (E_NOT_SUPPORTED): return "Unsupported Operation"; + case (E_INVALID_STATE): return "Invalid State"; + case (E_INVALID_HANDLE): return "Invalid Handle"; + case (E_INVALID_ID): return "Invalid ID"; + case (E_NULL_POINTER): return "Unexpected NULL Pointer"; + case (E_INVALID_SELECTION): return "Invalid Selection"; + case (E_INVALID_COMM_MODE): return "Invalid Communication Mode"; + case (E_INVALID_MEMORY_TYPE): return "Invalid Memory Type"; + case (E_INVALID_CLOCK): return "Invalid Clock"; + case (E_CONFLICT): return "Conflict In Settings"; + case (E_NOT_ALIGNED): return "Incorrect Alignment"; + case (E_NOT_FOUND): return "Resource Not Found"; + case (E_FULL): return "Resource Is Full"; + case (E_EMPTY): return "Resource Is Empty"; + case (E_ALREADY_FREE): return "Resource Already Free"; + case (E_READ_FAILED): return "Read Access Failed"; + case (E_INVALID_FRAME): return "Invalid Frame"; + case (E_SEND_FAILED): return "Send Operation Failed"; + case (E_RECEIVE_FAILED): return "Receive Operation Failed"; + case (E_TIMEOUT): return "Operation Timed Out"; + default: + break; + } + return NULL; +} +#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */ diff --git a/drivers/net/ethernet/freescale/fman/etc/list.c b/drivers/net/ethernet/freescale/fman/etc/list.c new file mode 100644 index 0000000..2d044be --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/etc/list.c @@ -0,0 +1,71 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * 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 list.c + + @Description Implementation of list. +*//***************************************************************************/ +#include "std_ext.h" +#include "list_ext.h" + + +void LIST_Append(t_List *p_NewList, t_List *p_Head) +{ + t_List *p_First = LIST_FIRST(p_NewList); + + if (p_First != p_NewList) + { + t_List *p_Last = LIST_LAST(p_NewList); + t_List *p_Cur = LIST_NEXT(p_Head); + + LIST_PREV(p_First) = p_Head; + LIST_FIRST(p_Head) = p_First; + LIST_NEXT(p_Last) = p_Cur; + LIST_LAST(p_Cur) = p_Last; + } +} + + +int LIST_NumOfObjs(t_List *p_List) +{ + t_List *p_Tmp; + int numOfObjs = 0; + + if (!LIST_IsEmpty(p_List)) + LIST_FOR_EACH(p_Tmp, p_List) + numOfObjs++; + + return numOfObjs; +} diff --git a/drivers/net/ethernet/freescale/fman/etc/memcpy.c b/drivers/net/ethernet/freescale/fman/etc/memcpy.c new file mode 100644 index 0000000..02973e5 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/etc/memcpy.c @@ -0,0 +1,601 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * 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. + */ + + + +#include "std_ext.h" +#include "xx_ext.h" +#include "memcpy_ext.h" + + +void * MemCpy32(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint32_t lastWord; + uint32_t currWord; + uint32_t *p_Src32; + uint32_t *p_Dst32; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessary to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ + { + *p_Dst8++ = *p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + *p_Dst8++ = *p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ + rightAlign = 32 - leftAlign; + + + if (leftAlign == 0) + { + /* source is also aligned */ + p_Src32 = (uint32_t*)(p_Src8); + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + *p_Dst32++ = *p_Src32++; + size -= 4; + } + p_Src8 = (uint8_t*)(p_Src32); + p_Dst8 = (uint8_t*)(p_Dst32); + } + else + { + /* source is not aligned (destination is aligned)*/ + p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); + p_Dst32 = (uint32_t*)(p_Dst8); + lastWord = *p_Src32++; + while(size >> 3) /* size >= 8 */ + { + currWord = *p_Src32; + *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign); + lastWord = currWord; + p_Src32++; + p_Dst32++; + size -= 4; + } + p_Dst8 = (uint8_t*)(p_Dst32); + p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + *p_Dst8++ = *p_Src8++; + + return pDst; +} + +void * IO2IOCpy32(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint32_t lastWord; + uint32_t currWord; + uint32_t *p_Src32; + uint32_t *p_Dst32; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessary to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ + { + WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8)); + p_Dst8++;p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8)); + p_Dst8++;p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ + rightAlign = 32 - leftAlign; + + if (leftAlign == 0) + { + /* source is also aligned */ + p_Src32 = (uint32_t*)(p_Src8); + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + WRITE_UINT32(*p_Dst32, GET_UINT32(*p_Src32)); + p_Dst32++;p_Src32++; + size -= 4; + } + p_Src8 = (uint8_t*)(p_Src32); + p_Dst8 = (uint8_t*)(p_Dst32); + } + else + { + /* source is not aligned (destination is aligned)*/ + p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); + p_Dst32 = (uint32_t*)(p_Dst8); + lastWord = GET_UINT32(*p_Src32); + p_Src32++; + while(size >> 3) /* size >= 8 */ + { + currWord = GET_UINT32(*p_Src32); + WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign)); + lastWord = currWord; + p_Src32++;p_Dst32++; + size -= 4; + } + p_Dst8 = (uint8_t*)(p_Dst32); + p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + { + WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8)); + p_Dst8++;p_Src8++; + } + + return pDst; +} + +void * Mem2IOCpy32(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint32_t lastWord; + uint32_t currWord; + uint32_t *p_Src32; + uint32_t *p_Dst32; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessary to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ + { + WRITE_UINT8(*p_Dst8, *p_Src8); + p_Dst8++;p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + WRITE_UINT8(*p_Dst8, *p_Src8); + p_Dst8++;p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ + rightAlign = 32 - leftAlign; + + if (leftAlign == 0) + { + /* source is also aligned */ + p_Src32 = (uint32_t*)(p_Src8); + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + WRITE_UINT32(*p_Dst32, *p_Src32); + p_Dst32++;p_Src32++; + size -= 4; + } + p_Src8 = (uint8_t*)(p_Src32); + p_Dst8 = (uint8_t*)(p_Dst32); + } + else + { + /* source is not aligned (destination is aligned)*/ + p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); + p_Dst32 = (uint32_t*)(p_Dst8); + lastWord = *p_Src32++; + while(size >> 3) /* size >= 8 */ + { + currWord = *p_Src32; + WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign)); + lastWord = currWord; + p_Src32++;p_Dst32++; + size -= 4; + } + p_Dst8 = (uint8_t*)(p_Dst32); + p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + { + WRITE_UINT8(*p_Dst8, *p_Src8); + p_Dst8++;p_Src8++; + } + + return pDst; +} + +void * IO2MemCpy32(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint32_t lastWord; + uint32_t currWord; + uint32_t *p_Src32; + uint32_t *p_Dst32; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessary to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ + { + *p_Dst8 = GET_UINT8(*p_Src8); + p_Dst8++;p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + *p_Dst8 = GET_UINT8(*p_Src8); + p_Dst8++;p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ + rightAlign = 32 - leftAlign; + + if (leftAlign == 0) + { + /* source is also aligned */ + p_Src32 = (uint32_t*)(p_Src8); + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + *p_Dst32 = GET_UINT32(*p_Src32); + p_Dst32++;p_Src32++; + size -= 4; + } + p_Src8 = (uint8_t*)(p_Src32); + p_Dst8 = (uint8_t*)(p_Dst32); + } + else + { + /* source is not aligned (destination is aligned)*/ + p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); + p_Dst32 = (uint32_t*)(p_Dst8); + lastWord = GET_UINT32(*p_Src32); + p_Src32++; + while(size >> 3) /* size >= 8 */ + { + currWord = GET_UINT32(*p_Src32); + *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign); + lastWord = currWord; + p_Src32++;p_Dst32++; + size -= 4; + } + p_Dst8 = (uint8_t*)(p_Dst32); + p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + { + *p_Dst8 = GET_UINT8(*p_Src8); + p_Dst8++;p_Src8++; + } + + return pDst; +} + +void * MemCpy64(void* pDst,void* pSrc, uint32_t size) +{ + uint32_t leftAlign; + uint32_t rightAlign; + uint64_t lastWord; + uint64_t currWord; + uint64_t *pSrc64; + uint64_t *pDst64; + uint8_t *p_Src8; + uint8_t *p_Dst8; + + p_Src8 = (uint8_t*)(pSrc); + p_Dst8 = (uint8_t*)(pDst); + /* first copy byte by byte till the source first alignment + * this step is necessarily to ensure we do not even try to access + * data which is before the source buffer, hence it is not ours. + */ + while((PTR_TO_UINT(p_Src8) & 7) && size) /* (pSrc mod 8) > 0 and size > 0 */ + { + *p_Dst8++ = *p_Src8++; + size--; + } + + /* align destination (possibly disaligning source)*/ + while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */ + { + *p_Dst8++ = *p_Src8++; + size--; + } + + /* dest is aligned and source is not necessarily aligned */ + leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 7) << 3); /* leftAlign = (pSrc mod 8)*8 */ + rightAlign = 64 - leftAlign; + + + if (leftAlign == 0) + { + /* source is also aligned */ + pSrc64 = (uint64_t*)(p_Src8); + pDst64 = (uint64_t*)(p_Dst8); + while (size >> 3) /* size >= 8 */ + { + *pDst64++ = *pSrc64++; + size -= 8; + } + p_Src8 = (uint8_t*)(pSrc64); + p_Dst8 = (uint8_t*)(pDst64); + } + else + { + /* source is not aligned (destination is aligned)*/ + pSrc64 = (uint64_t*)(p_Src8 - (leftAlign >> 3)); + pDst64 = (uint64_t*)(p_Dst8); + lastWord = *pSrc64++; + while(size >> 4) /* size >= 16 */ + { + currWord = *pSrc64; + *pDst64 = (lastWord << leftAlign) | (currWord >> rightAlign); + lastWord = currWord; + pSrc64++; + pDst64++; + size -= 8; + } + p_Dst8 = (uint8_t*)(pDst64); + p_Src8 = (uint8_t*)(pSrc64) - 8 + (leftAlign >> 3); + } + + /* complete the left overs */ + while (size--) + *p_Dst8++ = *p_Src8++; + + return pDst; +} + +void * MemSet32(void* pDst, uint8_t val, uint32_t size) +{ + uint32_t val32; + uint32_t *p_Dst32; + uint8_t *p_Dst8; + + p_Dst8 = (uint8_t*)(pDst); + + /* generate four 8-bit val's in 32-bit container */ + val32 = (uint32_t) val; + val32 |= (val32 << 8); + val32 |= (val32 << 16); + + /* align destination to 32 */ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + *p_Dst8++ = val; + size--; + } + + /* 32-bit chunks */ + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + *p_Dst32++ = val32; + size -= 4; + } + + /* complete the leftovers */ + p_Dst8 = (uint8_t*)(p_Dst32); + while (size--) + *p_Dst8++ = val; + + return pDst; +} + +void * IOMemSet32(void* pDst, uint8_t val, uint32_t size) +{ + uint32_t val32; + uint32_t *p_Dst32; + uint8_t *p_Dst8; + + p_Dst8 = (uint8_t*)(pDst); + + /* generate four 8-bit val's in 32-bit container */ + val32 = (uint32_t) val; + val32 |= (val32 << 8); + val32 |= (val32 << 16); + + /* align destination to 32 */ + while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ + { + WRITE_UINT8(*p_Dst8, val); + p_Dst8++; + size--; + } + + /* 32-bit chunks */ + p_Dst32 = (uint32_t*)(p_Dst8); + while (size >> 2) /* size >= 4 */ + { + WRITE_UINT32(*p_Dst32, val32); + p_Dst32++; + size -= 4; + } + + /* complete the leftovers */ + p_Dst8 = (uint8_t*)(p_Dst32); + while (size--) + { + WRITE_UINT8(*p_Dst8, val); + p_Dst8++; + } + + return pDst; +} + +void * MemSet64(void* pDst, uint8_t val, uint32_t size) +{ + uint64_t val64; + uint64_t *pDst64; + uint8_t *p_Dst8; + + p_Dst8 = (uint8_t*)(pDst); + + /* generate four 8-bit val's in 32-bit container */ + val64 = (uint64_t) val; + val64 |= (val64 << 8); + val64 |= (val64 << 16); + val64 |= (val64 << 24); + val64 |= (val64 << 32); + + /* align destination to 64 */ + while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */ + { + *p_Dst8++ = val; + size--; + } + + /* 64-bit chunks */ + pDst64 = (uint64_t*)(p_Dst8); + while (size >> 4) /* size >= 8 */ + { + *pDst64++ = val64; + size -= 8; + } + + /* complete the leftovers */ + p_Dst8 = (uint8_t*)(pDst64); + while (size--) + *p_Dst8++ = val; + + return pDst; +} + +void MemDisp(uint8_t *p, int size) +{ + uint32_t space = (uint32_t)(PTR_TO_UINT(p) & 0x3); + uint8_t *p_Limit; + + if (space) + { + p_Limit = (p - space + 4); + + XX_Print("0x%08X: ", (p - space)); + + while (space--) + { + XX_Print("--"); + } + while (size && (p < p_Limit)) + { + XX_Print("%02x", *(uint8_t*)p); + size--; + p++; + } + + XX_Print(" "); + p_Limit += 12; + + while ((size > 3) && (p < p_Limit)) + { + XX_Print("%08x ", *(uint32_t*)p); + size -= 4; + p += 4; + } + XX_Print("\r\n"); + } + + while (size > 15) + { + XX_Print("0x%08X: %08x %08x %08x %08x\r\n", + p, *(uint32_t *)p, *(uint32_t *)(p + 4), + *(uint32_t *)(p + 8), *(uint32_t *)(p + 12)); + size -= 16; + p += 16; + } + + if (size) + { + XX_Print("0x%08X: ", p); + + while (size > 3) + { + XX_Print("%08x ", *(uint32_t *)p); + size -= 4; + p += 4; + } + while (size) + { + XX_Print("%02x", *(uint8_t *)p); + size--; + p++; + } + + XX_Print("\r\n"); + } +} diff --git a/drivers/net/ethernet/freescale/fman/etc/mm.c b/drivers/net/ethernet/freescale/fman/etc/mm.c new file mode 100644 index 0000000..7b9d201 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/etc/mm.c @@ -0,0 +1,1142 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * 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. + */ + + +#include "string_ext.h" +#include "error_ext.h" +#include "std_ext.h" +#include "part_ext.h" +#include "xx_ext.h" + +#include "mm.h" + + + + +/********************************************************************** + * MM internal routines set * + **********************************************************************/ + +/**************************************************************** + * Routine: CreateBusyBlock + * + * Description: + * Initializes a new busy block of "size" bytes and started + * rom "base" address. Each busy block has a name that + * specified the purpose of the memory allocation. + * + * Arguments: + * base - base address of the busy block + * size - size of the busy block + * name - name that specified the busy block + * + * Return value: + * A pointer to new created structure returned on success; + * Otherwise, NULL. + ****************************************************************/ +static t_BusyBlock * CreateBusyBlock(uint64_t base, uint64_t size, char *name) +{ + t_BusyBlock *p_BusyBlock; + uint32_t n; + + p_BusyBlock = (t_BusyBlock *)XX_Malloc(sizeof(t_BusyBlock)); + if ( !p_BusyBlock ) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + return NULL; + } + + p_BusyBlock->base = base; + p_BusyBlock->end = base + size; + + n = strlen(name); + if (n >= MM_MAX_NAME_LEN) + n = MM_MAX_NAME_LEN - 1; + strncpy(p_BusyBlock->name, name, MM_MAX_NAME_LEN-1); + p_BusyBlock->name[n] = '\0'; + p_BusyBlock->p_Next = 0; + + return p_BusyBlock; +} + +/**************************************************************** + * Routine: CreateNewBlock + * + * Description: + * Initializes a new memory block of "size" bytes and started + * from "base" address. + * + * Arguments: + * base - base address of the memory block + * size - size of the memory block + * + * Return value: + * A pointer to new created structure returned on success; + * Otherwise, NULL. + ****************************************************************/ +static t_MemBlock * CreateNewBlock(uint64_t base, uint64_t size) +{ + t_MemBlock *p_MemBlock; + + p_MemBlock = (t_MemBlock *)XX_Malloc(sizeof(t_MemBlock)); + if ( !p_MemBlock ) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + return NULL; + } + + p_MemBlock->base = base; + p_MemBlock->end = base+size; + p_MemBlock->p_Next = 0; + + return p_MemBlock; +} + +/**************************************************************** + * Routine: CreateFreeBlock + * + * Description: + * Initializes a new free block of of "size" bytes and + * started from "base" address. + * + * Arguments: + * base - base address of the free block + * size - size of the free block + * + * Return value: + * A pointer to new created structure returned on success; + * Otherwise, NULL. + ****************************************************************/ +static t_FreeBlock * CreateFreeBlock(uint64_t base, uint64_t size) +{ + t_FreeBlock *p_FreeBlock; + + p_FreeBlock = (t_FreeBlock *)XX_Malloc(sizeof(t_FreeBlock)); + if ( !p_FreeBlock ) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + return NULL; + } + + p_FreeBlock->base = base; + p_FreeBlock->end = base + size; + p_FreeBlock->p_Next = 0; + + return p_FreeBlock; +} + +/**************************************************************** + * Routine: AddFree + * + * Description: + * Adds a new free block to the free lists. It updates each + * free list to include a new free block. + * Note, that all free block in each free list are ordered + * by their base address. + * + * Arguments: + * p_MM - pointer to the MM object + * base - base address of a given free block + * end - end address of a given free block + * + * Return value: + * + * + ****************************************************************/ +static t_Error AddFree(t_MM *p_MM, uint64_t base, uint64_t end) +{ + t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB; + uint64_t alignment; + uint64_t alignBase; + int i; + + /* Updates free lists to include a just released block */ + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + p_PrevB = p_NewB = 0; + p_CurrB = p_MM->freeBlocks[i]; + + alignment = (uint64_t)(0x1 << i); + alignBase = MAKE_ALIGNED(base, alignment); + + /* Goes to the next free list if there is no block to free */ + if (alignBase >= end) + continue; + + /* Looks for a free block that should be updated */ + while ( p_CurrB ) + { + if ( alignBase <= p_CurrB->end ) + { + if ( end > p_CurrB->end ) + { + t_FreeBlock *p_NextB; + while ( p_CurrB->p_Next && end > p_CurrB->p_Next->end ) + { + p_NextB = p_CurrB->p_Next; + p_CurrB->p_Next = p_CurrB->p_Next->p_Next; + XX_Free(p_NextB); + } + + p_NextB = p_CurrB->p_Next; + if ( !p_NextB || (p_NextB && end < p_NextB->base) ) + { + p_CurrB->end = end; + } + else + { + p_CurrB->end = p_NextB->end; + p_CurrB->p_Next = p_NextB->p_Next; + XX_Free(p_NextB); + } + } + else if ( (end < p_CurrB->base) && ((end-alignBase) >= alignment) ) + { + if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + + p_NewB->p_Next = p_CurrB; + if (p_PrevB) + p_PrevB->p_Next = p_NewB; + else + p_MM->freeBlocks[i] = p_NewB; + break; + } + + if ((alignBase < p_CurrB->base) && (end >= p_CurrB->base)) + { + p_CurrB->base = alignBase; + } + + /* if size of the free block is less then alignment + * deletes that free block from the free list. */ + if ( (p_CurrB->end - p_CurrB->base) < alignment) + { + if ( p_PrevB ) + p_PrevB->p_Next = p_CurrB->p_Next; + else + p_MM->freeBlocks[i] = p_CurrB->p_Next; + XX_Free(p_CurrB); + } + break; + } + else + { + p_PrevB = p_CurrB; + p_CurrB = p_CurrB->p_Next; + } + } + + /* If no free block found to be updated, insert a new free block + * to the end of the free list. + */ + if ( !p_CurrB && ((((uint64_t)(end-base)) & ((uint64_t)(alignment-1))) == 0) ) + { + if ((p_NewB = CreateFreeBlock(alignBase, end-base)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + + if (p_PrevB) + p_PrevB->p_Next = p_NewB; + else + p_MM->freeBlocks[i] = p_NewB; + } + + /* Update boundaries of the new free block */ + if ((alignment == 1) && !p_NewB) + { + if ( p_CurrB && base > p_CurrB->base ) + base = p_CurrB->base; + if ( p_CurrB && end < p_CurrB->end ) + end = p_CurrB->end; + } + } + + return (E_OK); +} + +/**************************************************************** + * Routine: CutFree + * + * Description: + * Cuts a free block from holdBase to holdEnd from the free lists. + * That is, it updates all free lists of the MM object do + * not include a block of memory from holdBase to holdEnd. + * For each free lists it seek for a free block that holds + * either holdBase or holdEnd. If such block is found it updates it. + * + * Arguments: + * p_MM - pointer to the MM object + * holdBase - base address of the allocated block + * holdEnd - end address of the allocated block + * + * Return value: + * E_OK is returned on success, + * otherwise returns an error code. + * + ****************************************************************/ +static t_Error CutFree(t_MM *p_MM, uint64_t holdBase, uint64_t holdEnd) +{ + t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB; + uint64_t alignBase, base, end; + uint64_t alignment; + int i; + + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + p_PrevB = p_NewB = 0; + p_CurrB = p_MM->freeBlocks[i]; + + alignment = (uint64_t)(0x1 << i); + alignBase = MAKE_ALIGNED(holdEnd, alignment); + + while ( p_CurrB ) + { + base = p_CurrB->base; + end = p_CurrB->end; + + if ( (holdBase <= base) && (holdEnd <= end) && (holdEnd > base) ) + { + if ( alignBase >= end || + (alignBase < end && ((end-alignBase) < alignment)) ) + { + if (p_PrevB) + p_PrevB->p_Next = p_CurrB->p_Next; + else + p_MM->freeBlocks[i] = p_CurrB->p_Next; + XX_Free(p_CurrB); + } + else + { + p_CurrB->base = alignBase; + } + break; + } + else if ( (holdBase > base) && (holdEnd <= end) ) + { + if ( (holdBase-base) >= alignment ) + { + if ( (alignBase < end) && ((end-alignBase) >= alignment) ) + { + if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + p_NewB->p_Next = p_CurrB->p_Next; + p_CurrB->p_Next = p_NewB; + } + p_CurrB->end = holdBase; + } + else if ( (alignBase < end) && ((end-alignBase) >= alignment) ) + { + p_CurrB->base = alignBase; + } + else + { + if (p_PrevB) + p_PrevB->p_Next = p_CurrB->p_Next; + else + p_MM->freeBlocks[i] = p_CurrB->p_Next; + XX_Free(p_CurrB); + } + break; + } + else + { + p_PrevB = p_CurrB; + p_CurrB = p_CurrB->p_Next; + } + } + } + + return (E_OK); +} + +/**************************************************************** + * Routine: AddBusy + * + * Description: + * Adds a new busy block to the list of busy blocks. Note, + * that all busy blocks are ordered by their base address in + * the busy list. + * + * Arguments: + * MM - handler to the MM object + * p_NewBusyB - pointer to the a busy block + * + * Return value: + * None. + * + ****************************************************************/ +static void AddBusy(t_MM *p_MM, t_BusyBlock *p_NewBusyB) +{ + t_BusyBlock *p_CurrBusyB, *p_PrevBusyB; + + /* finds a place of a new busy block in the list of busy blocks */ + p_PrevBusyB = 0; + p_CurrBusyB = p_MM->busyBlocks; + + while ( p_CurrBusyB && p_NewBusyB->base > p_CurrBusyB->base ) + { + p_PrevBusyB = p_CurrBusyB; + p_CurrBusyB = p_CurrBusyB->p_Next; + } + + /* insert the new busy block into the list of busy blocks */ + if ( p_CurrBusyB ) + p_NewBusyB->p_Next = p_CurrBusyB; + if ( p_PrevBusyB ) + p_PrevBusyB->p_Next = p_NewBusyB; + else + p_MM->busyBlocks = p_NewBusyB; +} + +/**************************************************************** + * Routine: CutBusy + * + * Description: + * Cuts a block from base to end from the list of busy blocks. + * This is done by updating the list of busy blocks do not + * include a given block, that block is going to be free. If a + * given block is a part of some other busy block, so that + * busy block is updated. If there are number of busy blocks + * included in the given block, so all that blocks are removed + * from the busy list and the end blocks are updated. + * If the given block devides some block into two parts, a new + * busy block is added to the busy list. + * + * Arguments: + * p_MM - pointer to the MM object + * base - base address of a given busy block + * end - end address of a given busy block + * + * Return value: + * E_OK on success, E_NOMEMORY otherwise. + * + ****************************************************************/ +static t_Error CutBusy(t_MM *p_MM, uint64_t base, uint64_t end) +{ + t_BusyBlock *p_CurrB, *p_PrevB, *p_NewB; + + p_CurrB = p_MM->busyBlocks; + p_PrevB = p_NewB = 0; + + while ( p_CurrB ) + { + if ( base < p_CurrB->end ) + { + if ( end > p_CurrB->end ) + { + t_BusyBlock *p_NextB; + while ( p_CurrB->p_Next && end >= p_CurrB->p_Next->end ) + { + p_NextB = p_CurrB->p_Next; + p_CurrB->p_Next = p_CurrB->p_Next->p_Next; + XX_Free(p_NextB); + } + + p_NextB = p_CurrB->p_Next; + if ( p_NextB && end > p_NextB->base ) + { + p_NextB->base = end; + } + } + + if ( base <= p_CurrB->base ) + { + if ( end < p_CurrB->end && end > p_CurrB->base ) + { + p_CurrB->base = end; + } + else if ( end >= p_CurrB->end ) + { + if ( p_PrevB ) + p_PrevB->p_Next = p_CurrB->p_Next; + else + p_MM->busyBlocks = p_CurrB->p_Next; + XX_Free(p_CurrB); + } + } + else + { + if ( end < p_CurrB->end && end > p_CurrB->base ) + { + if ((p_NewB = CreateBusyBlock(end, + p_CurrB->end-end, + p_CurrB->name)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + p_NewB->p_Next = p_CurrB->p_Next; + p_CurrB->p_Next = p_NewB; + } + p_CurrB->end = base; + } + break; + } + else + { + p_PrevB = p_CurrB; + p_CurrB = p_CurrB->p_Next; + } + } + + return (E_OK); +} + +/**************************************************************** + * Routine: MmGetGreaterAlignment + * + * Description: + * Allocates a block of memory according to the given size + * and the alignment. That routine is called from the MM_Get + * routine if the required alignment is greater then MM_MAX_ALIGNMENT. + * In that case, it goes over free blocks of 64 byte align list + * and checks if it has the required size of bytes of the required + * alignment. If no blocks found returns ILLEGAL_BASE. + * After the block is found and data is allocated, it calls + * the internal CutFree routine to update all free lists + * do not include a just allocated block. Of course, each + * free list contains a free blocks with the same alignment. + * It is also creates a busy block that holds + * information about an allocated block. + * + * Arguments: + * MM - handle to the MM object + * size - size of the MM + * alignment - index as a power of two defines + * a required alignment that is greater then 64. + * name - the name that specifies an allocated block. + * + * Return value: + * base address of an allocated block. + * ILLEGAL_BASE if can't allocate a block + * + ****************************************************************/ +static uint64_t MmGetGreaterAlignment(t_MM *p_MM, uint64_t size, uint64_t alignment, char* name) +{ + t_FreeBlock *p_FreeB; + t_BusyBlock *p_NewBusyB; + uint64_t holdBase, holdEnd, alignBase = 0; + + /* goes over free blocks of the 64 byte alignment list + and look for a block of the suitable size and + base address according to the alignment. */ + p_FreeB = p_MM->freeBlocks[MM_MAX_ALIGNMENT]; + + while ( p_FreeB ) + { + alignBase = MAKE_ALIGNED(p_FreeB->base, alignment); + + /* the block is found if the aligned base inside the block + * and has the anough size. */ + if ( alignBase >= p_FreeB->base && + alignBase < p_FreeB->end && + size <= (p_FreeB->end - alignBase) ) + break; + else + p_FreeB = p_FreeB->p_Next; + } + + /* If such block isn't found */ + if ( !p_FreeB ) + return (uint64_t)(ILLEGAL_BASE); + + holdBase = alignBase; + holdEnd = alignBase + size; + + /* init a new busy block */ + if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL) + return (uint64_t)(ILLEGAL_BASE); + + /* calls Update routine to update a lists of free blocks */ + if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK ) + return (uint64_t)(ILLEGAL_BASE); + + /* insert the new busy block into the list of busy blocks */ + AddBusy ( p_MM, p_NewBusyB ); + + return (holdBase); +} + + +/********************************************************************** + * MM API routines set * + **********************************************************************/ + +/*****************************************************************************/ +t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size) +{ + t_MM *p_MM; + uint64_t newBase, newSize; + int i; + + if (!size) + { + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size (should be positive)")); + } + + /* Initializes a new MM object */ + p_MM = (t_MM *)XX_Malloc(sizeof(t_MM)); + if (!p_MM) + { + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + } + + p_MM->h_Spinlock = XX_InitSpinlock(); + if (!p_MM->h_Spinlock) + { + XX_Free(p_MM); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MM spinlock!")); + } + + /* Initializes counter of free memory to total size */ + p_MM->freeMemSize = size; + + /* Initializes a new memory block */ + if ((p_MM->memBlocks = CreateNewBlock(base, size)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + + /* A busy list is empty */ + p_MM->busyBlocks = 0; + + /* Initializes a new free block for each free list*/ + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + newBase = MAKE_ALIGNED( base, (0x1 << i) ); + newSize = size - (newBase - base); + + if ((p_MM->freeBlocks[i] = CreateFreeBlock(newBase, newSize)) == NULL) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + } + + *h_MM = p_MM; + + return (E_OK); +} + +/*****************************************************************************/ +void MM_Free(t_Handle h_MM) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_MemBlock *p_MemBlock; + t_BusyBlock *p_BusyBlock; + t_FreeBlock *p_FreeBlock; + void *p_Block; + int i; + + ASSERT_COND(p_MM); + + /* release memory allocated for busy blocks */ + p_BusyBlock = p_MM->busyBlocks; + while ( p_BusyBlock ) + { + p_Block = p_BusyBlock; + p_BusyBlock = p_BusyBlock->p_Next; + XX_Free(p_Block); + } + + /* release memory allocated for free blocks */ + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + p_FreeBlock = p_MM->freeBlocks[i]; + while ( p_FreeBlock ) + { + p_Block = p_FreeBlock; + p_FreeBlock = p_FreeBlock->p_Next; + XX_Free(p_Block); + } + } + + /* release memory allocated for memory blocks */ + p_MemBlock = p_MM->memBlocks; + while ( p_MemBlock ) + { + p_Block = p_MemBlock; + p_MemBlock = p_MemBlock->p_Next; + XX_Free(p_Block); + } + + if (p_MM->h_Spinlock) + XX_FreeSpinlock(p_MM->h_Spinlock); + + /* release memory allocated for MM object itself */ + XX_Free(p_MM); +} + +/*****************************************************************************/ +uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char* name) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_FreeBlock *p_FreeB; + t_BusyBlock *p_NewBusyB; + uint64_t holdBase, holdEnd, j, i = 0; + uint32_t intFlags; + + SANITY_CHECK_RETURN_VALUE(p_MM, E_INVALID_HANDLE, (uint64_t)ILLEGAL_BASE); + + /* checks that alignment value is greater then zero */ + if (alignment == 0) + { + alignment = 1; + } + + j = alignment; + + /* checks if alignment is a power of two, if it correct and if the + required size is multiple of the given alignment. */ + while ((j & 0x1) == 0) + { + i++; + j = j >> 1; + } + + /* if the given alignment isn't power of two, returns an error */ + if (j != 1) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("alignment (should be power of 2)")); + return (uint64_t)ILLEGAL_BASE; + } + + if (i > MM_MAX_ALIGNMENT) + { + return (MmGetGreaterAlignment(p_MM, size, alignment, name)); + } + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + /* look for a block of the size greater or equal to the required size. */ + p_FreeB = p_MM->freeBlocks[i]; + while ( p_FreeB && (p_FreeB->end - p_FreeB->base) < size ) + p_FreeB = p_FreeB->p_Next; + + /* If such block is found */ + if ( !p_FreeB ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + holdBase = p_FreeB->base; + holdEnd = holdBase + size; + + /* init a new busy block */ + if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* calls Update routine to update a lists of free blocks */ + if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* Decreasing the allocated memory size from free memory size */ + p_MM->freeMemSize -= size; + + /* insert the new busy block into the list of busy blocks */ + AddBusy ( p_MM, p_NewBusyB ); + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (holdBase); +} + +/*****************************************************************************/ +uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char* name) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_FreeBlock *p_FreeB; + t_BusyBlock *p_NewBusyB; + uint32_t intFlags; + bool blockIsFree = FALSE; + + ASSERT_COND(p_MM); + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + p_FreeB = p_MM->freeBlocks[0]; /* The biggest free blocks are in the + free list with alignment 1 */ + + while ( p_FreeB ) + { + if ( base >= p_FreeB->base && (base+size) <= p_FreeB->end ) + { + blockIsFree = TRUE; + break; + } + else + p_FreeB = p_FreeB->p_Next; + } + + if ( !blockIsFree ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* init a new busy block */ + if ((p_NewBusyB = CreateBusyBlock(base, size, name)) == NULL) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* calls Update routine to update a lists of free blocks */ + if ( CutFree ( p_MM, base, base+size ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* Decreasing the allocated memory size from free memory size */ + p_MM->freeMemSize -= size; + + /* insert the new busy block into the list of busy blocks */ + AddBusy ( p_MM, p_NewBusyB ); + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (base); +} + +/*****************************************************************************/ +uint64_t MM_GetForceMin(t_Handle h_MM, uint64_t size, uint64_t alignment, uint64_t min, char* name) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_FreeBlock *p_FreeB; + t_BusyBlock *p_NewBusyB; + uint64_t holdBase, holdEnd, j = alignment, i=0; + uint32_t intFlags; + + ASSERT_COND(p_MM); + + /* checks if alignment is a power of two, if it correct and if the + required size is multiple of the given alignment. */ + while ((j & 0x1) == 0) + { + i++; + j = j >> 1; + } + + if ( (j != 1) || (i > MM_MAX_ALIGNMENT) ) + { + return (uint64_t)(ILLEGAL_BASE); + } + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + p_FreeB = p_MM->freeBlocks[i]; + + /* look for the first block that contains the minimum + base address. If the whole required size may be fit + into it, use that block, otherwise look for the next + block of size greater or equal to the required size. */ + while ( p_FreeB && (min >= p_FreeB->end)) + p_FreeB = p_FreeB->p_Next; + + /* If such block is found */ + if ( !p_FreeB ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* if this block is large enough, use this block */ + holdBase = ( min <= p_FreeB->base ) ? p_FreeB->base : min; + if ((holdBase + size) <= p_FreeB->end ) + { + holdEnd = holdBase + size; + } + else + { + p_FreeB = p_FreeB->p_Next; + while ( p_FreeB && ((p_FreeB->end - p_FreeB->base) < size) ) + p_FreeB = p_FreeB->p_Next; + + /* If such block is found */ + if ( !p_FreeB ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + holdBase = p_FreeB->base; + holdEnd = holdBase + size; + } + + /* init a new busy block */ + if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* calls Update routine to update a lists of free blocks */ + if ( CutFree( p_MM, holdBase, holdEnd ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(ILLEGAL_BASE); + } + + /* Decreasing the allocated memory size from free memory size */ + p_MM->freeMemSize -= size; + + /* insert the new busy block into the list of busy blocks */ + AddBusy( p_MM, p_NewBusyB ); + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (holdBase); +} + +/*****************************************************************************/ +uint64_t MM_Put(t_Handle h_MM, uint64_t base) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_BusyBlock *p_BusyB, *p_PrevBusyB; + uint64_t size; + uint32_t intFlags; + + ASSERT_COND(p_MM); + + /* Look for a busy block that have the given base value. + * That block will be returned back to the memory. + */ + p_PrevBusyB = 0; + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + p_BusyB = p_MM->busyBlocks; + while ( p_BusyB && base != p_BusyB->base ) + { + p_PrevBusyB = p_BusyB; + p_BusyB = p_BusyB->p_Next; + } + + if ( !p_BusyB ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(0); + } + + if ( AddFree( p_MM, p_BusyB->base, p_BusyB->end ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(0); + } + + /* removes a busy block form the list of busy blocks */ + if ( p_PrevBusyB ) + p_PrevBusyB->p_Next = p_BusyB->p_Next; + else + p_MM->busyBlocks = p_BusyB->p_Next; + + size = p_BusyB->end - p_BusyB->base; + + /* Adding the deallocated memory size to free memory size */ + p_MM->freeMemSize += size; + + XX_Free(p_BusyB); + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (size); +} + +/*****************************************************************************/ +uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size) +{ + t_MM *p_MM = (t_MM *)h_MM; + uint64_t end = base + size; + uint32_t intFlags; + + ASSERT_COND(p_MM); + + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + + if ( CutBusy( p_MM, base, end ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(0); + } + + if ( AddFree ( p_MM, base, end ) != E_OK ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + return (uint64_t)(0); + } + + /* Adding the deallocated memory size to free memory size */ + p_MM->freeMemSize += size; + + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (size); +} + +/*****************************************************************************/ +t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_MemBlock *p_MemB, *p_NewMemB; + t_Error errCode; + uint32_t intFlags; + + ASSERT_COND(p_MM); + + /* find a last block in the list of memory blocks to insert a new + * memory block + */ + intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); + + p_MemB = p_MM->memBlocks; + while ( p_MemB->p_Next ) + { + if ( base >= p_MemB->base && base < p_MemB->end ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + } + p_MemB = p_MemB->p_Next; + } + /* check for a last memory block */ + if ( base >= p_MemB->base && base < p_MemB->end ) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + } + + /* create a new memory block */ + if ((p_NewMemB = CreateNewBlock(base, size)) == NULL) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + } + + /* append a new memory block to the end of the list of memory blocks */ + p_MemB->p_Next = p_NewMemB; + + /* add a new free block to the free lists */ + errCode = AddFree(p_MM, base, base+size); + if (errCode) + { + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + p_MemB->p_Next = 0; + XX_Free(p_NewMemB); + return ((t_Error)errCode); + } + + /* Adding the new block size to free memory size */ + p_MM->freeMemSize += size; + + XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); + + return (E_OK); +} + +/*****************************************************************************/ +uint64_t MM_GetMemBlock(t_Handle h_MM, int index) +{ + t_MM *p_MM = (t_MM*)h_MM; + t_MemBlock *p_MemBlock; + int i; + + ASSERT_COND(p_MM); + + p_MemBlock = p_MM->memBlocks; + for (i=0; i < index; i++) + p_MemBlock = p_MemBlock->p_Next; + + if ( p_MemBlock ) + return (p_MemBlock->base); + else + return (uint64_t)ILLEGAL_BASE; +} + +/*****************************************************************************/ +uint64_t MM_GetBase(t_Handle h_MM) +{ + t_MM *p_MM = (t_MM*)h_MM; + t_MemBlock *p_MemBlock; + + ASSERT_COND(p_MM); + + p_MemBlock = p_MM->memBlocks; + return p_MemBlock->base; +} + +/*****************************************************************************/ +bool MM_InRange(t_Handle h_MM, uint64_t addr) +{ + t_MM *p_MM = (t_MM*)h_MM; + t_MemBlock *p_MemBlock; + + ASSERT_COND(p_MM); + + p_MemBlock = p_MM->memBlocks; + + if ((addr >= p_MemBlock->base) && (addr < p_MemBlock->end)) + return TRUE; + else + return FALSE; +} + +/*****************************************************************************/ +uint64_t MM_GetFreeMemSize(t_Handle h_MM) +{ + t_MM *p_MM = (t_MM*)h_MM; + + ASSERT_COND(p_MM); + + return p_MM->freeMemSize; +} + +/*****************************************************************************/ +void MM_Dump(t_Handle h_MM) +{ + t_MM *p_MM = (t_MM *)h_MM; + t_FreeBlock *p_FreeB; + t_BusyBlock *p_BusyB; + int i; + + p_BusyB = p_MM->busyBlocks; + XX_Print("List of busy blocks:\n"); + while (p_BusyB) + { + XX_Print("\t0x%p: (%s: b=0x%llx, e=0x%llx)\n", p_BusyB, p_BusyB->name, p_BusyB->base, p_BusyB->end ); + p_BusyB = p_BusyB->p_Next; + } + + XX_Print("\nLists of free blocks according to alignment:\n"); + for (i=0; i <= MM_MAX_ALIGNMENT; i++) + { + XX_Print("%d alignment:\n", (0x1 << i)); + p_FreeB = p_MM->freeBlocks[i]; + while (p_FreeB) + { + XX_Print("\t0x%p: (b=0x%llx, e=0x%llx)\n", p_FreeB, p_FreeB->base, p_FreeB->end); + p_FreeB = p_FreeB->p_Next; + } + XX_Print("\n"); + } +} diff --git a/drivers/net/ethernet/freescale/fman/etc/mm.h b/drivers/net/ethernet/freescale/fman/etc/mm.h new file mode 100644 index 0000000..43b2298 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/etc/mm.h @@ -0,0 +1,105 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * 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: mm.h + * + * + * Description: + * MM (Memory Management) object definitions. + * It also includes definitions of the Free Block, Busy Block + * and Memory Block structures used by the MM object. + * + ****************************************************************/ + +#ifndef __MM_H +#define __MM_H + + +#include "mm_ext.h" + +#define __ERR_MODULE__ MODULE_MM + + +#define MAKE_ALIGNED(addr, align) \ + (((uint64_t)(addr) + ((align) - 1)) & (~(((uint64_t)align) - 1))) + + +/* t_MemBlock data structure defines parameters of the Memory Block */ +typedef struct t_MemBlock +{ + struct t_MemBlock *p_Next; /* Pointer to the next memory block */ + + uint64_t base; /* Base address of the memory block */ + uint64_t end; /* End address of the memory block */ +} t_MemBlock; + + +/* t_FreeBlock data structure defines parameters of the Free Block */ +typedef struct t_FreeBlock +{ + struct t_FreeBlock *p_Next; /* Pointer to the next free block */ + + uint64_t base; /* Base address of the block */ + uint64_t end; /* End address of the block */ +} t_FreeBlock; + + +/* t_BusyBlock data structure defines parameters of the Busy Block */ +typedef struct t_BusyBlock +{ + struct t_BusyBlock *p_Next; /* Pointer to the next free block */ + + uint64_t base; /* Base address of the block */ + uint64_t end; /* End address of the block */ + char name[MM_MAX_NAME_LEN]; /* That block of memory was allocated for + something specified by the Name */ +} t_BusyBlock; + + +/* t_MM data structure defines parameters of the MM object */ +typedef struct t_MM +{ + t_Handle h_Spinlock; + + t_MemBlock *memBlocks; /* List of memory blocks (Memory list) */ + t_BusyBlock *busyBlocks; /* List of busy blocks (Busy list) */ + t_FreeBlock *freeBlocks[MM_MAX_ALIGNMENT + 1]; + /* Alignment lists of free blocks (Free lists) */ + + uint64_t freeMemSize; /* Total size of free memory (in bytes) */ +} t_MM; + + +#endif /* __MM_H */ diff --git a/drivers/net/ethernet/freescale/fman/etc/sprint.c b/drivers/net/ethernet/freescale/fman/etc/sprint.c new file mode 100644 index 0000000..46d2956 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/etc/sprint.c @@ -0,0 +1,81 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * 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: sprint.c */ +/* */ +/* Description: */ +/* Debug routines (externals) */ +/*------------------------------------------------------*/ +#include "string_ext.h" +#include "stdlib_ext.h" +#include "stdarg_ext.h" +#include "sprint_ext.h" +#include "std_ext.h" +#include "xx_ext.h" + + +int Sprint(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +int Snprint(char * buf, uint32_t size, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsnprintf(buf,size,fmt,args); + va_end(args); + return i; +} + +#ifndef NCSW_VXWORKS +int Sscan(const char * buf, const char * fmt, ...) +{ + va_list args; + int i; + + va_start(args,fmt); + i = vsscanf(buf,fmt,args); + va_end(args); + return i; +} +#endif /* NCSW_VXWORKS */ |