Esempio n. 1
0
/**
 * Retrieve BDs that have been processed by the SGDMA channel. This function is
 * called typically after the XTE_HANDLER_SGRECV handler has been invoked for
 * the receive channel or XTE_HANDLER_SGSEND for the transmit channel.
 *
 * The set of BDs returned is a list starting with the BdPtr and extending
 * for 1 or more BDs (the exact number is the return value of this function).
 * The list can be navigated with macros XTemac_mSgRecvBdNext() for the
 * XTE_RECV channel, and XTemac_mSgSendBdNext() for the XTE_SEND channel.
 * Treat the returned BDs as read-only.
 *
 * This function and XTemac_SgFree() must be called in the correct order. See
 * xtemac.h for more information on the SGDMA use model.
 *
 * The last BD in the returned list is guaranteed to have the "Last" bit set
 * (i.e. XDmaBdV2_IsLast evaluates to true).
 *
 * The returned BDs can be examined for the outcome of the SGDMA transaction.
 *
 * @param InstancePtr is a pointer to the instance to be worked on.
 * @param Direction is the channel to address (XTE_SEND or XTE_RECV).
 * @param BdPtr is an output parameter that points to the 1st BD in the returned
 *        list. If no BDs were ready, then this parameter is unchanged.
 * @param NumBd is an upper limit to the number of BDs to retrieve.
 *
 * @return
 * Number of BDs that are ready for post processing. If the direction parameter
 * is invalid, then 0 is returned.
 *
 * @note
 * This function is not thread-safe. The user must provide mutually exclusive
 * access to this function if there are to be multiple threads that can call it.
 *
 ******************************************************************************/
unsigned XTemac_SgGetProcessed(XTemac * InstancePtr, u32 Direction,
			       unsigned NumBd, XDmaBdV2 ** BdPtr)
{
	u32 DgieReg;
	XDmaV2 *DmaPtr;
	unsigned Rc;

	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(BdPtr != NULL);
	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	/* Which channel to address */
	if (Direction == XTE_RECV) {
		DmaPtr = &InstancePtr->RecvDma;
	} else if (Direction == XTE_SEND) {
		DmaPtr = &InstancePtr->SendDma;
	} else {
		return (0);
	}

	/* This is a critical section. Prevent interrupts from the device while
	 * the BD ring is being modified.
	 */
	DgieReg = XTemac_mGetIpifReg(XTE_DGIE_OFFSET);
	XTemac_mSetIpifReg(XTE_DGIE_OFFSET, 0);

	/* Extract ready BDs */
	Rc = XDmaV2_SgBdFromHw(DmaPtr, NumBd, BdPtr);

	/* This is where we ack IPXR_PCTR interrupt for the dma channel. This
	 * cannot be done in XTemac_IntrSgDmaHandler() because HW will keep the
	 * interrupt asserted as long as the DMA channel's PCT > threshold. Calling
	 * SgBdFromHw above will decrement PCT which should in most cases allow
	 * the acknowledgement to take effect.
	 *
	 * We have to read the status 1st and test it before clearing
	 * it. Bloody toggle-on-write statuses. Grrrr!
	 */
	if (XDmaV2_GetInterruptStatus(DmaPtr) & XDMAV2_IPXR_PCTR_MASK) {
		XDmaV2_SetInterruptStatus(DmaPtr, XDMAV2_IPXR_PCTR_MASK);
	}

	/* End critical section */
	XTemac_mSetIpifReg(XTE_DGIE_OFFSET, DgieReg);

	return (Rc);
}
Esempio n. 2
0
/**
 *
 * Master interrupt handler for FIFO direct frame transfer mode. This routine
 * will query the status of the device, bump statistics, and invoke user
 * callbacks in the following priority:
 *
 *  - XTE_HANDLER_ERROR for error class XST_PFIFO_DEADLOCK.
 *  - XTE_HANDLER_ERROR for error class XST_DMA_ERROR for reads.
 *  - XTE_HANDLER_FIFODMAREAD for successfull DMA reads
 *  - XTE_HANDLER_ERROR for error class XST_DMA_ERROR for writes.
 *  - XTE_HANDLER_FIFODMAWRITE for successfull DMA writes
 *  - XTE_HANDLER_ERROR for error class XST_FIFO_ERROR.
 *  - XTE_HANDLER_FIFORECV for newly received frames
 *  - XTE_HANDLER_ERROR for error class XST_SEND_ERROR.
 *  - XTE_HANDLER_FIFOSEND for completed transmits
 *  - XTE_HANDLER_ERROR for error class XST_RECV_ERROR.
 *
 * This routine must be connected to an interrupt controller using OS/BSP
 * specific methods.
 *
 * @param InstancePtr is a pointer to the TEMAC instance that has caused the
 *        interrupt.
 *
 * @return None
 *
 ******************************************************************************/
