| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964 |
- /*
- * Copyright : (C) 2022 Phytium Information Technology, Inc.
- * All Rights Reserved.
- *
- * This program is OPEN SOURCE software: you can redistribute it and/or modify it
- * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
- * either version 1.0 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the Phytium Public License for more details.
- *
- *
- * FilePath: fxmac_bdring.c
- * Date: 2022-04-06 14:46:52
- * LastEditTime: 2022-04-06 14:46:58
- * Description: This file is for
- *
- * Modify History:
- * Ver Who Date Changes
- * ----- ------ -------- --------------------------------------
- */
- #include "fxmac_hw.h"
- #include "fxmac.h"
- #include "fxmac_bdring.h"
- #include "fxmac_bd.h"
- #include "ftypes.h"
- #include "fxmac.h"
- #include "string.h"
- #include "fprintk.h"
- #include "fdebug.h"
- static void FXmacBdSetRxWrap(uintptr bdptr);
- static void FXmacBdSetTxWrap(uintptr bdptr);
- /************************** Variable Definitions *****************************/
- /***************** Macros (Inline Functions) Definitions *********************/
- /**
- * @name: FXMAC_RING_SEEKAHEAD
- * @msg: Move the bdptr argument ahead an arbitrary number of BDs wrapping around
- * to the beginning of the ring if needed.
- * @param ring_ptr is the ring bdptr appears in
- * @param bdptr on input is the starting BD position and on output is the final BD position
- * @param num_bd is the number of BD spaces to increment
- */
- #define FXMAC_RING_SEEKAHEAD(ring_ptr, bdptr, num_bd) \
- { \
- uintptr addr = (uintptr)(void *)(bdptr); \
- \
- addr += ((ring_ptr)->separation * (num_bd)); \
- if ((addr > (ring_ptr)->high_bd_addr) || ((uintptr)(void *)(bdptr) > addr)) \
- { \
- addr -= (ring_ptr)->length; \
- } \
- \
- (bdptr) = (FXmacBd *)(void *)addr; \
- }
- /**
- * @name: FXMAC_RING_SEEKBACK
- * @msg: Move the bdptr argument backwards an arbitrary number of BDs wrapping
- * around to the end of the ring if needed.
- * @param ring_ptr is the ring bdptr appears in
- * @param bdptr on input is the starting BD position and on output is the
- * final BD position
- * @param num_bd is the number of BD spaces to increment
- * @return {*}
- */
- #define FXMAC_RING_SEEKBACK(ring_ptr, bdptr, num_bd) \
- { \
- uintptr addr = (uintptr)(void *)(bdptr); \
- \
- addr -= ((ring_ptr)->separation * (num_bd)); \
- if ((addr < (ring_ptr)->base_bd_addr) || ((uintptr)(void *)(bdptr) < addr)) \
- { \
- addr += (ring_ptr)->length; \
- } \
- \
- (bdptr) = (FXmacBd *)(void *)addr; \
- }
- /**
- * @name: FXmacBdRingCreate
- * @msg: Using a memory segment allocated by the caller, create and setup the BD list
- * for the given DMA channel.
- * @param ring_ptr is the instance to be worked on.
- * @param Physaddr is the physical base address of user memory region.
- * @param Virtaddr is the virtual base address of the user memory region. If
- * address translation is not being utilized, then Virtaddr should be
- * equivalent to Physaddr.
- * @param Alignment governs the byte alignment of individual BDs. This function
- * will enforce a minimum alignment of 4 bytes with no maximum as long
- * as it is specified as a power of 2.
- * @param bd_count is the number of BDs to setup in the user memory region. It
- * is assumed the region is large enough to contain the BDs.
- * @return
- * FT_SUCCESS if initialization was successful
- * FXMAC_ERR_INVALID_PARAM under any of the following conditions:
- * 1) Physaddr and/or Virtaddr are not aligned to the given Alignment
- * parameter.
- * 2) Alignment parameter does not meet minimum requirements or is not a
- * power of 2 value.
- * 3) bd_count is 0.
- */
- FError FXmacBdRingCreate(FXmacBdRing *ring_ptr, uintptr phys_addr,
- uintptr virt_addr, u32 alignment, u32 bd_count)
- {
- u32 i;
- uintptr bd_virt_addr;
- uintptr bd_phy_addr;
- uintptr virt_addr_loc = virt_addr;
- /* In case there is a failure prior to creating list, make sure the
- * following attributes are 0 to prevent calls to other functions
- * from doing anything.
- */
- ring_ptr->all_cnt = 0U;
- ring_ptr->free_cnt = 0U;
- ring_ptr->hw_cnt = 0U;
- ring_ptr->pre_cnt = 0U;
- ring_ptr->post_cnt = 0U;
- /* Make sure alignment parameter meets minimum requirements */
- if (alignment < (u32)FXMAC_DMABD_MINIMUM_ALIGNMENT)
- {
- return (FError)(FXMAC_ERR_INVALID_PARAM);
- }
- /* Make sure alignment is a power of 2 */
- if (((alignment - 0x00000001U) & alignment) != 0x00000000U)
- {
- return (FError)(FXMAC_ERR_INVALID_PARAM);
- }
- /* Make sure phys_addr and virt_addr are on same alignment */
- if (((phys_addr % alignment) != (u32)0) || ((virt_addr_loc % alignment) != (u32)0))
- {
- return (FError)(FXMAC_ERR_INVALID_PARAM);
- }
- /* Is bd_count reasonable? */
- if (bd_count == 0x00000000U)
- {
- return (FError)(FXMAC_ERR_INVALID_PARAM);
- }
- /* Figure out how many bytes will be between the start of adjacent BDs */
- ring_ptr->separation = ((u32)sizeof(FXmacBd));
- /* Must make sure the ring doesn't span address 0x00000000. If it does,
- * then the next/prev BD traversal macros will fail.
- */
- if (virt_addr_loc > ((virt_addr_loc + (ring_ptr->separation * bd_count)) - (u32)1))
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- /* Initial ring setup:
- * - Clear the entire space
- * - Setup each BD's BDA field with the physical address of the next BD
- */
- (void)memset((void *)virt_addr_loc, 0, (ring_ptr->separation * bd_count));
- bd_virt_addr = virt_addr_loc;
- bd_phy_addr = phys_addr + ring_ptr->separation;
- for (i = 1U; i < bd_count; i++)
- {
- bd_virt_addr += ring_ptr->separation;
- bd_phy_addr += ring_ptr->separation;
- }
- /* Setup and initialize pointers and counters */
- ring_ptr->run_state = (u32)(FXMAC_DMA_SG_IS_STOPED);
- ring_ptr->base_bd_addr = virt_addr_loc;
- ring_ptr->phys_base_addr = phys_addr;
- ring_ptr->high_bd_addr = bd_virt_addr;
- ring_ptr->length =
- ((ring_ptr->high_bd_addr - ring_ptr->base_bd_addr) + ring_ptr->separation);
- ring_ptr->all_cnt = (u32)bd_count;
- ring_ptr->free_cnt = (u32)bd_count;
- ring_ptr->free_head = (FXmacBd *)(void *)virt_addr_loc;
- ring_ptr->pre_head = (FXmacBd *)virt_addr_loc;
- ring_ptr->hw_head = (FXmacBd *)virt_addr_loc;
- ring_ptr->hw_tail = (FXmacBd *)virt_addr_loc;
- ring_ptr->post_head = (FXmacBd *)virt_addr_loc;
- ring_ptr->bda_restart = (FXmacBd *)(void *)phys_addr;
- return (FError)(FT_SUCCESS);
- }
- /**
- * @name: FXmacBdRingClone
- * @msg: Clone the given BD into every BD in the list.
- * every field of the source BD is replicated in every BD of the list.
- * @param ring_ptr is the instance to be worked on.
- * @param src_bd_ptr is the source BD template to be cloned into the list. This
- * BD will be modified.
- * @param direction is either FXMAC_SEND or FXMAC_RECV that indicates
- * which direction.
- * @return {*}
- */
- FError FXmacBdRingClone(FXmacBdRing *ring_ptr, FXmacBd *src_bd_ptr,
- u8 direction)
- {
- u32 i;
- uintptr cur_bd;
- /* Can't do this function if there isn't a ring */
- if (ring_ptr->all_cnt == 0x00000000U)
- {
- return (FError)(FXMAC_ERR_SG_NO_LIST);
- }
- /* Can't do this function with the channel running */
- if (ring_ptr->run_state == (u32)FXMAC_DMA_SG_IS_STARTED)
- {
- return (FError)(FT_COMPONENT_IS_STARTED);
- }
- /* Can't do this function with some of the BDs in use */
- if (ring_ptr->free_cnt != ring_ptr->all_cnt)
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- if ((direction != (u8)FXMAC_SEND) && (direction != (u8)FXMAC_RECV))
- {
- return (FError)(FXMAC_ERR_INVALID_PARAM);
- }
- /* Starting from the top of the ring, save bd.next, overwrite the entire
- * BD with the template, then restore bd.next
- */
- cur_bd = ring_ptr->base_bd_addr;
- for (i = 0U; i < ring_ptr->all_cnt; i++)
- {
- memcpy((void *)cur_bd, src_bd_ptr, sizeof(FXmacBd));
- cur_bd += ring_ptr->separation;
- }
- cur_bd -= ring_ptr->separation;
- if (direction == FXMAC_RECV)
- {
- FXmacBdSetRxWrap(cur_bd);
- }
- else
- {
- FXmacBdSetTxWrap(cur_bd);
- }
- return (FError)(FT_SUCCESS);
- }
- /**
- * @name: FXmacBdRingAlloc
- * @msg: Reserve locations in the BD list. The set of returned BDs may be modified
- * in preparation for future DMA transaction(s). Once the BDs are ready to be
- * submitted to hardware, the user must call FXmacBdRingToHw() in the same
- * order which they were allocated here.
- * @param ring_ptr is a pointer to the BD ring instance to be worked on.
- * @param num_bd is the number of BDs to allocate
- * @param bd_set_ptr is an output parameter, it points to the first BD available
- * for modification.
- * @return FT_SUCCESS if the requested number of BDs was returned in the bd_set_ptr
- * parameter.
- * - FXMAC_ERR_GENERAL if there were not enough free BDs to satisfy the request.
- */
- FError FXmacBdRingAlloc(FXmacBdRing *ring_ptr, u32 num_bd,
- FXmacBd **bd_set_ptr)
- {
- FError status;
- /* Enough free BDs available for the request? */
- if (ring_ptr->free_cnt < num_bd)
- {
- status = (FError)(FXMAC_ERR_GENERAL);
- }
- else
- {
- /* Set the return argument and move free_head forward */
- *bd_set_ptr = ring_ptr->free_head;
- FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->free_head, num_bd);
- ring_ptr->free_cnt -= num_bd;
- ring_ptr->pre_cnt += num_bd;
- status = (FError)(FT_SUCCESS);
- }
- return status;
- }
- /**
- * @name: FXmacBdRingUnAlloc
- * @msg: * Fully or partially undo an FXmacBdRingAlloc() operation. Use this
- * function if all the BDs allocated by FXmacBdRingAlloc() could not be
- * transferred to hardware with FXmacBdRingToHw().
- *
- * This function helps out in situations when an unrelated error occurs after
- * BDs have been allocated but before they have been given to hardware.
- * An example of this type of error would be an OS running out of resources.
- *
- * This function is not the same as FXmacBdRingFree(). The Free function
- * returns BDs to the free list after they have been processed by hardware,
- * while UnAlloc returns them before being processed by hardware.
- *
- * There are two scenarios where this function can be used. Full UnAlloc or
- * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned:
- *
- * <pre>
- * status = FXmacBdRingAlloc(Myring_ptr, 10, &bdptr),
- * ...
- * if (Error)
- * {
- * status = FXmacBdRingUnAlloc(Myring_ptr, 10, &bdptr),
- * }
- * </pre>
- *
- * A partial UnAlloc means some of the BDs Alloc'd will be returned:
- *
- * <pre>
- * status = FXmacBdRingAlloc(Myring_ptr, 10, &bdptr),
- * BdsLeft = 10,
- * cur_bd_ptr = bdptr,
- *
- * while (BdsLeft)
- * {
- * if (Error)
- * {
- * status = FXmacBdRingUnAlloc(Myring_ptr, BdsLeft, cur_bd_ptr),
- * }
- *
- * cur_bd_ptr = FXMAC_BD_RING_NEXT(Myring_ptr, cur_bd_ptr),
- * BdsLeft--,
- * }
- * </pre>
- *
- * A partial UnAlloc must include the last BD in the list that was Alloc'd.
- *
- * @param ring_ptr is a pointer to the instance to be worked on.
- * @param num_bd is the number of BDs to allocate
- * @param bd_set_ptr is an output parameter, it points to the first BD available
- * for modification.
- *
- * @return
- * - FT_SUCCESS if the BDs were unallocated.
- * - FXMAC_ERR_GENERAL if num_bd parameter was greater that the number of BDs in
- * the preprocessing state.
- *
- * @return {*}
- */
- FError FXmacBdRingUnAlloc(FXmacBdRing *ring_ptr, u32 num_bd,
- FXmacBd *bd_set_ptr)
- {
- FError status;
- (void)bd_set_ptr;
- FASSERT(ring_ptr != NULL);
- FASSERT(bd_set_ptr != NULL);
- /* Enough BDs in the free state for the request? */
- if (ring_ptr->pre_cnt < num_bd)
- {
- status = (FError)(FXMAC_ERR_GENERAL);
- }
- else
- {
- /* Set the return argument and move free_head backward */
- FXMAC_RING_SEEKBACK(ring_ptr, (ring_ptr->free_head), num_bd);
- ring_ptr->free_cnt += num_bd;
- ring_ptr->pre_cnt -= num_bd;
- status = (FError)(FT_SUCCESS);
- }
- return status;
- }
- /**
- * @name: FXmacBdRingToHw
- * @msg: Enqueue a set of BDs to hardware that were previously allocated by
- * FXmacBdRingAlloc(). Once this function returns, the argument BD set goes
- * under hardware control. Any changes made to these BDs after this point will
- * corrupt the BD list leading to data corruption and system instability.
- *
- * @param ring_ptr is a pointer to the instance to be worked on.
- * @param num_bd is the number of BDs in the set.
- * @param bd_set_ptr is the first BD of the set to commit to hardware.
- * @return FT_SUCCESS if the set of BDs was accepted and enqueued to hardware.
- * XST_FAILURE if the set of BDs was rejected because the last BD of the set
- * did not have its "last" bit set.
- * FXMAC_ERR_SG_LIST if this function was called out of sequence with
- * FXmacBdRingAlloc().
- */
- FError FXmacBdRingToHw(FXmacBdRing *ring_ptr, u32 num_bd,
- FXmacBd *bd_set_ptr)
- {
- FXmacBd *cur_bd_ptr;
- u32 i;
- FError status;
- /* if no bds to process, simply return. */
- if (0U == num_bd)
- {
- status = (FError)(FT_SUCCESS);
- }
- else
- {
- /* Make sure we are in sync with FXmacBdRingAlloc() */
- if ((ring_ptr->pre_cnt < num_bd) || (ring_ptr->pre_head != bd_set_ptr))
- {
- status = (FError)(FXMAC_ERR_SG_LIST);
- }
- else
- {
- cur_bd_ptr = bd_set_ptr;
- for (i = 0U; i < num_bd; i++)
- {
- cur_bd_ptr = (FXmacBd *)((void *)FXMAC_BD_RING_NEXT(ring_ptr, cur_bd_ptr));
- }
- /* Adjust ring pointers & counters */
- FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->pre_head, num_bd);
- ring_ptr->pre_cnt -= num_bd;
- ring_ptr->hw_tail = cur_bd_ptr;
- ring_ptr->hw_cnt += num_bd;
- status = (FError)(FT_SUCCESS);
- }
- }
- return status;
- }
- /**
- * @name: FXmacBdRingFromHwTx
- * @msg: Returns a set of BD(s) that have been processed by hardware. The returned
- * BDs may be examined to determine the outcome of the DMA transaction(s).
- * Once the BDs have been examined, the user must call FXmacBdRingFree()
- * in the same order which they were retrieved here. Example:
- *
- * <pre>
- * num_bd = FXmacBdRingFromHwTx(Myring_ptr, MaxBd, &MyBdSet),
- * if (num_bd == 0)
- * {
- * * hardware has nothing ready for us yet*
- * }
- *
- * cur_bd = MyBdSet,
- * for (i=0; i<num_bd; i++)
- * {
- * * Examine cur_bd for post processing *.....
- *
- * * Onto next BD *
- * cur_bd = FXMAC_BD_RING_NEXT(Myring_ptr, cur_bd),
- * }
- *
- * FXmacBdRingFree(Myring_ptr, num_bd, MyBdSet), *Return list*
- * }
- * </pre>
- *
- * A more advanced use of this function may allocate multiple sets of BDs.
- * They must be retrieved from hardware and freed in the correct sequence:
- * <pre>
- * * Legal *
- * FXmacBdRingFromHwTx(Myring_ptr, num_bd1, &MySet1),
- * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
- *
- * * Legal *
- * FXmacBdRingFromHwTx(Myring_ptr, num_bd1, &MySet1),
- * FXmacBdRingFromHwTx(Myring_ptr, num_bd2, &MySet2),
- * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
- * FXmacBdRingFree(Myring_ptr, num_bd2, MySet2),
- *
- * * Not legal *
- * FXmacBdRingFromHwTx(Myring_ptr, num_bd1, &MySet1),
- * FXmacBdRingFromHwTx(Myring_ptr, num_bd2, &MySet2),
- * FXmacBdRingFree(Myring_ptr, num_bd2, MySet2),
- * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
- * </pre>
- *
- * If hardware has only partially completed a packet spanning multiple BDs,
- * then none of the BDs for that packet will be included in the results.
- *
- * @param ring_ptr is a pointer to the instance to be worked on.
- * @param bd_limit is the maximum number of BDs to return in the set.
- * @param bd_set_ptr is an output parameter, it points to the first BD available
- * for examination.
- *
- * @return
- * The number of BDs processed by hardware. A value of 0 indicates that no
- * data is available. No more than bd_limit BDs will be returned.
- *
- * @return
- * The number of BDs processed by hardware. A value of 0 indicates that no
- * data is available. No more than bd_limit BDs will be returned.
- */
- u32 FXmacBdRingFromHwTx(FXmacBdRing *ring_ptr, u32 bd_limit,
- FXmacBd **bd_set_ptr)
- {
- FXmacBd *cur_bd_ptr;
- u32 bd_str = 0U;
- u32 bd_count;
- u32 bd_partial_count;
- u32 Sop = 0U;
- u32 status;
- u32 bd_limitLoc = bd_limit;
- cur_bd_ptr = ring_ptr->hw_head;
- bd_count = 0U;
- bd_partial_count = 0U;
- /* If no BDs in work group, then there's nothing to search */
- if (ring_ptr->hw_cnt == 0x00000000U)
- {
- *bd_set_ptr = NULL;
- status = 0U;
- }
- else
- {
- if (bd_limitLoc > ring_ptr->hw_cnt)
- {
- bd_limitLoc = ring_ptr->hw_cnt;
- }
- /* Starting at hw_head, keep moving forward in the list until:
- * - A BD is encountered with its new/used bit set which means
- * hardware has not completed processing of that BD.
- * - ring_ptr->hw_tail is reached and ring_ptr->hw_cnt is reached.
- * - The number of requested BDs has been processed
- */
- while (bd_count < bd_limitLoc)
- {
- /* Read the status */
- if (cur_bd_ptr != NULL)
- {
- bd_str = FXMAC_BD_READ(cur_bd_ptr, FXMAC_BD_STAT_OFFSET);
- }
- if ((Sop == 0x00000000U) && ((bd_str & FXMAC_TXBUF_USED_MASK) != 0x00000000U))
- {
- Sop = 1U;
- }
- if (Sop == 0x00000001U)
- {
- bd_count++;
- bd_partial_count++;
- }
- /* hardware has processed this BD so check the "last" bit.
- * If it is clear, then there are more BDs for the current
- * packet. Keep a count of these partial packet BDs.
- */
- if ((Sop == 0x00000001U) && ((bd_str & FXMAC_TXBUF_LAST_MASK) != 0x00000000U))
- {
- Sop = 0U;
- bd_partial_count = 0U;
- }
- /* Move on to next BD in work group */
- cur_bd_ptr = FXMAC_BD_RING_NEXT(ring_ptr, cur_bd_ptr);
- }
- /* Subtract off any partial packet BDs found */
- bd_count -= bd_partial_count;
- /* If bd_count is non-zero then BDs were found to return. Set return
- * parameters, update pointers and counters, return success
- */
- if (bd_count > 0x00000000U)
- {
- *bd_set_ptr = ring_ptr->hw_head;
- ring_ptr->hw_cnt -= bd_count;
- ring_ptr->post_cnt += bd_count;
- FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->hw_head, bd_count);
- status = (bd_count);
- }
- else
- {
- *bd_set_ptr = NULL;
- status = 0U;
- }
- }
- return status;
- }
- /**
- * @name: FXmacBdRingFromHwRx
- * @msg: Returns a set of BD(s) that have been processed by hardware. The returned
- * BDs may be examined to determine the outcome of the DMA transaction(s).
- * Once the BDs have been examined, the user must call FXmacBdRingFree()
- * in the same order which they were retrieved here. Example:
- *
- * <pre>
- * num_bd = FXmacBdRingFromHwRx(Myring_ptr, MaxBd, &MyBdSet),
- *
- * if (num_bd == 0)
- * {
- * *hardware has nothing ready for us yet*
- * }
- *
- * cur_bd = MyBdSet,
- * for (i=0; i<num_bd; i++)
- * {
- * * Examine cur_bd for post processing *.....
- *
- * * Onto next BD *
- * cur_bd = FXMAC_BD_RING_NEXT(Myring_ptr, cur_bd),
- * }
- *
- * FXmacBdRingFree(Myring_ptr, num_bd, MyBdSet), * Return list *
- * }
- * </pre>
- *
- * A more advanced use of this function may allocate multiple sets of BDs.
- * They must be retrieved from hardware and freed in the correct sequence:
- * <pre>
- * * Legal *
- * FXmacBdRingFromHwRx(Myring_ptr, num_bd1, &MySet1),
- * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
- *
- * * Legal *
- * FXmacBdRingFromHwRx(Myring_ptr, num_bd1, &MySet1),
- * FXmacBdRingFromHwRx(Myring_ptr, num_bd2, &MySet2),
- * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
- * FXmacBdRingFree(Myring_ptr, num_bd2, MySet2),
- *
- * * Not legal *
- * FXmacBdRingFromHwRx(Myring_ptr, num_bd1, &MySet1),
- * FXmacBdRingFromHwRx(Myring_ptr, num_bd2, &MySet2),
- * FXmacBdRingFree(Myring_ptr, num_bd2, MySet2),
- * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
- * </pre>
- *
- * If hardware has only partially completed a packet spanning multiple BDs,
- * then none of the BDs for that packet will be included in the results.
- *
- * @param ring_ptr is a pointer to the instance to be worked on.
- * @param bd_limit is the maximum number of BDs to return in the set.
- * @param bd_set_ptr is an output parameter, it points to the first BD available
- * for examination.
- *
- * @return
- * The number of BDs processed by hardware. A value of 0 indicates that no
- * data is available. No more than bd_limit BDs will be returned.
- */
- u32 FXmacBdRingFromHwRx(FXmacBdRing *ring_ptr, u32 bd_limit,
- FXmacBd **bd_set_ptr)
- {
- FXmacBd *cur_bd_ptr;
- u32 bd_str = 0U;
- u32 bd_count;
- u32 bd_partial_count;
- u32 status;
- cur_bd_ptr = ring_ptr->hw_head;
- bd_count = 0U;
- bd_partial_count = 0U;
- /* If no BDs in work group, then there's nothing to search */
- if (ring_ptr->hw_cnt == 0x00000000U)
- {
- *bd_set_ptr = NULL;
- status = 0U;
- }
- else
- {
- /* Starting at hw_head, keep moving forward in the list until:
- * - A BD is encountered with its new/used bit set which means
- * hardware has completed processing of that BD.
- * - ring_ptr->hw_tail is reached and ring_ptr->hw_cnt is reached.
- * - The number of requested BDs has been processed
- */
- while (bd_count < bd_limit)
- {
- /* Read the status */
- if (cur_bd_ptr != NULL)
- {
- bd_str = FXMAC_BD_READ(cur_bd_ptr, FXMAC_BD_STAT_OFFSET);
- }
- if ((!(FXMAC_BD_IS_RX_NEW(cur_bd_ptr))) == TRUE)
- {
- break;
- }
- bd_count++;
- /* hardware has processed this BD so check the "last" bit. If
- * it is clear, then there are more BDs for the current packet.
- * Keep a count of these partial packet BDs.
- */
- if ((bd_str & FXMAC_RXBUF_EOF_MASK) != 0x00000000U)
- {
- bd_partial_count = 0U;
- }
- else
- {
- bd_partial_count++;
- }
- /* Move on to next BD in work group */
- cur_bd_ptr = FXMAC_BD_RING_NEXT(ring_ptr, cur_bd_ptr);
- // if((bd_str & FXMAC_RXBUF_EOF_MASK) != 0x00000000U)
- // {
- // if(bd_str &FXMAC_RXBUF_FCS_STATUS_MASK)
- // {
- // f_printk("********** error fcs data is appear ************* \r\n");
- // FtDumpHexWord(FXMAC_BD_READ(cur_bd_ptr,0) &(0xfffffff8),bd_str&FXMAC_RXBUF_LEN_MASK);
- // f_printk("********** end ************* \r\n");
- // }
- // }
- }
- /* Subtract off any partial packet BDs found */
- bd_count -= bd_partial_count;
- /* If bd_count is non-zero then BDs were found to return. Set return
- * parameters, update pointers and counters, return success
- */
- if (bd_count > 0x00000000U)
- {
- *bd_set_ptr = ring_ptr->hw_head;
- ring_ptr->hw_cnt -= bd_count;
- ring_ptr->post_cnt += bd_count;
- FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->hw_head, bd_count);
- status = (bd_count);
- }
- else
- {
- *bd_set_ptr = NULL;
- status = 0U;
- }
- }
- return status;
- }
- /**
- * @name: FXmacBdRingFree
- * @msg: Frees a set of BDs that had been previously retrieved with
- * FXmacBdRingFromHw().
- *
- * @param ring_ptr is a pointer to the instance to be worked on.
- * @param num_bd is the number of BDs to free.
- * @param bd_set_ptr is the head of a list of BDs returned by
- * FXmacBdRingFromHw().
- *
- * @return
- * FT_SUCCESS if the set of BDs was freed.
- * FXMAC_ERR_SG_LIST if this function was called out of sequence with
- * FXmacBdRingFromHw().
- */
- FError FXmacBdRingFree(FXmacBdRing *ring_ptr, u32 num_bd,
- FXmacBd *bd_set_ptr)
- {
- FError status;
- /* if no bds to process, simply return. */
- if (0x00000000U == num_bd)
- {
- status = (FError)(FT_SUCCESS);
- }
- else
- {
- /* Make sure we are in sync with FXmacBdRingFromHw() */
- if ((ring_ptr->post_cnt < num_bd) || (ring_ptr->post_head != bd_set_ptr))
- {
- status = (FError)(FXMAC_ERR_SG_LIST);
- }
- else
- {
- /* Update pointers and counters */
- ring_ptr->free_cnt += num_bd;
- ring_ptr->post_cnt -= num_bd;
- FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->post_head, num_bd);
- status = (FError)(FT_SUCCESS);
- }
- }
- return status;
- }
- /**
- * @name: FXmacBdRingCheck
- * @msg: Check the internal data structures of the BD ring for the provided channel.
- * The following checks are made:
- *
- * - Is the BD ring linked correctly in physical address space.
- * - Do the internal pointers point to BDs in the ring.
- * - Do the internal counters add up.
- *
- * The channel should be stopped prior to calling this function.
- *
- * @param {FXmacBdRing} ring_ptr is a pointer to the instance to be worked on.
- * @param {u8} direction is either FXMAC_SEND or FXMAC_RECV that indicates
- * which direction.
- * @return {*}
- * FT_SUCCESS if the set of BDs was freed.
- * XST_DMA_SG_NO_LIST if the list has not been created.
- * FT_COMPONENT_IS_STARTED if the channel is not stopped.
- * FXMAC_ERR_SG_LIST if a problem is found with the internal data
- * structures. If this value is returned, the channel should be reset to
- * avoid data corruption or system instability.
- */
- FError FXmacBdRingCheck(FXmacBdRing *ring_ptr, u8 direction)
- {
- uintptr addr_v, addr_p;
- u32 i;
- if ((direction != (u8)FXMAC_SEND) && (direction != (u8)FXMAC_RECV))
- {
- return (FError)(FXMAC_ERR_INVALID_PARAM);
- }
- /* Is the list created */
- if (ring_ptr->all_cnt == 0x00000000U)
- {
- return (FError)(FXMAC_ERR_SG_NO_LIST);
- }
- /* Can't check if channel is running */
- if (ring_ptr->run_state == (u32)FXMAC_DMA_SG_IS_STARTED)
- {
- return (FError)(FT_COMPONENT_IS_STARTED);
- }
- /* run_state doesn't make sense */
- if (ring_ptr->run_state != (u32)FXMAC_DMA_SG_IS_STOPED)
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- /* Verify internal pointers point to correct memory space */
- addr_v = (uintptr)ring_ptr->free_head;
- if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- addr_v = (uintptr)ring_ptr->pre_head;
- if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- addr_v = (uintptr)ring_ptr->hw_head;
- if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- addr_v = (uintptr)ring_ptr->hw_tail;
- if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- addr_v = (uintptr)ring_ptr->post_head;
- if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- /* Verify internal counters add up */
- if ((ring_ptr->hw_cnt + ring_ptr->pre_cnt + ring_ptr->free_cnt +
- ring_ptr->post_cnt) != ring_ptr->all_cnt)
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- /* Verify BDs are linked correctly */
- addr_v = ring_ptr->base_bd_addr;
- addr_p = ring_ptr->phys_base_addr + ring_ptr->separation;
- for (i = 1U; i < ring_ptr->all_cnt; i++)
- {
- /* Check BDA for this BD. It should point to next physical addr */
- if (FXMAC_BD_READ(addr_v, FXMAC_BD_ADDR_OFFSET) != addr_p)
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- /* Move on to next BD */
- addr_v += ring_ptr->separation;
- addr_p += ring_ptr->separation;
- }
- /* Last BD should have wrap bit set */
- if (FXMAC_SEND == direction)
- {
- if ((!FXMAC_BD_IS_TX_WRAP(addr_v)) == TRUE)
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- }
- else
- {
- /* FXMAC_RECV */
- if ((!FXMAC_BD_IS_RX_WRAP(addr_v)) == TRUE)
- {
- return (FError)(FXMAC_ERR_SG_LIST);
- }
- }
- /* No problems found */
- return (FError)(FT_SUCCESS);
- }
- /**
- * @name: FXmacBdSetRxWrap
- * @msg: Set this bit to mark the last descriptor in the receive buffer descriptor
- * list.
- * @param {uintptr} bdptr is the BD pointer to operate on
- */
- static void FXmacBdSetRxWrap(uintptr bdptr)
- {
- u32 data_value_rx;
- u32 *temp_ptr;
- bdptr += (u32)(FXMAC_BD_ADDR_OFFSET);
- temp_ptr = (u32 *)bdptr;
- if (temp_ptr != NULL)
- {
- data_value_rx = *temp_ptr;
- data_value_rx |= FXMAC_RXBUF_WRAP_MASK;
- *temp_ptr = data_value_rx;
- }
- }
- /**
- * @name: FXmacBdSetTxWrap
- * @msg: Sets this bit to mark the last descriptor in the transmit buffer
- * descriptor list.
- * @param {uintptr} bdptr is the BD pointer to operate on
- */
- static void FXmacBdSetTxWrap(uintptr bdptr)
- {
- u32 data_value_tx;
- u32 *temp_ptr;
- bdptr += (u32)(FXMAC_BD_STAT_OFFSET);
- temp_ptr = (u32 *)bdptr;
- if (temp_ptr != NULL)
- {
- data_value_tx = *temp_ptr;
- data_value_tx |= FXMAC_TXBUF_WRAP_MASK;
- *temp_ptr = data_value_tx;
- }
- }
- /**
- * @name: FXmacBdringPtrReset
- * @msg: Reset BD ring head and tail pointers.
- * @return {*}
- * @param {FXmacBdRing} *ring_ptr is the instance to be worked on.
- * @param {void} *virtaddrloc is the virtual base address of the user memory region.
- */
- void FXmacBdringPtrReset(FXmacBdRing *ring_ptr, void *virtaddrloc)
- {
- ring_ptr->free_head = virtaddrloc;
- ring_ptr->pre_head = virtaddrloc;
- ring_ptr->hw_head = virtaddrloc;
- ring_ptr->hw_tail = virtaddrloc;
- ring_ptr->post_head = virtaddrloc;
- }
|