fxmac_bdring.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. /*
  2. * Copyright : (C) 2022 Phytium Information Technology, Inc.
  3. * All Rights Reserved.
  4. *
  5. * This program is OPEN SOURCE software: you can redistribute it and/or modify it
  6. * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
  7. * either version 1.0 of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
  10. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * See the Phytium Public License for more details.
  12. *
  13. *
  14. * FilePath: fxmac_bdring.c
  15. * Date: 2022-04-06 14:46:52
  16. * LastEditTime: 2022-04-06 14:46:58
  17. * Description:  This file is for
  18. *
  19. * Modify History:
  20. * Ver   Who        Date         Changes
  21. * ----- ------     --------    --------------------------------------
  22. */
  23. #include "fxmac_hw.h"
  24. #include "fxmac.h"
  25. #include "fxmac_bdring.h"
  26. #include "fxmac_bd.h"
  27. #include "ftypes.h"
  28. #include "fxmac.h"
  29. #include "string.h"
  30. #include "fprintk.h"
  31. #include "fdebug.h"
  32. static void FXmacBdSetRxWrap(uintptr bdptr);
  33. static void FXmacBdSetTxWrap(uintptr bdptr);
  34. /************************** Variable Definitions *****************************/
  35. /***************** Macros (Inline Functions) Definitions *********************/
  36. /**
  37. * @name: FXMAC_RING_SEEKAHEAD
  38. * @msg: Move the bdptr argument ahead an arbitrary number of BDs wrapping around
  39. * to the beginning of the ring if needed.
  40. * @param ring_ptr is the ring bdptr appears in
  41. * @param bdptr on input is the starting BD position and on output is the final BD position
  42. * @param num_bd is the number of BD spaces to increment
  43. */
  44. #define FXMAC_RING_SEEKAHEAD(ring_ptr, bdptr, num_bd) \
  45. { \
  46. uintptr addr = (uintptr)(void *)(bdptr); \
  47. \
  48. addr += ((ring_ptr)->separation * (num_bd)); \
  49. if ((addr > (ring_ptr)->high_bd_addr) || ((uintptr)(void *)(bdptr) > addr)) \
  50. { \
  51. addr -= (ring_ptr)->length; \
  52. } \
  53. \
  54. (bdptr) = (FXmacBd *)(void *)addr; \
  55. }
  56. /**
  57. * @name: FXMAC_RING_SEEKBACK
  58. * @msg: Move the bdptr argument backwards an arbitrary number of BDs wrapping
  59. * around to the end of the ring if needed.
  60. * @param ring_ptr is the ring bdptr appears in
  61. * @param bdptr on input is the starting BD position and on output is the
  62. * final BD position
  63. * @param num_bd is the number of BD spaces to increment
  64. * @return {*}
  65. */
  66. #define FXMAC_RING_SEEKBACK(ring_ptr, bdptr, num_bd) \
  67. { \
  68. uintptr addr = (uintptr)(void *)(bdptr); \
  69. \
  70. addr -= ((ring_ptr)->separation * (num_bd)); \
  71. if ((addr < (ring_ptr)->base_bd_addr) || ((uintptr)(void *)(bdptr) < addr)) \
  72. { \
  73. addr += (ring_ptr)->length; \
  74. } \
  75. \
  76. (bdptr) = (FXmacBd *)(void *)addr; \
  77. }
  78. /**
  79. * @name: FXmacBdRingCreate
  80. * @msg: Using a memory segment allocated by the caller, create and setup the BD list
  81. * for the given DMA channel.
  82. * @param ring_ptr is the instance to be worked on.
  83. * @param Physaddr is the physical base address of user memory region.
  84. * @param Virtaddr is the virtual base address of the user memory region. If
  85. * address translation is not being utilized, then Virtaddr should be
  86. * equivalent to Physaddr.
  87. * @param Alignment governs the byte alignment of individual BDs. This function
  88. * will enforce a minimum alignment of 4 bytes with no maximum as long
  89. * as it is specified as a power of 2.
  90. * @param bd_count is the number of BDs to setup in the user memory region. It
  91. * is assumed the region is large enough to contain the BDs.
  92. * @return
  93. * FT_SUCCESS if initialization was successful
  94. * FXMAC_ERR_INVALID_PARAM under any of the following conditions:
  95. * 1) Physaddr and/or Virtaddr are not aligned to the given Alignment
  96. * parameter.
  97. * 2) Alignment parameter does not meet minimum requirements or is not a
  98. * power of 2 value.
  99. * 3) bd_count is 0.
  100. */
  101. FError FXmacBdRingCreate(FXmacBdRing *ring_ptr, uintptr phys_addr,
  102. uintptr virt_addr, u32 alignment, u32 bd_count)
  103. {
  104. u32 i;
  105. uintptr bd_virt_addr;
  106. uintptr bd_phy_addr;
  107. uintptr virt_addr_loc = virt_addr;
  108. /* In case there is a failure prior to creating list, make sure the
  109. * following attributes are 0 to prevent calls to other functions
  110. * from doing anything.
  111. */
  112. ring_ptr->all_cnt = 0U;
  113. ring_ptr->free_cnt = 0U;
  114. ring_ptr->hw_cnt = 0U;
  115. ring_ptr->pre_cnt = 0U;
  116. ring_ptr->post_cnt = 0U;
  117. /* Make sure alignment parameter meets minimum requirements */
  118. if (alignment < (u32)FXMAC_DMABD_MINIMUM_ALIGNMENT)
  119. {
  120. return (FError)(FXMAC_ERR_INVALID_PARAM);
  121. }
  122. /* Make sure alignment is a power of 2 */
  123. if (((alignment - 0x00000001U) & alignment) != 0x00000000U)
  124. {
  125. return (FError)(FXMAC_ERR_INVALID_PARAM);
  126. }
  127. /* Make sure phys_addr and virt_addr are on same alignment */
  128. if (((phys_addr % alignment) != (u32)0) || ((virt_addr_loc % alignment) != (u32)0))
  129. {
  130. return (FError)(FXMAC_ERR_INVALID_PARAM);
  131. }
  132. /* Is bd_count reasonable? */
  133. if (bd_count == 0x00000000U)
  134. {
  135. return (FError)(FXMAC_ERR_INVALID_PARAM);
  136. }
  137. /* Figure out how many bytes will be between the start of adjacent BDs */
  138. ring_ptr->separation = ((u32)sizeof(FXmacBd));
  139. /* Must make sure the ring doesn't span address 0x00000000. If it does,
  140. * then the next/prev BD traversal macros will fail.
  141. */
  142. if (virt_addr_loc > ((virt_addr_loc + (ring_ptr->separation * bd_count)) - (u32)1))
  143. {
  144. return (FError)(FXMAC_ERR_SG_LIST);
  145. }
  146. /* Initial ring setup:
  147. * - Clear the entire space
  148. * - Setup each BD's BDA field with the physical address of the next BD
  149. */
  150. (void)memset((void *)virt_addr_loc, 0, (ring_ptr->separation * bd_count));
  151. bd_virt_addr = virt_addr_loc;
  152. bd_phy_addr = phys_addr + ring_ptr->separation;
  153. for (i = 1U; i < bd_count; i++)
  154. {
  155. bd_virt_addr += ring_ptr->separation;
  156. bd_phy_addr += ring_ptr->separation;
  157. }
  158. /* Setup and initialize pointers and counters */
  159. ring_ptr->run_state = (u32)(FXMAC_DMA_SG_IS_STOPED);
  160. ring_ptr->base_bd_addr = virt_addr_loc;
  161. ring_ptr->phys_base_addr = phys_addr;
  162. ring_ptr->high_bd_addr = bd_virt_addr;
  163. ring_ptr->length =
  164. ((ring_ptr->high_bd_addr - ring_ptr->base_bd_addr) + ring_ptr->separation);
  165. ring_ptr->all_cnt = (u32)bd_count;
  166. ring_ptr->free_cnt = (u32)bd_count;
  167. ring_ptr->free_head = (FXmacBd *)(void *)virt_addr_loc;
  168. ring_ptr->pre_head = (FXmacBd *)virt_addr_loc;
  169. ring_ptr->hw_head = (FXmacBd *)virt_addr_loc;
  170. ring_ptr->hw_tail = (FXmacBd *)virt_addr_loc;
  171. ring_ptr->post_head = (FXmacBd *)virt_addr_loc;
  172. ring_ptr->bda_restart = (FXmacBd *)(void *)phys_addr;
  173. return (FError)(FT_SUCCESS);
  174. }
  175. /**
  176. * @name: FXmacBdRingClone
  177. * @msg: Clone the given BD into every BD in the list.
  178. * every field of the source BD is replicated in every BD of the list.
  179. * @param ring_ptr is the instance to be worked on.
  180. * @param src_bd_ptr is the source BD template to be cloned into the list. This
  181. * BD will be modified.
  182. * @param direction is either FXMAC_SEND or FXMAC_RECV that indicates
  183. * which direction.
  184. * @return {*}
  185. */
  186. FError FXmacBdRingClone(FXmacBdRing *ring_ptr, FXmacBd *src_bd_ptr,
  187. u8 direction)
  188. {
  189. u32 i;
  190. uintptr cur_bd;
  191. /* Can't do this function if there isn't a ring */
  192. if (ring_ptr->all_cnt == 0x00000000U)
  193. {
  194. return (FError)(FXMAC_ERR_SG_NO_LIST);
  195. }
  196. /* Can't do this function with the channel running */
  197. if (ring_ptr->run_state == (u32)FXMAC_DMA_SG_IS_STARTED)
  198. {
  199. return (FError)(FT_COMPONENT_IS_STARTED);
  200. }
  201. /* Can't do this function with some of the BDs in use */
  202. if (ring_ptr->free_cnt != ring_ptr->all_cnt)
  203. {
  204. return (FError)(FXMAC_ERR_SG_LIST);
  205. }
  206. if ((direction != (u8)FXMAC_SEND) && (direction != (u8)FXMAC_RECV))
  207. {
  208. return (FError)(FXMAC_ERR_INVALID_PARAM);
  209. }
  210. /* Starting from the top of the ring, save bd.next, overwrite the entire
  211. * BD with the template, then restore bd.next
  212. */
  213. cur_bd = ring_ptr->base_bd_addr;
  214. for (i = 0U; i < ring_ptr->all_cnt; i++)
  215. {
  216. memcpy((void *)cur_bd, src_bd_ptr, sizeof(FXmacBd));
  217. cur_bd += ring_ptr->separation;
  218. }
  219. cur_bd -= ring_ptr->separation;
  220. if (direction == FXMAC_RECV)
  221. {
  222. FXmacBdSetRxWrap(cur_bd);
  223. }
  224. else
  225. {
  226. FXmacBdSetTxWrap(cur_bd);
  227. }
  228. return (FError)(FT_SUCCESS);
  229. }
  230. /**
  231. * @name: FXmacBdRingAlloc
  232. * @msg: Reserve locations in the BD list. The set of returned BDs may be modified
  233. * in preparation for future DMA transaction(s). Once the BDs are ready to be
  234. * submitted to hardware, the user must call FXmacBdRingToHw() in the same
  235. * order which they were allocated here.
  236. * @param ring_ptr is a pointer to the BD ring instance to be worked on.
  237. * @param num_bd is the number of BDs to allocate
  238. * @param bd_set_ptr is an output parameter, it points to the first BD available
  239. * for modification.
  240. * @return FT_SUCCESS if the requested number of BDs was returned in the bd_set_ptr
  241. * parameter.
  242. * - FXMAC_ERR_GENERAL if there were not enough free BDs to satisfy the request.
  243. */
  244. FError FXmacBdRingAlloc(FXmacBdRing *ring_ptr, u32 num_bd,
  245. FXmacBd **bd_set_ptr)
  246. {
  247. FError status;
  248. /* Enough free BDs available for the request? */
  249. if (ring_ptr->free_cnt < num_bd)
  250. {
  251. status = (FError)(FXMAC_ERR_GENERAL);
  252. }
  253. else
  254. {
  255. /* Set the return argument and move free_head forward */
  256. *bd_set_ptr = ring_ptr->free_head;
  257. FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->free_head, num_bd);
  258. ring_ptr->free_cnt -= num_bd;
  259. ring_ptr->pre_cnt += num_bd;
  260. status = (FError)(FT_SUCCESS);
  261. }
  262. return status;
  263. }
  264. /**
  265. * @name: FXmacBdRingUnAlloc
  266. * @msg: * Fully or partially undo an FXmacBdRingAlloc() operation. Use this
  267. * function if all the BDs allocated by FXmacBdRingAlloc() could not be
  268. * transferred to hardware with FXmacBdRingToHw().
  269. *
  270. * This function helps out in situations when an unrelated error occurs after
  271. * BDs have been allocated but before they have been given to hardware.
  272. * An example of this type of error would be an OS running out of resources.
  273. *
  274. * This function is not the same as FXmacBdRingFree(). The Free function
  275. * returns BDs to the free list after they have been processed by hardware,
  276. * while UnAlloc returns them before being processed by hardware.
  277. *
  278. * There are two scenarios where this function can be used. Full UnAlloc or
  279. * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned:
  280. *
  281. * <pre>
  282. * status = FXmacBdRingAlloc(Myring_ptr, 10, &bdptr),
  283. * ...
  284. * if (Error)
  285. * {
  286. * status = FXmacBdRingUnAlloc(Myring_ptr, 10, &bdptr),
  287. * }
  288. * </pre>
  289. *
  290. * A partial UnAlloc means some of the BDs Alloc'd will be returned:
  291. *
  292. * <pre>
  293. * status = FXmacBdRingAlloc(Myring_ptr, 10, &bdptr),
  294. * BdsLeft = 10,
  295. * cur_bd_ptr = bdptr,
  296. *
  297. * while (BdsLeft)
  298. * {
  299. * if (Error)
  300. * {
  301. * status = FXmacBdRingUnAlloc(Myring_ptr, BdsLeft, cur_bd_ptr),
  302. * }
  303. *
  304. * cur_bd_ptr = FXMAC_BD_RING_NEXT(Myring_ptr, cur_bd_ptr),
  305. * BdsLeft--,
  306. * }
  307. * </pre>
  308. *
  309. * A partial UnAlloc must include the last BD in the list that was Alloc'd.
  310. *
  311. * @param ring_ptr is a pointer to the instance to be worked on.
  312. * @param num_bd is the number of BDs to allocate
  313. * @param bd_set_ptr is an output parameter, it points to the first BD available
  314. * for modification.
  315. *
  316. * @return
  317. * - FT_SUCCESS if the BDs were unallocated.
  318. * - FXMAC_ERR_GENERAL if num_bd parameter was greater that the number of BDs in
  319. * the preprocessing state.
  320. *
  321. * @return {*}
  322. */
  323. FError FXmacBdRingUnAlloc(FXmacBdRing *ring_ptr, u32 num_bd,
  324. FXmacBd *bd_set_ptr)
  325. {
  326. FError status;
  327. (void)bd_set_ptr;
  328. FASSERT(ring_ptr != NULL);
  329. FASSERT(bd_set_ptr != NULL);
  330. /* Enough BDs in the free state for the request? */
  331. if (ring_ptr->pre_cnt < num_bd)
  332. {
  333. status = (FError)(FXMAC_ERR_GENERAL);
  334. }
  335. else
  336. {
  337. /* Set the return argument and move free_head backward */
  338. FXMAC_RING_SEEKBACK(ring_ptr, (ring_ptr->free_head), num_bd);
  339. ring_ptr->free_cnt += num_bd;
  340. ring_ptr->pre_cnt -= num_bd;
  341. status = (FError)(FT_SUCCESS);
  342. }
  343. return status;
  344. }
  345. /**
  346. * @name: FXmacBdRingToHw
  347. * @msg: Enqueue a set of BDs to hardware that were previously allocated by
  348. * FXmacBdRingAlloc(). Once this function returns, the argument BD set goes
  349. * under hardware control. Any changes made to these BDs after this point will
  350. * corrupt the BD list leading to data corruption and system instability.
  351. *
  352. * @param ring_ptr is a pointer to the instance to be worked on.
  353. * @param num_bd is the number of BDs in the set.
  354. * @param bd_set_ptr is the first BD of the set to commit to hardware.
  355. * @return FT_SUCCESS if the set of BDs was accepted and enqueued to hardware.
  356. * XST_FAILURE if the set of BDs was rejected because the last BD of the set
  357. * did not have its "last" bit set.
  358. * FXMAC_ERR_SG_LIST if this function was called out of sequence with
  359. * FXmacBdRingAlloc().
  360. */
  361. FError FXmacBdRingToHw(FXmacBdRing *ring_ptr, u32 num_bd,
  362. FXmacBd *bd_set_ptr)
  363. {
  364. FXmacBd *cur_bd_ptr;
  365. u32 i;
  366. FError status;
  367. /* if no bds to process, simply return. */
  368. if (0U == num_bd)
  369. {
  370. status = (FError)(FT_SUCCESS);
  371. }
  372. else
  373. {
  374. /* Make sure we are in sync with FXmacBdRingAlloc() */
  375. if ((ring_ptr->pre_cnt < num_bd) || (ring_ptr->pre_head != bd_set_ptr))
  376. {
  377. status = (FError)(FXMAC_ERR_SG_LIST);
  378. }
  379. else
  380. {
  381. cur_bd_ptr = bd_set_ptr;
  382. for (i = 0U; i < num_bd; i++)
  383. {
  384. cur_bd_ptr = (FXmacBd *)((void *)FXMAC_BD_RING_NEXT(ring_ptr, cur_bd_ptr));
  385. }
  386. /* Adjust ring pointers & counters */
  387. FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->pre_head, num_bd);
  388. ring_ptr->pre_cnt -= num_bd;
  389. ring_ptr->hw_tail = cur_bd_ptr;
  390. ring_ptr->hw_cnt += num_bd;
  391. status = (FError)(FT_SUCCESS);
  392. }
  393. }
  394. return status;
  395. }
  396. /**
  397. * @name: FXmacBdRingFromHwTx
  398. * @msg: Returns a set of BD(s) that have been processed by hardware. The returned
  399. * BDs may be examined to determine the outcome of the DMA transaction(s).
  400. * Once the BDs have been examined, the user must call FXmacBdRingFree()
  401. * in the same order which they were retrieved here. Example:
  402. *
  403. * <pre>
  404. * num_bd = FXmacBdRingFromHwTx(Myring_ptr, MaxBd, &MyBdSet),
  405. * if (num_bd == 0)
  406. * {
  407. * * hardware has nothing ready for us yet*
  408. * }
  409. *
  410. * cur_bd = MyBdSet,
  411. * for (i=0; i<num_bd; i++)
  412. * {
  413. * * Examine cur_bd for post processing *.....
  414. *
  415. * * Onto next BD *
  416. * cur_bd = FXMAC_BD_RING_NEXT(Myring_ptr, cur_bd),
  417. * }
  418. *
  419. * FXmacBdRingFree(Myring_ptr, num_bd, MyBdSet), *Return list*
  420. * }
  421. * </pre>
  422. *
  423. * A more advanced use of this function may allocate multiple sets of BDs.
  424. * They must be retrieved from hardware and freed in the correct sequence:
  425. * <pre>
  426. * * Legal *
  427. * FXmacBdRingFromHwTx(Myring_ptr, num_bd1, &MySet1),
  428. * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
  429. *
  430. * * Legal *
  431. * FXmacBdRingFromHwTx(Myring_ptr, num_bd1, &MySet1),
  432. * FXmacBdRingFromHwTx(Myring_ptr, num_bd2, &MySet2),
  433. * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
  434. * FXmacBdRingFree(Myring_ptr, num_bd2, MySet2),
  435. *
  436. * * Not legal *
  437. * FXmacBdRingFromHwTx(Myring_ptr, num_bd1, &MySet1),
  438. * FXmacBdRingFromHwTx(Myring_ptr, num_bd2, &MySet2),
  439. * FXmacBdRingFree(Myring_ptr, num_bd2, MySet2),
  440. * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
  441. * </pre>
  442. *
  443. * If hardware has only partially completed a packet spanning multiple BDs,
  444. * then none of the BDs for that packet will be included in the results.
  445. *
  446. * @param ring_ptr is a pointer to the instance to be worked on.
  447. * @param bd_limit is the maximum number of BDs to return in the set.
  448. * @param bd_set_ptr is an output parameter, it points to the first BD available
  449. * for examination.
  450. *
  451. * @return
  452. * The number of BDs processed by hardware. A value of 0 indicates that no
  453. * data is available. No more than bd_limit BDs will be returned.
  454. *
  455. * @return
  456. * The number of BDs processed by hardware. A value of 0 indicates that no
  457. * data is available. No more than bd_limit BDs will be returned.
  458. */
  459. u32 FXmacBdRingFromHwTx(FXmacBdRing *ring_ptr, u32 bd_limit,
  460. FXmacBd **bd_set_ptr)
  461. {
  462. FXmacBd *cur_bd_ptr;
  463. u32 bd_str = 0U;
  464. u32 bd_count;
  465. u32 bd_partial_count;
  466. u32 Sop = 0U;
  467. u32 status;
  468. u32 bd_limitLoc = bd_limit;
  469. cur_bd_ptr = ring_ptr->hw_head;
  470. bd_count = 0U;
  471. bd_partial_count = 0U;
  472. /* If no BDs in work group, then there's nothing to search */
  473. if (ring_ptr->hw_cnt == 0x00000000U)
  474. {
  475. *bd_set_ptr = NULL;
  476. status = 0U;
  477. }
  478. else
  479. {
  480. if (bd_limitLoc > ring_ptr->hw_cnt)
  481. {
  482. bd_limitLoc = ring_ptr->hw_cnt;
  483. }
  484. /* Starting at hw_head, keep moving forward in the list until:
  485. * - A BD is encountered with its new/used bit set which means
  486. * hardware has not completed processing of that BD.
  487. * - ring_ptr->hw_tail is reached and ring_ptr->hw_cnt is reached.
  488. * - The number of requested BDs has been processed
  489. */
  490. while (bd_count < bd_limitLoc)
  491. {
  492. /* Read the status */
  493. if (cur_bd_ptr != NULL)
  494. {
  495. bd_str = FXMAC_BD_READ(cur_bd_ptr, FXMAC_BD_STAT_OFFSET);
  496. }
  497. if ((Sop == 0x00000000U) && ((bd_str & FXMAC_TXBUF_USED_MASK) != 0x00000000U))
  498. {
  499. Sop = 1U;
  500. }
  501. if (Sop == 0x00000001U)
  502. {
  503. bd_count++;
  504. bd_partial_count++;
  505. }
  506. /* hardware has processed this BD so check the "last" bit.
  507. * If it is clear, then there are more BDs for the current
  508. * packet. Keep a count of these partial packet BDs.
  509. */
  510. if ((Sop == 0x00000001U) && ((bd_str & FXMAC_TXBUF_LAST_MASK) != 0x00000000U))
  511. {
  512. Sop = 0U;
  513. bd_partial_count = 0U;
  514. }
  515. /* Move on to next BD in work group */
  516. cur_bd_ptr = FXMAC_BD_RING_NEXT(ring_ptr, cur_bd_ptr);
  517. }
  518. /* Subtract off any partial packet BDs found */
  519. bd_count -= bd_partial_count;
  520. /* If bd_count is non-zero then BDs were found to return. Set return
  521. * parameters, update pointers and counters, return success
  522. */
  523. if (bd_count > 0x00000000U)
  524. {
  525. *bd_set_ptr = ring_ptr->hw_head;
  526. ring_ptr->hw_cnt -= bd_count;
  527. ring_ptr->post_cnt += bd_count;
  528. FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->hw_head, bd_count);
  529. status = (bd_count);
  530. }
  531. else
  532. {
  533. *bd_set_ptr = NULL;
  534. status = 0U;
  535. }
  536. }
  537. return status;
  538. }
  539. /**
  540. * @name: FXmacBdRingFromHwRx
  541. * @msg: Returns a set of BD(s) that have been processed by hardware. The returned
  542. * BDs may be examined to determine the outcome of the DMA transaction(s).
  543. * Once the BDs have been examined, the user must call FXmacBdRingFree()
  544. * in the same order which they were retrieved here. Example:
  545. *
  546. * <pre>
  547. * num_bd = FXmacBdRingFromHwRx(Myring_ptr, MaxBd, &MyBdSet),
  548. *
  549. * if (num_bd == 0)
  550. * {
  551. * *hardware has nothing ready for us yet*
  552. * }
  553. *
  554. * cur_bd = MyBdSet,
  555. * for (i=0; i<num_bd; i++)
  556. * {
  557. * * Examine cur_bd for post processing *.....
  558. *
  559. * * Onto next BD *
  560. * cur_bd = FXMAC_BD_RING_NEXT(Myring_ptr, cur_bd),
  561. * }
  562. *
  563. * FXmacBdRingFree(Myring_ptr, num_bd, MyBdSet), * Return list *
  564. * }
  565. * </pre>
  566. *
  567. * A more advanced use of this function may allocate multiple sets of BDs.
  568. * They must be retrieved from hardware and freed in the correct sequence:
  569. * <pre>
  570. * * Legal *
  571. * FXmacBdRingFromHwRx(Myring_ptr, num_bd1, &MySet1),
  572. * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
  573. *
  574. * * Legal *
  575. * FXmacBdRingFromHwRx(Myring_ptr, num_bd1, &MySet1),
  576. * FXmacBdRingFromHwRx(Myring_ptr, num_bd2, &MySet2),
  577. * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
  578. * FXmacBdRingFree(Myring_ptr, num_bd2, MySet2),
  579. *
  580. * * Not legal *
  581. * FXmacBdRingFromHwRx(Myring_ptr, num_bd1, &MySet1),
  582. * FXmacBdRingFromHwRx(Myring_ptr, num_bd2, &MySet2),
  583. * FXmacBdRingFree(Myring_ptr, num_bd2, MySet2),
  584. * FXmacBdRingFree(Myring_ptr, num_bd1, MySet1),
  585. * </pre>
  586. *
  587. * If hardware has only partially completed a packet spanning multiple BDs,
  588. * then none of the BDs for that packet will be included in the results.
  589. *
  590. * @param ring_ptr is a pointer to the instance to be worked on.
  591. * @param bd_limit is the maximum number of BDs to return in the set.
  592. * @param bd_set_ptr is an output parameter, it points to the first BD available
  593. * for examination.
  594. *
  595. * @return
  596. * The number of BDs processed by hardware. A value of 0 indicates that no
  597. * data is available. No more than bd_limit BDs will be returned.
  598. */
  599. u32 FXmacBdRingFromHwRx(FXmacBdRing *ring_ptr, u32 bd_limit,
  600. FXmacBd **bd_set_ptr)
  601. {
  602. FXmacBd *cur_bd_ptr;
  603. u32 bd_str = 0U;
  604. u32 bd_count;
  605. u32 bd_partial_count;
  606. u32 status;
  607. cur_bd_ptr = ring_ptr->hw_head;
  608. bd_count = 0U;
  609. bd_partial_count = 0U;
  610. /* If no BDs in work group, then there's nothing to search */
  611. if (ring_ptr->hw_cnt == 0x00000000U)
  612. {
  613. *bd_set_ptr = NULL;
  614. status = 0U;
  615. }
  616. else
  617. {
  618. /* Starting at hw_head, keep moving forward in the list until:
  619. * - A BD is encountered with its new/used bit set which means
  620. * hardware has completed processing of that BD.
  621. * - ring_ptr->hw_tail is reached and ring_ptr->hw_cnt is reached.
  622. * - The number of requested BDs has been processed
  623. */
  624. while (bd_count < bd_limit)
  625. {
  626. /* Read the status */
  627. if (cur_bd_ptr != NULL)
  628. {
  629. bd_str = FXMAC_BD_READ(cur_bd_ptr, FXMAC_BD_STAT_OFFSET);
  630. }
  631. if ((!(FXMAC_BD_IS_RX_NEW(cur_bd_ptr))) == TRUE)
  632. {
  633. break;
  634. }
  635. bd_count++;
  636. /* hardware has processed this BD so check the "last" bit. If
  637. * it is clear, then there are more BDs for the current packet.
  638. * Keep a count of these partial packet BDs.
  639. */
  640. if ((bd_str & FXMAC_RXBUF_EOF_MASK) != 0x00000000U)
  641. {
  642. bd_partial_count = 0U;
  643. }
  644. else
  645. {
  646. bd_partial_count++;
  647. }
  648. /* Move on to next BD in work group */
  649. cur_bd_ptr = FXMAC_BD_RING_NEXT(ring_ptr, cur_bd_ptr);
  650. // if((bd_str & FXMAC_RXBUF_EOF_MASK) != 0x00000000U)
  651. // {
  652. // if(bd_str &FXMAC_RXBUF_FCS_STATUS_MASK)
  653. // {
  654. // f_printk("********** error fcs data is appear ************* \r\n");
  655. // FtDumpHexWord(FXMAC_BD_READ(cur_bd_ptr,0) &(0xfffffff8),bd_str&FXMAC_RXBUF_LEN_MASK);
  656. // f_printk("********** end ************* \r\n");
  657. // }
  658. // }
  659. }
  660. /* Subtract off any partial packet BDs found */
  661. bd_count -= bd_partial_count;
  662. /* If bd_count is non-zero then BDs were found to return. Set return
  663. * parameters, update pointers and counters, return success
  664. */
  665. if (bd_count > 0x00000000U)
  666. {
  667. *bd_set_ptr = ring_ptr->hw_head;
  668. ring_ptr->hw_cnt -= bd_count;
  669. ring_ptr->post_cnt += bd_count;
  670. FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->hw_head, bd_count);
  671. status = (bd_count);
  672. }
  673. else
  674. {
  675. *bd_set_ptr = NULL;
  676. status = 0U;
  677. }
  678. }
  679. return status;
  680. }
  681. /**
  682. * @name: FXmacBdRingFree
  683. * @msg: Frees a set of BDs that had been previously retrieved with
  684. * FXmacBdRingFromHw().
  685. *
  686. * @param ring_ptr is a pointer to the instance to be worked on.
  687. * @param num_bd is the number of BDs to free.
  688. * @param bd_set_ptr is the head of a list of BDs returned by
  689. * FXmacBdRingFromHw().
  690. *
  691. * @return
  692. * FT_SUCCESS if the set of BDs was freed.
  693. * FXMAC_ERR_SG_LIST if this function was called out of sequence with
  694. * FXmacBdRingFromHw().
  695. */
  696. FError FXmacBdRingFree(FXmacBdRing *ring_ptr, u32 num_bd,
  697. FXmacBd *bd_set_ptr)
  698. {
  699. FError status;
  700. /* if no bds to process, simply return. */
  701. if (0x00000000U == num_bd)
  702. {
  703. status = (FError)(FT_SUCCESS);
  704. }
  705. else
  706. {
  707. /* Make sure we are in sync with FXmacBdRingFromHw() */
  708. if ((ring_ptr->post_cnt < num_bd) || (ring_ptr->post_head != bd_set_ptr))
  709. {
  710. status = (FError)(FXMAC_ERR_SG_LIST);
  711. }
  712. else
  713. {
  714. /* Update pointers and counters */
  715. ring_ptr->free_cnt += num_bd;
  716. ring_ptr->post_cnt -= num_bd;
  717. FXMAC_RING_SEEKAHEAD(ring_ptr, ring_ptr->post_head, num_bd);
  718. status = (FError)(FT_SUCCESS);
  719. }
  720. }
  721. return status;
  722. }
  723. /**
  724. * @name: FXmacBdRingCheck
  725. * @msg: Check the internal data structures of the BD ring for the provided channel.
  726. * The following checks are made:
  727. *
  728. * - Is the BD ring linked correctly in physical address space.
  729. * - Do the internal pointers point to BDs in the ring.
  730. * - Do the internal counters add up.
  731. *
  732. * The channel should be stopped prior to calling this function.
  733. *
  734. * @param {FXmacBdRing} ring_ptr is a pointer to the instance to be worked on.
  735. * @param {u8} direction is either FXMAC_SEND or FXMAC_RECV that indicates
  736. * which direction.
  737. * @return {*}
  738. * FT_SUCCESS if the set of BDs was freed.
  739. * XST_DMA_SG_NO_LIST if the list has not been created.
  740. * FT_COMPONENT_IS_STARTED if the channel is not stopped.
  741. * FXMAC_ERR_SG_LIST if a problem is found with the internal data
  742. * structures. If this value is returned, the channel should be reset to
  743. * avoid data corruption or system instability.
  744. */
  745. FError FXmacBdRingCheck(FXmacBdRing *ring_ptr, u8 direction)
  746. {
  747. uintptr addr_v, addr_p;
  748. u32 i;
  749. if ((direction != (u8)FXMAC_SEND) && (direction != (u8)FXMAC_RECV))
  750. {
  751. return (FError)(FXMAC_ERR_INVALID_PARAM);
  752. }
  753. /* Is the list created */
  754. if (ring_ptr->all_cnt == 0x00000000U)
  755. {
  756. return (FError)(FXMAC_ERR_SG_NO_LIST);
  757. }
  758. /* Can't check if channel is running */
  759. if (ring_ptr->run_state == (u32)FXMAC_DMA_SG_IS_STARTED)
  760. {
  761. return (FError)(FT_COMPONENT_IS_STARTED);
  762. }
  763. /* run_state doesn't make sense */
  764. if (ring_ptr->run_state != (u32)FXMAC_DMA_SG_IS_STOPED)
  765. {
  766. return (FError)(FXMAC_ERR_SG_LIST);
  767. }
  768. /* Verify internal pointers point to correct memory space */
  769. addr_v = (uintptr)ring_ptr->free_head;
  770. if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
  771. {
  772. return (FError)(FXMAC_ERR_SG_LIST);
  773. }
  774. addr_v = (uintptr)ring_ptr->pre_head;
  775. if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
  776. {
  777. return (FError)(FXMAC_ERR_SG_LIST);
  778. }
  779. addr_v = (uintptr)ring_ptr->hw_head;
  780. if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
  781. {
  782. return (FError)(FXMAC_ERR_SG_LIST);
  783. }
  784. addr_v = (uintptr)ring_ptr->hw_tail;
  785. if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
  786. {
  787. return (FError)(FXMAC_ERR_SG_LIST);
  788. }
  789. addr_v = (uintptr)ring_ptr->post_head;
  790. if ((addr_v < ring_ptr->base_bd_addr) || (addr_v > ring_ptr->high_bd_addr))
  791. {
  792. return (FError)(FXMAC_ERR_SG_LIST);
  793. }
  794. /* Verify internal counters add up */
  795. if ((ring_ptr->hw_cnt + ring_ptr->pre_cnt + ring_ptr->free_cnt +
  796. ring_ptr->post_cnt) != ring_ptr->all_cnt)
  797. {
  798. return (FError)(FXMAC_ERR_SG_LIST);
  799. }
  800. /* Verify BDs are linked correctly */
  801. addr_v = ring_ptr->base_bd_addr;
  802. addr_p = ring_ptr->phys_base_addr + ring_ptr->separation;
  803. for (i = 1U; i < ring_ptr->all_cnt; i++)
  804. {
  805. /* Check BDA for this BD. It should point to next physical addr */
  806. if (FXMAC_BD_READ(addr_v, FXMAC_BD_ADDR_OFFSET) != addr_p)
  807. {
  808. return (FError)(FXMAC_ERR_SG_LIST);
  809. }
  810. /* Move on to next BD */
  811. addr_v += ring_ptr->separation;
  812. addr_p += ring_ptr->separation;
  813. }
  814. /* Last BD should have wrap bit set */
  815. if (FXMAC_SEND == direction)
  816. {
  817. if ((!FXMAC_BD_IS_TX_WRAP(addr_v)) == TRUE)
  818. {
  819. return (FError)(FXMAC_ERR_SG_LIST);
  820. }
  821. }
  822. else
  823. {
  824. /* FXMAC_RECV */
  825. if ((!FXMAC_BD_IS_RX_WRAP(addr_v)) == TRUE)
  826. {
  827. return (FError)(FXMAC_ERR_SG_LIST);
  828. }
  829. }
  830. /* No problems found */
  831. return (FError)(FT_SUCCESS);
  832. }
  833. /**
  834. * @name: FXmacBdSetRxWrap
  835. * @msg: Set this bit to mark the last descriptor in the receive buffer descriptor
  836. * list.
  837. * @param {uintptr} bdptr is the BD pointer to operate on
  838. */
  839. static void FXmacBdSetRxWrap(uintptr bdptr)
  840. {
  841. u32 data_value_rx;
  842. u32 *temp_ptr;
  843. bdptr += (u32)(FXMAC_BD_ADDR_OFFSET);
  844. temp_ptr = (u32 *)bdptr;
  845. if (temp_ptr != NULL)
  846. {
  847. data_value_rx = *temp_ptr;
  848. data_value_rx |= FXMAC_RXBUF_WRAP_MASK;
  849. *temp_ptr = data_value_rx;
  850. }
  851. }
  852. /**
  853. * @name: FXmacBdSetTxWrap
  854. * @msg: Sets this bit to mark the last descriptor in the transmit buffer
  855. * descriptor list.
  856. * @param {uintptr} bdptr is the BD pointer to operate on
  857. */
  858. static void FXmacBdSetTxWrap(uintptr bdptr)
  859. {
  860. u32 data_value_tx;
  861. u32 *temp_ptr;
  862. bdptr += (u32)(FXMAC_BD_STAT_OFFSET);
  863. temp_ptr = (u32 *)bdptr;
  864. if (temp_ptr != NULL)
  865. {
  866. data_value_tx = *temp_ptr;
  867. data_value_tx |= FXMAC_TXBUF_WRAP_MASK;
  868. *temp_ptr = data_value_tx;
  869. }
  870. }
  871. /**
  872. * @name: FXmacBdringPtrReset
  873. * @msg: Reset BD ring head and tail pointers.
  874. * @return {*}
  875. * @param {FXmacBdRing} *ring_ptr is the instance to be worked on.
  876. * @param {void} *virtaddrloc is the virtual base address of the user memory region.
  877. */
  878. void FXmacBdringPtrReset(FXmacBdRing *ring_ptr, void *virtaddrloc)
  879. {
  880. ring_ptr->free_head = virtaddrloc;
  881. ring_ptr->pre_head = virtaddrloc;
  882. ring_ptr->hw_head = virtaddrloc;
  883. ring_ptr->hw_tail = virtaddrloc;
  884. ring_ptr->post_head = virtaddrloc;
  885. }