void XTemac_IntrFifoHandler(void *TemacPtr)
{
	u32 RegDISR;
	u32 CorePending;
	u32 RegMisc;
	u32 Bytes;
	unsigned Cnt;
	XTemac *InstancePtr = (XTemac *) TemacPtr;

	XASSERT_VOID(InstancePtr != NULL);

	/* This ISR will try to handle as many interrupts as it can in a single
	 * call. However, in most of the places where the user's error handler is
	 * called, this ISR exits because it is expected that the user will reset
	 * the device most of the time.
	 */

	/* Log interrupt */
	XTemac_mBumpStats(Interrupts, 1);

	/* Get top level interrupt status. The status is self clearing when the
	 * interrupt source is cleared
	 */
	RegDISR = XTemac_mGetIpifReg(XTE_DISR_OFFSET);

	/* Handle IPIF and packet FIFO errors */
	if (RegDISR & (XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK |
		       XTE_DXR_RECV_FIFO_MASK | XTE_DXR_SEND_FIFO_MASK)) {
		/* IPIF transaction or data phase error */
		if (RegDISR & (XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK)) {
			XTemac_mBumpStats(IpifErrors, 1);
			ERR_HANDLER(XST_IPIF_ERROR, RegDISR, 0);
			return;
		}

		/* Receive packet FIFO is deadlocked */
		if (RegDISR & XTE_DXR_RECV_FIFO_MASK) {
			XTemac_mBumpStats(RxPktFifoErrors, 1);
			ERR_HANDLER(XST_PFIFO_DEADLOCK, XTE_RECV, 0);
			return;
		}

		/* Transmit packet FIFO is deadlocked */
		if (RegDISR & XTE_DXR_SEND_FIFO_MASK) {
			XTemac_mBumpStats(TxPktFifoErrors, 1);
			ERR_HANDLER(XST_PFIFO_DEADLOCK, XTE_SEND, 0);
			return;
		}
	}

	/* Handle receive side simple DMA channel interrupt. Read and ack the
	 * DMA's interrupt status. If an error is indicated then call the
	 * error handler. If a transfer complete is indicated then call the
	 * DMA read handler
	 */
	if (RegDISR & XTE_DXR_RECV_DMA_MASK) {
		RegMisc = XDmaV2_GetInterruptStatus(&InstancePtr->RecvDma);
		XDmaV2_SetInterruptStatus(&InstancePtr->RecvDma, RegMisc);

		if (RegMisc & XDMAV2_IPXR_DE_MASK) {
			XTemac_mBumpStats(RxDmaErrors, 1);
			ERR_HANDLER(XST_DMA_ERROR, XTE_RECV,
				    XDmaV2_mGetStatus(&InstancePtr->RecvDma));
			return;
		}

		if (RegMisc & XDMAV2_IPXR_DD_MASK) {
			Bytes = InstancePtr->DmaReadLengthRef;
			InstancePtr->DmaReadLengthRef = 0;
			DMAREAD_HANDLER(Bytes);
		}
	}

	/* Handle send side simple DMA channel interrupt. Read and ack the
	 * DMA's interrupt status. If an error is indicated then call the
	 * error handler. If a transfer complete is indicated then call the
	 * DMA write handler
	 */
	if (RegDISR & XTE_DXR_SEND_DMA_MASK) {
		RegMisc = XDmaV2_GetInterruptStatus(&InstancePtr->SendDma);
		XDmaV2_SetInterruptStatus(&InstancePtr->SendDma, RegMisc);

		if (RegMisc & XDMAV2_IPXR_DE_MASK) {
			XTemac_mBumpStats(TxDmaErrors, 1);
			ERR_HANDLER(XST_DMA_ERROR, XTE_SEND,
				    XDmaV2_mGetStatus(&InstancePtr->SendDma));
			return;
		}

		if (RegMisc & XDMAV2_IPXR_DD_MASK) {
			Bytes = InstancePtr->DmaWriteLengthRef;
			InstancePtr->DmaWriteLengthRef = 0;
			DMAWRITE_HANDLER(Bytes);
		}
	}

	/* Handle core interrupts */
	if (RegDISR & XTE_DXR_CORE_MASK) {
		/* Calculate which enabled interrupts have been asserted */
		CorePending = XTemac_mGetIpifReg(XTE_IPIER_OFFSET) &
		    XTemac_mGetIpifReg(XTE_IPISR_OFFSET);

		/* Check for fatal status/length FIFO errors. These errors can't be
		 * cleared
		 */
		if (CorePending & XTE_IPXR_FIFO_FATAL_ERROR_MASK) {
			XTemac_mBumpStats(FifoErrors, 1);
			ERR_HANDLER(XST_FIFO_ERROR, CorePending &
				    XTE_IPXR_FIFO_FATAL_ERROR_MASK, 0);
			return;
		}

		/* A receive packet has arrived. Call the receive handler.
		 *
		 * Acking this interrupt is not done here. The handler has a choice:
		 * 1) Call XTemac_FifoRecv() which will ack this interrupt source, or
		 * 2) Call XTemac_IntrFifoDisable() and defer XTEmac_FifoRecv() to a
		 * later time. Failure to do one of these actions will leave this
		 * interupt still pending resulting in an exception loop.
		 */
		if (CorePending & XTE_IPXR_RECV_DONE_MASK) {
			FIFORECV_HANDLER();
		}

		/* A transmit has completed. Pull off all statuses that are available.
		 * For each status that contains a non-fatal error, the error handler
		 * is invoked. For fatal errors, the error handler is invoked once and
		 * assumes the callback will reset the device.
		 *
		 * Unless there was a fatal error, then call the send handler since
		 * resources in the packet FIFO, transmit length FIFO, and transmit
		 * status FIFO have been freed up. This gives the handler a chance
		 * to enqueue new frame(s).
		 */
		if (CorePending & XTE_IPXR_XMIT_DONE_MASK) {
			Cnt = 0;

			/* While XMIT_DONE persists */
			do {
				/* Get TSR, try to clear XMIT_DONE */
				RegMisc = XTemac_mGetIpifReg(XTE_TSR_OFFSET);
				XTemac_mSetIpifReg(XTE_IPISR_OFFSET,
						   XTE_IPXR_XMIT_DONE_MASK);

				/* Does TSR indicate error? */
				if (RegMisc & XTE_TSR_ERROR_MASK) {
					XTemac_mBumpStats(TxStatusErrors, 1);
					ERR_HANDLER(XST_SEND_ERROR, RegMisc, 0);

					/* Fatal errors end processing immediately */
					if (RegMisc & XTE_TSR_PFIFOU_MASK) {
						return;
					}
				}

				Cnt++;

				/* Read IPISR and test XMIT_DONE again */
				RegMisc = XTemac_mGetIpifReg(XTE_IPISR_OFFSET);
			} while (RegMisc & XTE_IPXR_XMIT_DONE_MASK);

			FIFOSEND_HANDLER(Cnt);
		}

		/* Check for dropped receive frame. Ack the interupt then call the
		 * error handler
		 */
		if (CorePending & XTE_IPXR_RECV_DROPPED_MASK) {
			XTemac_mSetIpifReg(XTE_IPISR_OFFSET,
					   CorePending &
					   XTE_IPXR_RECV_DROPPED_MASK);

			XTemac_mBumpStats(RxRejectErrors, 1);
			ERR_HANDLER(XST_RECV_ERROR,
				    CorePending & XTE_IPXR_RECV_DROPPED_MASK,
				    0);

			/* no return here, nonfatal error */
		}
	}
}