我联系了客户支持中心、他们要求我将其发布在这里。
今年早些时候、用于 C 系列的 TivaWare 软件(使用版本2.1.4.178)中出现 UDP 传输问题、
但在版本2.2.0.295中似乎也没有对其进行修正。
此症状是由于数据碎片超过 MTU 大小而导致的。
具体而言、CRC 错误发生在数据接收端、数据似乎已部分损坏。
我猜问题是下面的功能。
(路径:third_parti\lwip-1.4.1\ports\Tiva-tm4c129\netif\Tiva-tm4c129.c)static err_t tivaif_transmit(struct netif *psNetif, struct pbuf *p) { tStellarisIF *pIF; tDescriptor *pDesc; struct pbuf *pBuf; uint32_t ui32NumChained, ui32NumDescs; bool bFirst; SYS_ARCH_DECL_PROTECT(lev); LWIP_DEBUGF(NETIF_DEBUG, ("tivaif_transmit 0x%08x, len %d\n", p, p->tot_len)); /** * This entire function must run within a "critical section" to preserve * the integrity of the transmit pbuf queue. */ SYS_ARCH_PROTECT(lev); /* Update our transmit attempt counter. */ DRIVER_STATS_INC(TXCount); /** * Increase the reference count on the packet provided so that we can * hold on to it until we are finished transmitting its content. */ pbuf_ref(p); /** * Determine whether all buffers passed are within SRAM and, if not, copy * the pbuf into SRAM-resident buffers so that the Ethernet DMA can access * the data. */ p = tivaif_check_pbuf(p); /* Make sure we still have a valid buffer (it may have been copied) */ if(!p) { LINK_STATS_INC(link.memerr); SYS_ARCH_UNPROTECT(lev); return(ERR_MEM); } /* Get our state data from the netif structure we were passed. */ pIF = (tStellarisIF *)psNetif->state; /* Make sure that the transmit descriptors are not all in use */ pDesc = &(pIF->pTxDescList->pDescriptors[pIF->pTxDescList->ui32Write]); if(pDesc->pBuf) { /** * The current write descriptor has a pbuf attached to it so this * implies that the ring is full. Reject this transmit request with a * memory error since we can't satisfy it just now. */ pbuf_free(p); LINK_STATS_INC(link.memerr); DRIVER_STATS_INC(TXNoDescCount); SYS_ARCH_UNPROTECT(lev); return (ERR_MEM); } /* How many pbufs are in the chain passed? */ ui32NumChained = (uint32_t)pbuf_clen(p); /* How many free transmit descriptors do we have? */ ui32NumDescs = (pIF->pTxDescList->ui32Read > pIF->pTxDescList->ui32Write) ? (pIF->pTxDescList->ui32Read - pIF->pTxDescList->ui32Write) : ((NUM_TX_DESCRIPTORS - pIF->pTxDescList->ui32Write) + pIF->pTxDescList->ui32Read); /* Do we have enough free descriptors to send the whole packet? */ if(ui32NumDescs < ui32NumChained) { /* No - we can't transmit this whole packet so return an error. */ pbuf_free(p); LINK_STATS_INC(link.memerr); DRIVER_STATS_INC(TXNoDescCount); SYS_ARCH_UNPROTECT(lev); return (ERR_MEM); } /* Tag the first descriptor as the start of the packet. */ bFirst = true; pDesc->Desc.ui32CtrlStatus = DES0_TX_CTRL_FIRST_SEG; /* Here, we know we can send the packet so write it to the descriptors */ pBuf = p; while(ui32NumChained) { /* Get a pointer to the descriptor we will write next. */ pDesc = &(pIF->pTxDescList->pDescriptors[pIF->pTxDescList->ui32Write]); /* Fill in the buffer pointer and length */ pDesc->Desc.ui32Count = (uint32_t)pBuf->len; pDesc->Desc.pvBuffer1 = pBuf->payload; /* Tag the first descriptor as the start of the packet. */ if(bFirst) { bFirst = false; pDesc->Desc.ui32CtrlStatus = DES0_TX_CTRL_FIRST_SEG; } else { pDesc->Desc.ui32CtrlStatus = 0; } pDesc->Desc.ui32CtrlStatus |= (DES0_TX_CTRL_IP_ALL_CKHSUMS | DES0_TX_CTRL_CHAINED); /* Decrement our descriptor counter, move on to the next buffer in the * pbuf chain. */ ui32NumChained--; pBuf = pBuf->next; /* Update the descriptor list write index. */ pIF->pTxDescList->ui32Write++; if(pIF->pTxDescList->ui32Write == NUM_TX_DESCRIPTORS) { pIF->pTxDescList->ui32Write = 0; } /* If this is the last descriptor, mark it as the end of the packet. */ if(!ui32NumChained) { pDesc->Desc.ui32CtrlStatus |= (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_INTERRUPT); /* Tag the descriptor with the original pbuf pointer. */ pDesc->pBuf = p; } else { /* Set the lsb of the pbuf pointer. We use this as a signal that * we should not free the pbuf when we are walking the descriptor * list while processing the transmit interrupt. We only free the * pbuf when processing the last descriptor used to transmit its * chain. */ pDesc->pBuf = (struct pbuf *)((uint32_t)p + 1); } DRIVER_STATS_INC(TXBufQueuedCount); /* Hand the descriptor over to the hardware. */ pDesc->Desc.ui32CtrlStatus |= DES0_TX_CTRL_OWN; } /* Tell the transmitter to start (in case it had stopped). */ EMACTxDMAPollDemand(EMAC0_BASE); /* Update lwIP statistics */ LINK_STATS_INC(link.xmit); SYS_ARCH_UNPROTECT(lev); return(ERR_OK); }
我们修改了以下函数并确认了正常运行。
更正后的行为103和110。static err_t if_transmit(struct netif *psNetif, struct pbuf *p) { tStellarisIF *pIF; tDescriptor *pDesc; struct pbuf *pBuf; uint32_t ui32NumChained, ui32NumDescs; bool bFirst; SYS_ARCH_DECL_PROTECT(lev); LWIP_DEBUGF(NETIF_DEBUG, ("tivaif_transmit 0x%08x, len %d\n", p, p->tot_len)); /** * This entire function must run within a "critical section" to preserve * the integrity of the transmit pbuf queue. */ SYS_ARCH_PROTECT(lev); /* Update our transmit attempt counter. */ DRIVER_STATS_INC(TXCount); /** * Increase the reference count on the packet provided so that we can * hold on to it until we are finished transmitting its content. */ pbuf_ref(p); /** * Determine whether all buffers passed are within SRAM and, if not, copy * the pbuf into SRAM-resident buffers so that the Ethernet DMA can access * the data. */ p = tivaif_check_pbuf(p); /* Make sure we still have a valid buffer (it may have been copied) */ if(!p) { LINK_STATS_INC(link.memerr); SYS_ARCH_UNPROTECT(lev); return(ERR_MEM); } /* Get our state data from the netif structure we were passed. */ pIF = (tStellarisIF *)psNetif->state; /* Make sure that the transmit descriptors are not all in use */ pDesc = &(pIF->pTxDescList->pDescriptors[pIF->pTxDescList->ui32Write]); if(pDesc->pBuf) { /** * The current write descriptor has a pbuf attached to it so this * implies that the ring is full. Reject this transmit request with a * memory error since we can't satisfy it just now. */ pbuf_free(p); LINK_STATS_INC(link.memerr); DRIVER_STATS_INC(TXNoDescCount); SYS_ARCH_UNPROTECT(lev); return (ERR_MEM); } /* How many pbufs are in the chain passed? */ ui32NumChained = (uint32_t)pbuf_clen(p); /* How many free transmit descriptors do we have? */ ui32NumDescs = (pIF->pTxDescList->ui32Read > pIF->pTxDescList->ui32Write) ? (pIF->pTxDescList->ui32Read - pIF->pTxDescList->ui32Write) : ((NUM_TX_DESCRIPTORS - pIF->pTxDescList->ui32Write) + pIF->pTxDescList->ui32Read); /* Do we have enough free descriptors to send the whole packet? */ if(ui32NumDescs < ui32NumChained) { /* No - we can't transmit this whole packet so return an error. */ pbuf_free(p); LINK_STATS_INC(link.memerr); DRIVER_STATS_INC(TXNoDescCount); SYS_ARCH_UNPROTECT(lev); return (ERR_MEM); } /* Tag the first descriptor as the start of the packet. */ bFirst = true; pDesc->Desc.ui32CtrlStatus = DES0_TX_CTRL_FIRST_SEG; /* Here, we know we can send the packet so write it to the descriptors */ pBuf = p; while(ui32NumChained) { /* Get a pointer to the descriptor we will write next. */ pDesc = &(pIF->pTxDescList->pDescriptors[pIF->pTxDescList->ui32Write]); /* Fill in the buffer pointer and length */ pDesc->Desc.ui32Count = (uint32_t)pBuf->len; pDesc->Desc.pvBuffer1 = pBuf->payload; /* Tag the first descriptor as the start of the packet. */ if(bFirst) { bFirst = false; pDesc->Desc.ui32CtrlStatus = (DES0_TX_CTRL_FIRST_SEG | DES0_TX_CTRL_IP_ALL_CKHSUMS); } else { pDesc->Desc.ui32CtrlStatus = 0; } pDesc->Desc.ui32CtrlStatus |= (//DES0_TX_CTRL_IP_ALL_CKHSUMS | DES0_TX_CTRL_CHAINED); /* Decrement our descriptor counter, move on to the next buffer in the * pbuf chain. */ ui32NumChained--; pBuf = pBuf->next; /* Update the descriptor list write index. */ pIF->pTxDescList->ui32Write++; if(pIF->pTxDescList->ui32Write == NUM_TX_DESCRIPTORS) { pIF->pTxDescList->ui32Write = 0; } /* If this is the last descriptor, mark it as the end of the packet. */ if(!ui32NumChained) { pDesc->Desc.ui32CtrlStatus |= (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_INTERRUPT); /* Tag the descriptor with the original pbuf pointer. */ pDesc->pBuf = p; } else { /* Set the lsb of the pbuf pointer. We use this as a signal that * we should not free the pbuf when we are walking the descriptor * list while processing the transmit interrupt. We only free the * pbuf when processing the last descriptor used to transmit its * chain. */ pDesc->pBuf = (struct pbuf *)((uint32_t)p + 1); } DRIVER_STATS_INC(TXBufQueuedCount); /* Hand the descriptor over to the hardware. */ pDesc->Desc.ui32CtrlStatus |= DES0_TX_CTRL_OWN; } /* Tell the transmitter to start (in case it had stopped). */ EMACTxDMAPollDemand(EMAC0_BASE); /* Update lwIP statistics */ LINK_STATS_INC(link.xmit); SYS_ARCH_UNPROTECT(lev); return(ERR_OK); }
芯片仅实现了 UDP、因此未测试其他协议。
请审查可行性。
感谢您的支持。

