xemac_intr_dma.c 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344
  1. /******************************************************************************
  2. *
  3. * Author: Xilinx, Inc.
  4. *
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or (at your
  9. * option) any later version.
  10. *
  11. *
  12. * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
  13. * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
  14. * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD,
  15. * XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
  16. * FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING
  17. * ANY THIRD PARTY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
  18. * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
  19. * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY
  20. * WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM
  21. * CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND
  22. * FITNESS FOR A PARTICULAR PURPOSE.
  23. *
  24. *
  25. * Xilinx hardware products are not intended for use in life support
  26. * appliances, devices, or systems. Use in such applications is
  27. * expressly prohibited.
  28. *
  29. *
  30. * (c) Copyright 2002-2004 Xilinx Inc.
  31. * All rights reserved.
  32. *
  33. *
  34. * You should have received a copy of the GNU General Public License along
  35. * with this program; if not, write to the Free Software Foundation, Inc.,
  36. * 675 Mass Ave, Cambridge, MA 02139, USA.
  37. *
  38. ******************************************************************************/
  39. /*****************************************************************************/
  40. /**
  41. *
  42. * @file xemac_intr_dma.c
  43. *
  44. * Contains functions used in interrupt mode when configured with scatter-gather
  45. * DMA.
  46. *
  47. * The interrupt handler, XEmac_IntrHandlerDma(), must be connected by the user
  48. * to the interrupt controller.
  49. *
  50. * <pre>
  51. * MODIFICATION HISTORY:
  52. *
  53. * Ver Who Date Changes
  54. * ----- ---- -------- ---------------------------------------------------------
  55. * 1.00a rpm 07/31/01 First release
  56. * 1.00b rpm 02/20/02 Repartitioned files and functions
  57. * 1.00c rpm 12/05/02 New version includes support for simple DMA and the delay
  58. * argument to SgSend
  59. * 1.00c rpm 02/03/03 The XST_DMA_SG_COUNT_EXCEEDED return code was removed
  60. * from SetPktThreshold in the internal DMA driver. Also
  61. * avoided compiler warnings by initializing Result in the
  62. * interrupt service routines.
  63. * 1.00c rpm 03/26/03 Fixed a problem in the interrupt service routines where
  64. * the interrupt status was toggled clear after a call to
  65. * ErrorHandler, but if ErrorHandler reset the device the
  66. * toggle actually asserted the interrupt because the
  67. * reset had cleared it.
  68. * </pre>
  69. *
  70. ******************************************************************************/
  71. /***************************** Include Files *********************************/
  72. #include "xbasic_types.h"
  73. #include "xemac_i.h"
  74. #include "xio.h"
  75. #include "xbuf_descriptor.h"
  76. #include "xdma_channel.h"
  77. #include "xipif_v1_23_b.h" /* Uses v1.23b of the IPIF */
  78. /************************** Constant Definitions *****************************/
  79. /**************************** Type Definitions *******************************/
  80. /***************** Macros (Inline Functions) Definitions *********************/
  81. /************************** Variable Definitions *****************************/
  82. /************************** Function Prototypes ******************************/
  83. static void HandleDmaRecvIntr(XEmac * InstancePtr);
  84. static void HandleDmaSendIntr(XEmac * InstancePtr);
  85. static void HandleEmacDmaIntr(XEmac * InstancePtr);
  86. /*****************************************************************************/
  87. /**
  88. *
  89. * Send an Ethernet frame using scatter-gather DMA. The caller attaches the
  90. * frame to one or more buffer descriptors, then calls this function once for
  91. * each descriptor. The caller is responsible for allocating and setting up the
  92. * descriptor. An entire Ethernet frame may or may not be contained within one
  93. * descriptor. This function simply inserts the descriptor into the scatter-
  94. * gather engine's transmit list. The caller is responsible for providing mutual
  95. * exclusion to guarantee that a frame is contiguous in the transmit list. The
  96. * buffer attached to the descriptor must be word-aligned.
  97. *
  98. * The driver updates the descriptor with the device control register before
  99. * being inserted into the transmit list. If this is the last descriptor in
  100. * the frame, the inserts are committed, which means the descriptors for this
  101. * frame are now available for transmission.
  102. *
  103. * It is assumed that the upper layer software supplies a correctly formatted
  104. * Ethernet frame, including the destination and source addresses, the
  105. * type/length field, and the data field. It is also assumed that upper layer
  106. * software does not append FCS at the end of the frame.
  107. *
  108. * The buffer attached to the descriptor must be word-aligned on the front end.
  109. *
  110. * This call is non-blocking. Notification of error or successful transmission
  111. * is done asynchronously through the send or error callback function.
  112. *
  113. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  114. * @param BdPtr is the address of a descriptor to be inserted into the transmit
  115. * ring.
  116. * @param Delay indicates whether to start the scatter-gather DMA channel
  117. * immediately, or whether to wait. This allows the user to build up a
  118. * list of more than one descriptor before starting the transmission of
  119. * the packets, which allows the application to keep up with DMA and have
  120. * a constant stream of frames being transmitted. Use XEM_SGDMA_NODELAY or
  121. * XEM_SGDMA_DELAY, defined in xemac.h, as the value of this argument. If
  122. * the user chooses to delay and build a list, the user must call this
  123. * function with the XEM_SGDMA_NODELAY option or call XEmac_Start() to
  124. * kick off the tranmissions.
  125. *
  126. * @return
  127. *
  128. * - XST_SUCCESS if the buffer was successfull sent
  129. * - XST_DEVICE_IS_STOPPED if the Ethernet MAC has not been started yet
  130. * - XST_NOT_SGDMA if the device is not in scatter-gather DMA mode
  131. * - XST_DMA_SG_LIST_FULL if the descriptor list for the DMA channel is full
  132. * - XST_DMA_SG_BD_LOCKED if the DMA channel cannot insert the descriptor into
  133. * the list because a locked descriptor exists at the insert point
  134. * - XST_DMA_SG_NOTHING_TO_COMMIT if even after inserting a descriptor into the
  135. * list, the DMA channel believes there are no new descriptors to commit. If
  136. * this is ever encountered, there is likely a thread mutual exclusion problem
  137. * on transmit.
  138. *
  139. * @note
  140. *
  141. * This function is not thread-safe. The user must provide mutually exclusive
  142. * access to this function if there are to be multiple threads that can call it.
  143. *
  144. * @internal
  145. *
  146. * A status that should never be returned from this function, although
  147. * the code is set up to handle it, is XST_DMA_SG_NO_LIST. Starting the device
  148. * requires a list to be created, and this function requires the device to be
  149. * started.
  150. *
  151. ******************************************************************************/
  152. XStatus
  153. XEmac_SgSend(XEmac * InstancePtr, XBufDescriptor * BdPtr, int Delay)
  154. {
  155. XStatus Result;
  156. u32 BdControl;
  157. XASSERT_NONVOID(InstancePtr != NULL);
  158. XASSERT_NONVOID(BdPtr != NULL);
  159. XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  160. /*
  161. * Be sure the device is configured for scatter-gather DMA, then be sure
  162. * it is started.
  163. */
  164. if (!XEmac_mIsSgDma(InstancePtr)) {
  165. return XST_NOT_SGDMA;
  166. }
  167. /*
  168. * Set some descriptor control word defaults (source address increment
  169. * and local destination address) and the destination address
  170. * (the FIFO). These are the same for every transmit descriptor.
  171. */
  172. BdControl = XBufDescriptor_GetControl(BdPtr);
  173. XBufDescriptor_SetControl(BdPtr, BdControl | XEM_DFT_SEND_BD_MASK);
  174. XBufDescriptor_SetDestAddress(BdPtr,
  175. InstancePtr->BaseAddress +
  176. XEM_PFIFO_TXDATA_OFFSET);
  177. /*
  178. * Put the descriptor in the send list. The DMA component accesses data
  179. * here that can also be modified in interrupt context, so a critical
  180. * section is required.
  181. */
  182. XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress);
  183. Result = XDmaChannel_PutDescriptor(&InstancePtr->SendChannel, BdPtr);
  184. if (Result != XST_SUCCESS) {
  185. XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
  186. return Result;
  187. }
  188. /*
  189. * If this is the last buffer in the frame, commit the inserts and start
  190. * the DMA engine if necessary
  191. */
  192. if (XBufDescriptor_IsLastControl(BdPtr)) {
  193. Result = XDmaChannel_CommitPuts(&InstancePtr->SendChannel);
  194. if (Result != XST_SUCCESS) {
  195. XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
  196. return Result;
  197. }
  198. if (Delay == XEM_SGDMA_NODELAY) {
  199. /*
  200. * Start the DMA channel. Ignore the return status since we know the
  201. * list exists and has at least one entry and we don't care if the
  202. * channel is already started. The DMA component accesses data here
  203. * that can be modified at interrupt or task levels, so a critical
  204. * section is required.
  205. */
  206. (void) XDmaChannel_SgStart(&InstancePtr->SendChannel);
  207. }
  208. }
  209. XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
  210. return XST_SUCCESS;
  211. }
  212. /*****************************************************************************/
  213. /**
  214. *
  215. * Add a descriptor, with an attached empty buffer, into the receive descriptor
  216. * list. The buffer attached to the descriptor must be word-aligned. This is
  217. * used by the upper layer software during initialization when first setting up
  218. * the receive descriptors, and also during reception of frames to replace
  219. * filled buffers with empty buffers. This function can be called when the
  220. * device is started or stopped. Note that it does start the scatter-gather DMA
  221. * engine. Although this is not necessary during initialization, it is not a
  222. * problem during initialization because the MAC receiver is not yet started.
  223. *
  224. * The buffer attached to the descriptor must be word-aligned on both the front
  225. * end and the back end.
  226. *
  227. * Notification of received frames are done asynchronously through the receive
  228. * callback function.
  229. *
  230. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  231. * @param BdPtr is a pointer to the buffer descriptor that will be added to the
  232. * descriptor list.
  233. *
  234. * @return
  235. *
  236. * - XST_SUCCESS if a descriptor was successfully returned to the driver
  237. * - XST_NOT_SGDMA if the device is not in scatter-gather DMA mode
  238. * - XST_DMA_SG_LIST_FULL if the receive descriptor list is full
  239. * - XST_DMA_SG_BD_LOCKED if the DMA channel cannot insert the descriptor into
  240. * the list because a locked descriptor exists at the insert point.
  241. * - XST_DMA_SG_NOTHING_TO_COMMIT if even after inserting a descriptor into the
  242. * list, the DMA channel believes there are no new descriptors to commit.
  243. *
  244. * @internal
  245. *
  246. * A status that should never be returned from this function, although
  247. * the code is set up to handle it, is XST_DMA_SG_NO_LIST. Starting the device
  248. * requires a list to be created, and this function requires the device to be
  249. * started.
  250. *
  251. ******************************************************************************/
  252. XStatus
  253. XEmac_SgRecv(XEmac * InstancePtr, XBufDescriptor * BdPtr)
  254. {
  255. XStatus Result;
  256. u32 BdControl;
  257. XASSERT_NONVOID(InstancePtr != NULL);
  258. XASSERT_NONVOID(BdPtr != NULL);
  259. XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  260. /*
  261. * Be sure the device is configured for scatter-gather DMA
  262. */
  263. if (!XEmac_mIsSgDma(InstancePtr)) {
  264. return XST_NOT_SGDMA;
  265. }
  266. /*
  267. * Set some descriptor control word defaults (destination address increment
  268. * and local source address) and the source address (the FIFO). These are
  269. * the same for every receive descriptor.
  270. */
  271. BdControl = XBufDescriptor_GetControl(BdPtr);
  272. XBufDescriptor_SetControl(BdPtr, BdControl | XEM_DFT_RECV_BD_MASK);
  273. XBufDescriptor_SetSrcAddress(BdPtr,
  274. InstancePtr->BaseAddress +
  275. XEM_PFIFO_RXDATA_OFFSET);
  276. /*
  277. * Put the descriptor into the channel's descriptor list and commit.
  278. * Although this function is likely called within interrupt context, there
  279. * is the possibility that the upper layer software queues it to a task.
  280. * In this case, a critical section is needed here to protect shared data
  281. * in the DMA component.
  282. */
  283. XIIF_V123B_GINTR_DISABLE(InstancePtr->BaseAddress);
  284. Result = XDmaChannel_PutDescriptor(&InstancePtr->RecvChannel, BdPtr);
  285. if (Result != XST_SUCCESS) {
  286. XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
  287. return Result;
  288. }
  289. Result = XDmaChannel_CommitPuts(&InstancePtr->RecvChannel);
  290. if (Result != XST_SUCCESS) {
  291. XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
  292. return Result;
  293. }
  294. /*
  295. * Start the DMA channel. Ignore the return status since we know the list
  296. * exists and has at least one entry and we don't care if the channel is
  297. * already started. The DMA component accesses data here that can be
  298. * modified at interrupt or task levels, so a critical section is required.
  299. */
  300. (void) XDmaChannel_SgStart(&InstancePtr->RecvChannel);
  301. XIIF_V123B_GINTR_ENABLE(InstancePtr->BaseAddress);
  302. return XST_SUCCESS;
  303. }
  304. /*****************************************************************************/
  305. /**
  306. *
  307. * The interrupt handler for the Ethernet driver when configured with scatter-
  308. * gather DMA.
  309. *
  310. * Get the interrupt status from the IpIf to determine the source of the
  311. * interrupt. The source can be: MAC, Recv Packet FIFO, Send Packet FIFO, Recv
  312. * DMA channel, or Send DMA channel. The packet FIFOs only interrupt during
  313. * "deadlock" conditions.
  314. *
  315. * @param InstancePtr is a pointer to the XEmac instance that just interrupted.
  316. *
  317. * @return
  318. *
  319. * None.
  320. *
  321. * @note
  322. *
  323. * None.
  324. *
  325. ******************************************************************************/
  326. void
  327. XEmac_IntrHandlerDma(void *InstancePtr)
  328. {
  329. u32 IntrStatus;
  330. XEmac *EmacPtr = (XEmac *) InstancePtr;
  331. EmacPtr->Stats.TotalIntrs++;
  332. /*
  333. * Get the interrupt status from the IPIF. There is no clearing of
  334. * interrupts in the IPIF. Interrupts must be cleared at the source.
  335. */
  336. IntrStatus = XIIF_V123B_READ_DIPR(EmacPtr->BaseAddress);
  337. /*
  338. * See which type of interrupt is being requested, and service it
  339. */
  340. if (IntrStatus & XEM_IPIF_RECV_DMA_MASK) { /* Receive DMA interrupt */
  341. EmacPtr->Stats.RecvInterrupts++;
  342. HandleDmaRecvIntr(EmacPtr);
  343. }
  344. if (IntrStatus & XEM_IPIF_SEND_DMA_MASK) { /* Send DMA interrupt */
  345. EmacPtr->Stats.XmitInterrupts++;
  346. HandleDmaSendIntr(EmacPtr);
  347. }
  348. if (IntrStatus & XEM_IPIF_EMAC_MASK) { /* MAC interrupt */
  349. EmacPtr->Stats.EmacInterrupts++;
  350. HandleEmacDmaIntr(EmacPtr);
  351. }
  352. if (IntrStatus & XEM_IPIF_RECV_FIFO_MASK) { /* Receive FIFO interrupt */
  353. EmacPtr->Stats.RecvInterrupts++;
  354. XEmac_CheckFifoRecvError(EmacPtr);
  355. }
  356. if (IntrStatus & XEM_IPIF_SEND_FIFO_MASK) { /* Send FIFO interrupt */
  357. EmacPtr->Stats.XmitInterrupts++;
  358. XEmac_CheckFifoSendError(EmacPtr);
  359. }
  360. if (IntrStatus & XIIF_V123B_ERROR_MASK) {
  361. /*
  362. * An error occurred internal to the IPIF. This is more of a debug and
  363. * integration issue rather than a production error. Don't do anything
  364. * other than clear it, which provides a spot for software to trap
  365. * on the interrupt and begin debugging.
  366. */
  367. XIIF_V123B_WRITE_DISR(EmacPtr->BaseAddress,
  368. XIIF_V123B_ERROR_MASK);
  369. }
  370. }
  371. /*****************************************************************************/
  372. /**
  373. *
  374. * Set the packet count threshold for this device. The device must be stopped
  375. * before setting the threshold. The packet count threshold is used for interrupt
  376. * coalescing, which reduces the frequency of interrupts from the device to the
  377. * processor. In this case, the scatter-gather DMA engine only interrupts when
  378. * the packet count threshold is reached, instead of interrupting for each packet.
  379. * A packet is a generic term used by the scatter-gather DMA engine, and is
  380. * equivalent to an Ethernet frame in our case.
  381. *
  382. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  383. * @param Direction indicates the channel, send or receive, from which the
  384. * threshold register is read.
  385. * @param Threshold is the value of the packet threshold count used during
  386. * interrupt coalescing. A value of 0 disables the use of packet threshold
  387. * by the hardware.
  388. *
  389. * @return
  390. *
  391. * - XST_SUCCESS if the threshold was successfully set
  392. * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
  393. * - XST_DEVICE_IS_STARTED if the device has not been stopped
  394. * - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
  395. * asserts would also catch this error.
  396. *
  397. * @note
  398. *
  399. * The packet threshold could be set to larger than the number of descriptors
  400. * allocated to the DMA channel. In this case, the wait bound will take over
  401. * and always indicate data arrival. There was a check in this function that
  402. * returned an error if the treshold was larger than the number of descriptors,
  403. * but that was removed because users would then have to set the threshold
  404. * only after they set descriptor space, which is an order dependency that
  405. * caused confustion.
  406. *
  407. ******************************************************************************/
  408. XStatus
  409. XEmac_SetPktThreshold(XEmac * InstancePtr, u32 Direction, u8 Threshold)
  410. {
  411. XASSERT_NONVOID(InstancePtr != NULL);
  412. XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
  413. XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  414. /*
  415. * Be sure device is configured for scatter-gather DMA and has been stopped
  416. */
  417. if (!XEmac_mIsSgDma(InstancePtr)) {
  418. return XST_NOT_SGDMA;
  419. }
  420. if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) {
  421. return XST_DEVICE_IS_STARTED;
  422. }
  423. /*
  424. * Based on the direction, set the packet threshold in the
  425. * corresponding DMA channel component. Default to the receive
  426. * channel threshold register (if an invalid Direction is passed).
  427. */
  428. switch (Direction) {
  429. case XEM_SEND:
  430. return XDmaChannel_SetPktThreshold(&InstancePtr->SendChannel,
  431. Threshold);
  432. case XEM_RECV:
  433. return XDmaChannel_SetPktThreshold(&InstancePtr->RecvChannel,
  434. Threshold);
  435. default:
  436. return XST_INVALID_PARAM;
  437. }
  438. }
  439. /*****************************************************************************/
  440. /**
  441. *
  442. * Get the value of the packet count threshold for this driver/device. The packet
  443. * count threshold is used for interrupt coalescing, which reduces the frequency
  444. * of interrupts from the device to the processor. In this case, the
  445. * scatter-gather DMA engine only interrupts when the packet count threshold is
  446. * reached, instead of interrupting for each packet. A packet is a generic term
  447. * used by the scatter-gather DMA engine, and is equivalent to an Ethernet frame
  448. * in our case.
  449. *
  450. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  451. * @param Direction indicates the channel, send or receive, from which the
  452. * threshold register is read.
  453. * @param ThreshPtr is a pointer to the byte into which the current value of the
  454. * packet threshold register will be copied. An output parameter. A value
  455. * of 0 indicates the use of packet threshold by the hardware is disabled.
  456. *
  457. * @return
  458. *
  459. * - XST_SUCCESS if the packet threshold was retrieved successfully
  460. * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
  461. * - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
  462. * asserts would also catch this error.
  463. *
  464. * @note
  465. *
  466. * None.
  467. *
  468. ******************************************************************************/
  469. XStatus
  470. XEmac_GetPktThreshold(XEmac * InstancePtr, u32 Direction, u8 * ThreshPtr)
  471. {
  472. XASSERT_NONVOID(InstancePtr != NULL);
  473. XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
  474. XASSERT_NONVOID(ThreshPtr != NULL);
  475. XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  476. if (!XEmac_mIsSgDma(InstancePtr)) {
  477. return XST_NOT_SGDMA;
  478. }
  479. /*
  480. * Based on the direction, return the packet threshold set in the
  481. * corresponding DMA channel component. Default to the value in
  482. * the receive channel threshold register (if an invalid Direction
  483. * is passed).
  484. */
  485. switch (Direction) {
  486. case XEM_SEND:
  487. *ThreshPtr =
  488. XDmaChannel_GetPktThreshold(&InstancePtr->SendChannel);
  489. break;
  490. case XEM_RECV:
  491. *ThreshPtr =
  492. XDmaChannel_GetPktThreshold(&InstancePtr->RecvChannel);
  493. break;
  494. default:
  495. return XST_INVALID_PARAM;
  496. }
  497. return XST_SUCCESS;
  498. }
  499. /*****************************************************************************/
  500. /**
  501. *
  502. * Set the packet wait bound timer for this driver/device. The device must be
  503. * stopped before setting the timer value. The packet wait bound is used during
  504. * interrupt coalescing to trigger an interrupt when not enough packets have been
  505. * received to reach the packet count threshold. A packet is a generic term used
  506. * by the scatter-gather DMA engine, and is equivalent to an Ethernet frame in
  507. * our case. The timer is in milliseconds.
  508. *
  509. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  510. * @param Direction indicates the channel, send or receive, from which the
  511. * threshold register is read.
  512. * @param TimerValue is the value of the packet wait bound used during interrupt
  513. * coalescing. It is in milliseconds in the range 0 - 1023. A value of 0
  514. * disables the packet wait bound timer.
  515. *
  516. * @return
  517. *
  518. * - XST_SUCCESS if the packet wait bound was set successfully
  519. * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
  520. * - XST_DEVICE_IS_STARTED if the device has not been stopped
  521. * - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
  522. * asserts would also catch this error.
  523. *
  524. * @note
  525. *
  526. * None.
  527. *
  528. ******************************************************************************/
  529. XStatus
  530. XEmac_SetPktWaitBound(XEmac * InstancePtr, u32 Direction, u32 TimerValue)
  531. {
  532. XASSERT_NONVOID(InstancePtr != NULL);
  533. XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
  534. XASSERT_NONVOID(TimerValue <= XEM_SGDMA_MAX_WAITBOUND);
  535. XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  536. /*
  537. * Be sure device is configured for scatter-gather DMA and has been stopped
  538. */
  539. if (!XEmac_mIsSgDma(InstancePtr)) {
  540. return XST_NOT_SGDMA;
  541. }
  542. if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) {
  543. return XST_DEVICE_IS_STARTED;
  544. }
  545. /*
  546. * Based on the direction, set the packet wait bound in the
  547. * corresponding DMA channel component. Default to the receive
  548. * channel wait bound register (if an invalid Direction is passed).
  549. */
  550. switch (Direction) {
  551. case XEM_SEND:
  552. XDmaChannel_SetPktWaitBound(&InstancePtr->SendChannel,
  553. TimerValue);
  554. break;
  555. case XEM_RECV:
  556. XDmaChannel_SetPktWaitBound(&InstancePtr->RecvChannel,
  557. TimerValue);
  558. break;
  559. default:
  560. return XST_INVALID_PARAM;
  561. }
  562. return XST_SUCCESS;
  563. }
  564. /*****************************************************************************/
  565. /**
  566. *
  567. * Get the packet wait bound timer for this driver/device. The packet wait bound
  568. * is used during interrupt coalescing to trigger an interrupt when not enough
  569. * packets have been received to reach the packet count threshold. A packet is a
  570. * generic term used by the scatter-gather DMA engine, and is equivalent to an
  571. * Ethernet frame in our case. The timer is in milliseconds.
  572. *
  573. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  574. * @param Direction indicates the channel, send or receive, from which the
  575. * threshold register is read.
  576. * @param WaitPtr is a pointer to the byte into which the current value of the
  577. * packet wait bound register will be copied. An output parameter. Units
  578. * are in milliseconds in the range 0 - 1023. A value of 0 indicates the
  579. * packet wait bound timer is disabled.
  580. *
  581. * @return
  582. *
  583. * - XST_SUCCESS if the packet wait bound was retrieved successfully
  584. * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
  585. * - XST_INVALID_PARAM if the Direction parameter is invalid. Turning on
  586. * asserts would also catch this error.
  587. *
  588. * @note
  589. *
  590. * None.
  591. *
  592. ******************************************************************************/
  593. XStatus
  594. XEmac_GetPktWaitBound(XEmac * InstancePtr, u32 Direction, u32 * WaitPtr)
  595. {
  596. XASSERT_NONVOID(InstancePtr != NULL);
  597. XASSERT_NONVOID(Direction == XEM_SEND || Direction == XEM_RECV);
  598. XASSERT_NONVOID(WaitPtr != NULL);
  599. XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  600. if (!XEmac_mIsSgDma(InstancePtr)) {
  601. return XST_NOT_SGDMA;
  602. }
  603. /*
  604. * Based on the direction, return the packet wait bound set in the
  605. * corresponding DMA channel component. Default to the value in
  606. * the receive channel wait bound register (if an invalid Direction
  607. * is passed).
  608. */
  609. switch (Direction) {
  610. case XEM_SEND:
  611. *WaitPtr =
  612. XDmaChannel_GetPktWaitBound(&InstancePtr->SendChannel);
  613. break;
  614. case XEM_RECV:
  615. *WaitPtr =
  616. XDmaChannel_GetPktWaitBound(&InstancePtr->RecvChannel);
  617. break;
  618. default:
  619. return XST_INVALID_PARAM;
  620. }
  621. return XST_SUCCESS;
  622. }
  623. /*****************************************************************************/
  624. /**
  625. *
  626. * Give the driver the memory space to be used for the scatter-gather DMA
  627. * receive descriptor list. This function should only be called once, during
  628. * initialization of the Ethernet driver. The memory space must be big enough
  629. * to hold some number of descriptors, depending on the needs of the system.
  630. * The xemac.h file defines minimum and default numbers of descriptors
  631. * which can be used to allocate this memory space.
  632. *
  633. * The memory space must be word-aligned. An assert will occur if asserts are
  634. * turned on and the memory is not word-aligned.
  635. *
  636. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  637. * @param MemoryPtr is a pointer to the word-aligned memory.
  638. * @param ByteCount is the length, in bytes, of the memory space.
  639. *
  640. * @return
  641. *
  642. * - XST_SUCCESS if the space was initialized successfully
  643. * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
  644. * - XST_DMA_SG_LIST_EXISTS if this list space has already been created
  645. *
  646. * @note
  647. *
  648. * If the device is configured for scatter-gather DMA, this function must be
  649. * called AFTER the XEmac_Initialize() function because the DMA channel
  650. * components must be initialized before the memory space is set.
  651. *
  652. ******************************************************************************/
  653. XStatus
  654. XEmac_SetSgRecvSpace(XEmac * InstancePtr, u32 * MemoryPtr, u32 ByteCount)
  655. {
  656. XASSERT_NONVOID(InstancePtr != NULL);
  657. XASSERT_NONVOID(MemoryPtr != NULL);
  658. XASSERT_NONVOID(ByteCount != 0);
  659. XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  660. if (!XEmac_mIsSgDma(InstancePtr)) {
  661. return XST_NOT_SGDMA;
  662. }
  663. return XDmaChannel_CreateSgList(&InstancePtr->RecvChannel, MemoryPtr,
  664. ByteCount);
  665. }
  666. /*****************************************************************************/
  667. /**
  668. *
  669. * Give the driver the memory space to be used for the scatter-gather DMA
  670. * transmit descriptor list. This function should only be called once, during
  671. * initialization of the Ethernet driver. The memory space must be big enough
  672. * to hold some number of descriptors, depending on the needs of the system.
  673. * The xemac.h file defines minimum and default numbers of descriptors
  674. * which can be used to allocate this memory space.
  675. *
  676. * The memory space must be word-aligned. An assert will occur if asserts are
  677. * turned on and the memory is not word-aligned.
  678. *
  679. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  680. * @param MemoryPtr is a pointer to the word-aligned memory.
  681. * @param ByteCount is the length, in bytes, of the memory space.
  682. *
  683. * @return
  684. *
  685. * - XST_SUCCESS if the space was initialized successfully
  686. * - XST_NOT_SGDMA if the MAC is not configured for scatter-gather DMA
  687. * - XST_DMA_SG_LIST_EXISTS if this list space has already been created
  688. *
  689. * @note
  690. *
  691. * If the device is configured for scatter-gather DMA, this function must be
  692. * called AFTER the XEmac_Initialize() function because the DMA channel
  693. * components must be initialized before the memory space is set.
  694. *
  695. ******************************************************************************/
  696. XStatus
  697. XEmac_SetSgSendSpace(XEmac * InstancePtr, u32 * MemoryPtr, u32 ByteCount)
  698. {
  699. XASSERT_NONVOID(InstancePtr != NULL);
  700. XASSERT_NONVOID(MemoryPtr != NULL);
  701. XASSERT_NONVOID(ByteCount != 0);
  702. XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  703. if (!XEmac_mIsSgDma(InstancePtr)) {
  704. return XST_NOT_SGDMA;
  705. }
  706. return XDmaChannel_CreateSgList(&InstancePtr->SendChannel, MemoryPtr,
  707. ByteCount);
  708. }
  709. /*****************************************************************************/
  710. /**
  711. *
  712. * Set the callback function for handling received frames in scatter-gather DMA
  713. * mode. The upper layer software should call this function during
  714. * initialization. The callback is called once per frame received. The head of
  715. * a descriptor list is passed in along with the number of descriptors in the
  716. * list. Before leaving the callback, the upper layer software should attach a
  717. * new buffer to each descriptor in the list.
  718. *
  719. * The callback is invoked by the driver within interrupt context, so it needs
  720. * to do its job quickly. Sending the received frame up the protocol stack
  721. * should be done at task-level. If there are other potentially slow operations
  722. * within the callback, these too should be done at task-level.
  723. *
  724. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  725. * @param CallBackRef is a reference pointer to be passed back to the adapter in
  726. * the callback. This helps the adapter correlate the callback to a
  727. * particular driver.
  728. * @param FuncPtr is the pointer to the callback function.
  729. *
  730. * @return
  731. *
  732. * None.
  733. *
  734. * @note
  735. *
  736. * None.
  737. *
  738. ******************************************************************************/
  739. void
  740. XEmac_SetSgRecvHandler(XEmac * InstancePtr, void *CallBackRef,
  741. XEmac_SgHandler FuncPtr)
  742. {
  743. /*
  744. * Asserted IsDmaSg here instead of run-time check because there is really
  745. * no ill-effects of setting these when not configured for scatter-gather.
  746. */
  747. XASSERT_VOID(InstancePtr != NULL);
  748. XASSERT_VOID(FuncPtr != NULL);
  749. XASSERT_VOID(XEmac_mIsSgDma(InstancePtr));
  750. XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  751. InstancePtr->SgRecvHandler = FuncPtr;
  752. InstancePtr->SgRecvRef = CallBackRef;
  753. }
  754. /*****************************************************************************/
  755. /**
  756. *
  757. * Set the callback function for handling confirmation of transmitted frames in
  758. * scatter-gather DMA mode. The upper layer software should call this function
  759. * during initialization. The callback is called once per frame sent. The head
  760. * of a descriptor list is passed in along with the number of descriptors in
  761. * the list. The callback is responsible for freeing buffers attached to these
  762. * descriptors.
  763. *
  764. * The callback is invoked by the driver within interrupt context, so it needs
  765. * to do its job quickly. If there are potentially slow operations within the
  766. * callback, these should be done at task-level.
  767. *
  768. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  769. * @param CallBackRef is a reference pointer to be passed back to the adapter in
  770. * the callback. This helps the adapter correlate the callback to a
  771. * particular driver.
  772. * @param FuncPtr is the pointer to the callback function.
  773. *
  774. * @return
  775. *
  776. * None.
  777. *
  778. * @note
  779. *
  780. * None.
  781. *
  782. ******************************************************************************/
  783. void
  784. XEmac_SetSgSendHandler(XEmac * InstancePtr, void *CallBackRef,
  785. XEmac_SgHandler FuncPtr)
  786. {
  787. /*
  788. * Asserted IsDmaSg here instead of run-time check because there is really
  789. * no ill-effects of setting these when not configured for scatter-gather.
  790. */
  791. XASSERT_VOID(InstancePtr != NULL);
  792. XASSERT_VOID(FuncPtr != NULL);
  793. XASSERT_VOID(XEmac_mIsSgDma(InstancePtr));
  794. XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
  795. InstancePtr->SgSendHandler = FuncPtr;
  796. InstancePtr->SgSendRef = CallBackRef;
  797. }
  798. /*****************************************************************************/
  799. /*
  800. *
  801. * Handle an interrupt from the DMA receive channel. DMA interrupts are:
  802. *
  803. * - DMA error. DMA encountered a bus error or timeout. This is a fatal error
  804. * that requires reset of the channel. The driver calls the error handler
  805. * of the upper layer software with an error code indicating the device should
  806. * be reset.
  807. * - Packet count threshold reached. For scatter-gather operations, indicates
  808. * the threshold for the number of packets not serviced by software has been
  809. * reached. The driver behaves as follows:
  810. * - Get the value of the packet counter, which tells us how many packets
  811. * are ready to be serviced
  812. * - For each packet
  813. * - For each descriptor, remove it from the scatter-gather list
  814. * - Check for the last descriptor in the frame, and if set
  815. * - Bump frame statistics
  816. * - Call the scatter-gather receive callback function
  817. * - Decrement the packet counter by one
  818. * Note that there are no receive errors reported in the status word of
  819. * the buffer descriptor. If receive errors occur, the MAC drops the
  820. * packet, and we only find out about the errors through various error
  821. * count registers.
  822. * - Packet wait bound reached. For scatter-gather, indicates the time to wait
  823. * for the next packet has expired. The driver follows the same logic as when
  824. * the packet count threshold interrupt is received.
  825. * - Scatter-gather end acknowledge. Hardware has reached the end of the
  826. * descriptor list. The driver follows the same logic as when the packet count
  827. * threshold interrupt is received. In addition, the driver restarts the DMA
  828. * scatter-gather channel in case there are newly inserted descriptors.
  829. *
  830. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  831. *
  832. * @return
  833. *
  834. * Although the function returns void, there are asynchronous errors that can
  835. * be generated (by calling the ErrorHandler) from this function. These are:
  836. * - XST_DMA_SG_LIST_EMPTY indicates we tried to get a buffer descriptor from the
  837. * DMA channel, but there was not one ready for software.
  838. * - XST_DMA_ERROR indicates a DMA bus error or timeout occurred. This is a fatal
  839. * error that requires reset.
  840. *
  841. * @note
  842. *
  843. * None.
  844. *
  845. ******************************************************************************/
  846. static void
  847. HandleDmaRecvIntr(XEmac * InstancePtr)
  848. {
  849. u32 IntrStatus;
  850. /*
  851. * Read the interrupt status
  852. */
  853. IntrStatus = XDmaChannel_GetIntrStatus(&InstancePtr->RecvChannel);
  854. /*
  855. * For packet threshold or wait bound interrupts, process desciptors. Also
  856. * process descriptors on a SG end acknowledgement, which means the end of
  857. * the descriptor list has been reached by the hardware. For receive, this
  858. * is potentially trouble since it means the descriptor list is full,
  859. * unless software can process enough packets quickly enough so the
  860. * hardware has room to put new packets.
  861. */
  862. if (IntrStatus & (XDC_IXR_PKT_THRESHOLD_MASK |
  863. XDC_IXR_PKT_WAIT_BOUND_MASK | XDC_IXR_SG_END_MASK)) {
  864. XStatus Result = XST_SUCCESS;
  865. u32 NumFrames;
  866. u32 NumProcessed;
  867. u32 NumBuffers;
  868. u32 NumBytes;
  869. u32 IsLast;
  870. XBufDescriptor *FirstBdPtr;
  871. XBufDescriptor *BdPtr;
  872. /*
  873. * Get the number of unserviced packets
  874. */
  875. NumFrames = XDmaChannel_GetPktCount(&InstancePtr->RecvChannel);
  876. for (NumProcessed = 0; NumProcessed < NumFrames; NumProcessed++) {
  877. IsLast = FALSE;
  878. FirstBdPtr = NULL;
  879. NumBuffers = 0;
  880. NumBytes = 0;
  881. /*
  882. * For each packet, get the descriptor from the list. On the
  883. * last one in the frame, make the callback to the upper layer.
  884. */
  885. while (!IsLast) {
  886. Result =
  887. XDmaChannel_GetDescriptor(&InstancePtr->
  888. RecvChannel,
  889. &BdPtr);
  890. if (Result != XST_SUCCESS) {
  891. /*
  892. * An error getting a buffer descriptor from the list.
  893. * This should not happen, but if it does, report it to
  894. * the error callback and break out of the loops to service
  895. * other interrupts.
  896. */
  897. InstancePtr->ErrorHandler(InstancePtr->
  898. ErrorRef,
  899. Result);
  900. break;
  901. }
  902. /*
  903. * Keep a pointer to the first descriptor in the list, as it
  904. * will be passed to the upper layers in a bit. By the fact
  905. * that we received this packet means no errors occurred, so
  906. * no need to check the device status word for errors.
  907. */
  908. if (FirstBdPtr == NULL) {
  909. FirstBdPtr = BdPtr;
  910. }
  911. NumBytes += XBufDescriptor_GetLength(BdPtr);
  912. /*
  913. * Check to see if this is the last descriptor in the frame,
  914. * and if so, set the IsLast flag to get out of the loop.
  915. */
  916. if (XBufDescriptor_IsLastStatus(BdPtr)) {
  917. IsLast = TRUE;
  918. }
  919. /*
  920. * Bump the number of buffers in this packet
  921. */
  922. NumBuffers++;
  923. } /* end while loop */
  924. /*
  925. * Check for error that occurred inside the while loop, and break
  926. * out of the for loop if there was one so other interrupts can
  927. * be serviced.
  928. */
  929. if (Result != XST_SUCCESS) {
  930. break;
  931. }
  932. InstancePtr->Stats.RecvFrames++;
  933. InstancePtr->Stats.RecvBytes += NumBytes;
  934. /*
  935. * Make the callback to the upper layers, passing it the first
  936. * descriptor in the packet and the number of descriptors in the
  937. * packet.
  938. */
  939. InstancePtr->SgRecvHandler(InstancePtr->SgRecvRef,
  940. FirstBdPtr, NumBuffers);
  941. /*
  942. * Decrement the packet count register to reflect the fact we
  943. * just processed a packet
  944. */
  945. XDmaChannel_DecrementPktCount(&InstancePtr->
  946. RecvChannel);
  947. } /* end for loop */
  948. /*
  949. * If the interrupt was an end-ack, check the descriptor list again to
  950. * see if it is empty. If not, go ahead and restart the scatter-gather
  951. * channel. This is to fix a possible race condition where, on receive,
  952. * the driver attempted to start a scatter-gather channel that was
  953. * already started, which resulted in no action from the XDmaChannel
  954. * component. But, just after the XDmaChannel component saw that the
  955. * hardware was already started, the hardware stopped because it
  956. * reached the end of the list. In that case, this interrupt is
  957. * generated and we can restart the hardware here.
  958. */
  959. if (IntrStatus & XDC_IXR_SG_END_MASK) {
  960. /*
  961. * Ignore the return status since we know the list exists and we
  962. * don't care if the list is empty or the channel is already started.
  963. */
  964. (void) XDmaChannel_SgStart(&InstancePtr->RecvChannel);
  965. }
  966. }
  967. /*
  968. * All interrupts are handled (except the error below) so acknowledge
  969. * (clear) the interrupts by writing the value read above back to the status
  970. * register. The packet count interrupt must be acknowledged after the
  971. * decrement, otherwise it will come right back. We clear the interrupts
  972. * before we handle the error interrupt because the ErrorHandler should
  973. * result in a reset, which clears the interrupt status register. So we
  974. * don't want to toggle the interrupt back on by writing the interrupt
  975. * status register with an old value after a reset.
  976. */
  977. XDmaChannel_SetIntrStatus(&InstancePtr->RecvChannel, IntrStatus);
  978. /*
  979. * Check for DMA errors and call the error callback function if an error
  980. * occurred (DMA bus or timeout error), which should result in a reset of
  981. * the device by the upper layer software.
  982. */
  983. if (IntrStatus & XDC_IXR_DMA_ERROR_MASK) {
  984. InstancePtr->Stats.DmaErrors++;
  985. InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XST_DMA_ERROR);
  986. }
  987. }
  988. /*****************************************************************************/
  989. /*
  990. *
  991. * Handle an interrupt from the DMA send channel. DMA interrupts are:
  992. *
  993. * - DMA error. DMA encountered a bus error or timeout. This is a fatal error
  994. * that requires reset of the channel. The driver calls the error handler
  995. * of the upper layer software with an error code indicating the device should
  996. * be reset.
  997. * - Packet count threshold reached. For scatter-gather operations, indicates
  998. * the threshold for the number of packets not serviced by software has been
  999. * reached. The driver behaves as follows:
  1000. * - Get the value of the packet counter, which tells us how many packets
  1001. * are ready to be serviced
  1002. * - For each packet
  1003. * - For each descriptor, remove it from the scatter-gather list
  1004. * - Check for the last descriptor in the frame, and if set
  1005. * - Bump frame statistics
  1006. * - Call the scatter-gather receive callback function
  1007. * - Decrement the packet counter by one
  1008. * Note that there are no receive errors reported in the status word of
  1009. * the buffer descriptor. If receive errors occur, the MAC drops the
  1010. * packet, and we only find out about the errors through various error
  1011. * count registers.
  1012. * - Packet wait bound reached. For scatter-gather, indicates the time to wait
  1013. * for the next packet has expired. The driver follows the same logic as when
  1014. * the packet count threshold interrupt is received.
  1015. * - Scatter-gather end acknowledge. Hardware has reached the end of the
  1016. * descriptor list. The driver follows the same logic as when the packet count
  1017. * threshold interrupt is received. In addition, the driver restarts the DMA
  1018. * scatter-gather channel in case there are newly inserted descriptors.
  1019. *
  1020. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  1021. *
  1022. * @return
  1023. *
  1024. * Although the function returns void, there are asynchronous errors
  1025. * that can be generated from this function. These are:
  1026. * - XST_DMA_SG_LIST_EMPTY indicates we tried to get a buffer descriptor from
  1027. * the DMA channel, but there was not one ready for software.
  1028. * - XST_DMA_ERROR indicates a DMA bus error or timeout occurred. This is a
  1029. * fatal error that requires reset.
  1030. *
  1031. * @note
  1032. *
  1033. * None.
  1034. *
  1035. ******************************************************************************/
  1036. static void
  1037. HandleDmaSendIntr(XEmac * InstancePtr)
  1038. {
  1039. u32 IntrStatus;
  1040. /*
  1041. * Read the interrupt status
  1042. */
  1043. IntrStatus = XDmaChannel_GetIntrStatus(&InstancePtr->SendChannel);
  1044. /*
  1045. * For packet threshold or wait bound interrupt, process descriptors. Also
  1046. * process descriptors on a SG end acknowledgement, which means the end of
  1047. * the descriptor list has been reached by the hardware. For transmit,
  1048. * this is a normal condition during times of light traffic. In fact, the
  1049. * wait bound interrupt may be masked for transmit since the end-ack would
  1050. * always occur before the wait bound expires.
  1051. */
  1052. if (IntrStatus & (XDC_IXR_PKT_THRESHOLD_MASK |
  1053. XDC_IXR_PKT_WAIT_BOUND_MASK | XDC_IXR_SG_END_MASK)) {
  1054. XStatus Result = XST_SUCCESS;
  1055. u32 NumFrames;
  1056. u32 NumProcessed;
  1057. u32 NumBuffers;
  1058. u32 NumBytes;
  1059. u32 IsLast;
  1060. XBufDescriptor *FirstBdPtr;
  1061. XBufDescriptor *BdPtr;
  1062. /*
  1063. * Get the number of unserviced packets
  1064. */
  1065. NumFrames = XDmaChannel_GetPktCount(&InstancePtr->SendChannel);
  1066. for (NumProcessed = 0; NumProcessed < NumFrames; NumProcessed++) {
  1067. IsLast = FALSE;
  1068. FirstBdPtr = NULL;
  1069. NumBuffers = 0;
  1070. NumBytes = 0;
  1071. /*
  1072. * For each frame, traverse the descriptor list and look for
  1073. * errors. On the last one in the frame, make the callback.
  1074. */
  1075. while (!IsLast) {
  1076. Result =
  1077. XDmaChannel_GetDescriptor(&InstancePtr->
  1078. SendChannel,
  1079. &BdPtr);
  1080. if (Result != XST_SUCCESS) {
  1081. /*
  1082. * An error getting a buffer descriptor from the list.
  1083. * This should not happen, but if it does, report it to
  1084. * the error callback and break out of the loops to service
  1085. * other interrupts
  1086. */
  1087. InstancePtr->ErrorHandler(InstancePtr->
  1088. ErrorRef,
  1089. Result);
  1090. break;
  1091. }
  1092. /*
  1093. * Keep a pointer to the first descriptor in the list and
  1094. * check the device status for errors. The device status is
  1095. * only available in the first descriptor of a packet.
  1096. */
  1097. if (FirstBdPtr == NULL) {
  1098. u32 XmitStatus;
  1099. FirstBdPtr = BdPtr;
  1100. XmitStatus =
  1101. XBufDescriptor_GetDeviceStatus
  1102. (BdPtr);
  1103. if (XmitStatus &
  1104. XEM_TSR_EXCESS_DEFERRAL_MASK) {
  1105. InstancePtr->Stats.
  1106. XmitExcessDeferral++;
  1107. }
  1108. if (XmitStatus &
  1109. XEM_TSR_LATE_COLLISION_MASK) {
  1110. InstancePtr->Stats.
  1111. XmitLateCollisionErrors++;
  1112. }
  1113. }
  1114. NumBytes += XBufDescriptor_GetLength(BdPtr);
  1115. /*
  1116. * Check to see if this is the last descriptor in the frame,
  1117. * and if so, set the IsLast flag to get out of the loop. The
  1118. * transmit channel must check the last bit in the control
  1119. * word, not the status word (the DMA engine does not update
  1120. * the last bit in the status word for the transmit direction).
  1121. */
  1122. if (XBufDescriptor_IsLastControl(BdPtr)) {
  1123. IsLast = TRUE;
  1124. }
  1125. /*
  1126. * Bump the number of buffers in this packet
  1127. */
  1128. NumBuffers++;
  1129. } /* end while loop */
  1130. /*
  1131. * Check for error that occurred inside the while loop, and break
  1132. * out of the for loop if there was one so other interrupts can
  1133. * be serviced.
  1134. */
  1135. if (Result != XST_SUCCESS) {
  1136. break;
  1137. }
  1138. InstancePtr->Stats.XmitFrames++;
  1139. InstancePtr->Stats.XmitBytes += NumBytes;
  1140. /*
  1141. * Make the callback to the upper layers, passing it the first
  1142. * descriptor in the packet and the number of descriptors in the
  1143. * packet.
  1144. */
  1145. InstancePtr->SgSendHandler(InstancePtr->SgSendRef,
  1146. FirstBdPtr, NumBuffers);
  1147. /*
  1148. * Decrement the packet count register to reflect the fact we
  1149. * just processed a packet
  1150. */
  1151. XDmaChannel_DecrementPktCount(&InstancePtr->
  1152. SendChannel);
  1153. } /* end for loop */
  1154. /*
  1155. * If the interrupt was an end-ack, check the descriptor list again to
  1156. * see if it is empty. If not, go ahead and restart the scatter-gather
  1157. * channel. This is to fix a possible race condition where, on transmit,
  1158. * the driver attempted to start a scatter-gather channel that was
  1159. * already started, which resulted in no action from the XDmaChannel
  1160. * component. But, just after the XDmaChannel component saw that the
  1161. * hardware was already started, the hardware stopped because it
  1162. * reached the end of the list. In that case, this interrupt is
  1163. * generated and we can restart the hardware here.
  1164. */
  1165. if (IntrStatus & XDC_IXR_SG_END_MASK) {
  1166. /*
  1167. * Ignore the return status since we know the list exists and we
  1168. * don't care if the list is empty or the channel is already started.
  1169. */
  1170. (void) XDmaChannel_SgStart(&InstancePtr->SendChannel);
  1171. }
  1172. }
  1173. /*
  1174. * All interrupts are handled (except the error below) so acknowledge
  1175. * (clear) the interrupts by writing the value read above back to the status
  1176. * register. The packet count interrupt must be acknowledged after the
  1177. * decrement, otherwise it will come right back. We clear the interrupts
  1178. * before we handle the error interrupt because the ErrorHandler should
  1179. * result in a reset, which clears the interrupt status register. So we
  1180. * don't want to toggle the interrupt back on by writing the interrupt
  1181. * status register with an old value after a reset.
  1182. */
  1183. XDmaChannel_SetIntrStatus(&InstancePtr->SendChannel, IntrStatus);
  1184. /*
  1185. * Check for DMA errors and call the error callback function if an error
  1186. * occurred (DMA bus or timeout error), which should result in a reset of
  1187. * the device by the upper layer software.
  1188. */
  1189. if (IntrStatus & XDC_IXR_DMA_ERROR_MASK) {
  1190. InstancePtr->Stats.DmaErrors++;
  1191. InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XST_DMA_ERROR);
  1192. }
  1193. }
  1194. /*****************************************************************************/
  1195. /*
  1196. *
  1197. * Handle an interrupt from the Ethernet MAC when configured with scatter-gather
  1198. * DMA. The only interrupts handled in this case are errors.
  1199. *
  1200. * @param InstancePtr is a pointer to the XEmac instance to be worked on.
  1201. *
  1202. * @return
  1203. *
  1204. * None.
  1205. *
  1206. * @note
  1207. *
  1208. * None.
  1209. *
  1210. ******************************************************************************/
  1211. static void
  1212. HandleEmacDmaIntr(XEmac * InstancePtr)
  1213. {
  1214. u32 IntrStatus;
  1215. /*
  1216. * When configured with DMA, the EMAC generates interrupts only when errors
  1217. * occur. We clear the interrupts immediately so that any latched status
  1218. * interrupt bits will reflect the true status of the device, and so any
  1219. * pulsed interrupts (non-status) generated during the Isr will not be lost.
  1220. */
  1221. IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress);
  1222. XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, IntrStatus);
  1223. /*
  1224. * Check the MAC for errors
  1225. */
  1226. XEmac_CheckEmacError(InstancePtr, IntrStatus);
  1227. }