/****************************************************************************** * * FUNCTION: * * IpIntrSelfTest * * DESCRIPTION: * * Perform a self test on the IP interrupt registers of the IPIF. This * function modifies registers of the IPIF such that they are not guaranteed * to be in the same state when it returns. Any bits in the IP interrupt * status register which are set are assumed to be set by default after a reset * and are not tested in the test. * * ARGUMENTS: * * InstancePtr points to the XIpIf to operate on. * * IpRegistersWidth contains the number of bits in the IP interrupt registers * of the device. The hardware is parameterizable such that only the number of * bits necessary to support a device are implemented. This value must be * between 0 and 32 with 0 indicating there are no IP interrupt registers used. * * RETURN VALUE: * * A status indicating XST_SUCCESS if the test was successful. Otherwise, one * of the following values is returned. * * XST_IPIF_RESET_REGISTER_ERROR The value of a register at reset was * not valid * XST_IPIF_IP_STATUS_ERROR A write to the IP interrupt status * register did not read back correctly * XST_IPIF_IP_ACK_ERROR One or more bits in the IP status * register did not reset when acked * XST_IPIF_IP_ENABLE_ERROR The IP interrupt enable register * did not read back correctly based upon * what was written to it * NOTES: * * None. * ******************************************************************************/ static XStatus IpIntrSelfTest(u32 RegBaseAddress, u32 IpRegistersWidth) { /* ensure that the IP interrupt interrupt enable register is zero * as it should be at reset, the interrupt status is dependent upon the * IP such that it's reset value is not known */ if (XIIF_V123B_READ_IIER(RegBaseAddress) != 0) { return XST_IPIF_RESET_REGISTER_ERROR; } /* if there are any used IP interrupts, then test all of the interrupt * bits in all testable registers */ if (IpRegistersWidth > 0) { u32 BitCount; u32 IpInterruptMask = XIIF_V123B_FIRST_BIT_MASK; u32 Mask = XIIF_V123B_FIRST_BIT_MASK; /* bits assigned MSB to LSB */ u32 InterruptStatus; /* generate the register masks to be used for IP register tests, the * number of bits supported by the hardware is parameterizable such * that only that number of bits are implemented in the registers, the * bits are allocated starting at the MSB of the registers */ for (BitCount = 1; BitCount < IpRegistersWidth; BitCount++) { Mask = Mask << 1; IpInterruptMask |= Mask; } /* get the current IP interrupt status register contents, any bits * already set must default to 1 at reset in the device and these * bits can't be tested in the following test, remove these bits from * the mask that was generated for the test */ InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress); IpInterruptMask &= ~InterruptStatus; /* set the bits in the device status register and verify them by reading * the register again, all bits of the register are latched */ XIIF_V123B_WRITE_IISR(RegBaseAddress, IpInterruptMask); InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress); if ((InterruptStatus & IpInterruptMask) != IpInterruptMask) { return XST_IPIF_IP_STATUS_ERROR; } /* test to ensure that the bits set in the IP interrupt status register * can be cleared by acknowledging them in the IP interrupt status * register then read it again and verify it was cleared */ XIIF_V123B_WRITE_IISR(RegBaseAddress, IpInterruptMask); InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress); if ((InterruptStatus & IpInterruptMask) != 0) { return XST_IPIF_IP_ACK_ERROR; } /* set the IP interrupt enable set register and then read the IP * interrupt enable register and verify the interrupts were enabled */ XIIF_V123B_WRITE_IIER(RegBaseAddress, IpInterruptMask); if (XIIF_V123B_READ_IIER(RegBaseAddress) != IpInterruptMask) { return XST_IPIF_IP_ENABLE_ERROR; } /* clear the IP interrupt enable register and then read the * IP interrupt enable register and verify the interrupts were disabled */ XIIF_V123B_WRITE_IIER(RegBaseAddress, 0); if (XIIF_V123B_READ_IIER(RegBaseAddress) != 0) { return XST_IPIF_IP_ENABLE_ERROR; } } return XST_SUCCESS; }
/* * * Check the interrupt status bits of the Ethernet MAC for errors. Errors * currently handled are: * - Receive length FIFO overrun. Indicates data was lost due to the receive * length FIFO becoming full during the reception of a packet. Only a device * reset clears this condition. * - Receive length FIFO underrun. An attempt to read an empty FIFO. Only a * device reset clears this condition. * - Transmit status FIFO overrun. Indicates data was lost due to the transmit * status FIFO becoming full following the transmission of a packet. Only a * device reset clears this condition. * - Transmit status FIFO underrun. An attempt to read an empty FIFO. Only a * device reset clears this condition. * - Transmit length FIFO overrun. Indicates data was lost due to the transmit * length FIFO becoming full following the transmission of a packet. Only a * device reset clears this condition. * - Transmit length FIFO underrun. An attempt to read an empty FIFO. Only a * device reset clears this condition. * - Receive data FIFO overrun. Indicates data was lost due to the receive data * FIFO becoming full during the reception of a packet. * - Receive data errors: * - Receive missed frame error. Valid data was lost by the MAC. * - Receive collision error. Data was lost by the MAC due to a collision. * - Receive FCS error. Data was dicarded by the MAC due to FCS error. * - Receive length field error. Data was dicarded by the MAC due to an invalid * length field in the packet. * - Receive short error. Data was dicarded by the MAC because a packet was * shorter than allowed. * - Receive long error. Data was dicarded by the MAC because a packet was * longer than allowed. * - Receive alignment error. Data was truncated by the MAC because its length * was not byte-aligned. * * @param InstancePtr is a pointer to the XEmac instance to be worked on. * @param IntrStatus is the contents of the interrupt status register to be checked * * @return * * None. * * @note * * This function is intended for internal use only. * ******************************************************************************/ void XEmac_CheckEmacError(XEmac * InstancePtr, u32 IntrStatus) { u32 ResetError = FALSE; /* * First check for receive fifo overrun/underrun errors. Most require a * reset by the user to clear, but the data FIFO overrun error does not. */ if (IntrStatus & XEM_EIR_RECV_DFIFO_OVER_MASK) { InstancePtr->Stats.RecvOverrunErrors++; InstancePtr->Stats.FifoErrors++; } if (IntrStatus & XEM_EIR_RECV_LFIFO_OVER_MASK) { /* * Receive Length FIFO overrun interrupts no longer occur in v1.00l * and later of the EMAC device. Frames are just dropped by the EMAC * if the length FIFO is full. The user would notice the Receive Missed * Frame count incrementing without any other errors being reported. * This code is left here for backward compatibility with v1.00k and * older EMAC devices. */ InstancePtr->Stats.RecvOverrunErrors++; InstancePtr->Stats.FifoErrors++; ResetError = TRUE; /* requires a reset */ } if (IntrStatus & XEM_EIR_RECV_LFIFO_UNDER_MASK) { InstancePtr->Stats.RecvUnderrunErrors++; InstancePtr->Stats.FifoErrors++; ResetError = TRUE; /* requires a reset */ } /* * Now check for general receive errors. Get the latest count where * available, otherwise just bump the statistic so we know the interrupt * occurred. */ if (IntrStatus & XEM_EIR_RECV_ERROR_MASK) { if (IntrStatus & XEM_EIR_RECV_MISSED_FRAME_MASK) { /* * Caused by length FIFO or data FIFO overruns on receive side */ InstancePtr->Stats.RecvMissedFrameErrors = XIo_In32(InstancePtr->BaseAddress + XEM_RMFC_OFFSET); } if (IntrStatus & XEM_EIR_RECV_COLLISION_MASK) { InstancePtr->Stats.RecvCollisionErrors = XIo_In32(InstancePtr->BaseAddress + XEM_RCC_OFFSET); } if (IntrStatus & XEM_EIR_RECV_FCS_ERROR_MASK) { InstancePtr->Stats.RecvFcsErrors = XIo_In32(InstancePtr->BaseAddress + XEM_RFCSEC_OFFSET); } if (IntrStatus & XEM_EIR_RECV_LEN_ERROR_MASK) { InstancePtr->Stats.RecvLengthFieldErrors++; } if (IntrStatus & XEM_EIR_RECV_SHORT_ERROR_MASK) { InstancePtr->Stats.RecvShortErrors++; } if (IntrStatus & XEM_EIR_RECV_LONG_ERROR_MASK) { InstancePtr->Stats.RecvLongErrors++; } if (IntrStatus & XEM_EIR_RECV_ALIGN_ERROR_MASK) { InstancePtr->Stats.RecvAlignmentErrors = XIo_In32(InstancePtr->BaseAddress + XEM_RAEC_OFFSET); } /* * Bump recv interrupts stats only if not scatter-gather DMA (this * stat gets bumped elsewhere in that case) */ if (!XEmac_mIsSgDma(InstancePtr)) { InstancePtr->Stats.RecvInterrupts++; /* TODO: double bump? */ } } /* * Check for transmit errors. These apply to both DMA and non-DMA modes * of operation. The entire device should be reset after overruns or * underruns. */ if (IntrStatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK | XEM_EIR_XMIT_LFIFO_OVER_MASK)) { InstancePtr->Stats.XmitOverrunErrors++; InstancePtr->Stats.FifoErrors++; ResetError = TRUE; } if (IntrStatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK | XEM_EIR_XMIT_LFIFO_UNDER_MASK)) { InstancePtr->Stats.XmitUnderrunErrors++; InstancePtr->Stats.FifoErrors++; ResetError = TRUE; } if (ResetError) { /* * If a reset error occurred, disable the EMAC interrupts since the * reset-causing interrupt(s) is latched in the EMAC - meaning it will * keep occurring until the device is reset. In order to give the higher * layer software time to reset the device, we have to disable the * overrun/underrun interrupts until that happens. We trust that the * higher layer resets the device. We are able to get away with disabling * all EMAC interrupts since the only interrupts it generates are for * error conditions, and we don't care about any more errors right now. */ XIIF_V123B_WRITE_IIER(InstancePtr->BaseAddress, 0); /* * Invoke the error handler callback, which should result in a reset * of the device by the upper layer software. */ InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XST_RESET_ERROR); } }