zynq unable to alloc pbuf in recv_handler

原文地址:https://blog.csdn.net/qq_21748131/article/details/123038734

zynq解决使用LWIP时报错unable to alloc pbuf in recv_handler错误
错误原因
错误原因
解决办法
总结
在使用LWIP时候zynq的SDK范例运行非常正常,但是在此基础上增加别的协议栈时容易发生unable to alloc pbuf in recv_handler错误。

错误原因
1:这个错误在setup_rx_bds函数中发生,该函数功能是释放DMA的空闲bd块和传递以太网数据包。setup_rx_bds在emacps_recv_handler函数中调用。

void setup_rx_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *rxring)
{
    XEmacPs_Bd *rxbd;
    XStatus status;
    struct pbuf *p;
    u32_t freebds;
    u32_t bdindex;
    u32 *temp;
    u32_t index;

    index = get_base_index_rxpbufsstorage (xemacpsif);

    freebds = XEmacPs_BdRingGetFreeCnt (rxring);
    while (freebds > 0) {
        freebds--;
#ifdef ZYNQMP_USE_JUMBO
        p = pbuf_alloc(PBUF_RAW, MAX_FRAME_SIZE_JUMBO, PBUF_POOL);
#else
        p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
#endif
        if (!p) {
#if LINK_STATS
            lwip_stats.link.memerr++;
            lwip_stats.link.drop++;
#endif
            printf("unable to alloc pbuf in recv_handler\r\n");  
            return;
        }
        status = XEmacPs_BdRingAlloc(rxring, 1, &rxbd);
        if (status != XST_SUCCESS) {
            LWIP_DEBUGF(NETIF_DEBUG, ("setup_rx_bds: Error allocating RxBD\r\n"));
            pbuf_free(p);
            return;
        }
        status = XEmacPs_BdRingToHw(rxring, 1, rxbd);
        if (status != XST_SUCCESS) {
            LWIP_DEBUGF(NETIF_DEBUG, ("Error committing RxBD to hardware: "));
            if (status == XST_DMA_SG_LIST_ERROR) {
                LWIP_DEBUGF(NETIF_DEBUG, ("XST_DMA_SG_LIST_ERROR: this function was called out of sequence with XEmacPs_BdRingAlloc()\r\n"));
            }
            else {
                LWIP_DEBUGF(NETIF_DEBUG, ("set of BDs was rejected because the first BD did not have its start-of-packet bit set, or the last BD did not have its end-of-packet bit set, or any one of the BD set has 0 as length value\r\n"));
            }

            pbuf_free(p);
            XEmacPs_BdRingUnAlloc(rxring, 1, rxbd);
            return;
        }
#ifdef ZYNQMP_USE_JUMBO
        if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
            Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)MAX_FRAME_SIZE_JUMBO);
        }
#else
        if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
            Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)XEMACPS_MAX_FRAME_SIZE);
        }
#endif
        bdindex = XEMACPS_BD_TO_INDEX(rxring, rxbd);
        temp = (u32 *)rxbd;
        if (bdindex == (XLWIP_CONFIG_N_RX_DESC - 1)) {
            *temp = 0x00000002;
        } else {
            *temp = 0;
        }
        temp++;
        *temp = 0;
        dsb();

        XEmacPs_BdSetAddressRx(rxbd, (UINTPTR)p->payload);
        rx_pbufs_storage[index + bdindex] = (UINTPTR)p;
    }
}


错误发生在 printf(“unable to alloc pbuf in recv_handler\r\n”); 这个地方,是申请pbuf失败。
网上最多查到的办法是增大pbuf部分的内存,例如 MEM_SIZE, MEMP_NUM_PBUF, PBUF_POOL_SIZE.这些参数。但是使用LWIP范例时候同样的用法为什么不会报错呢?我们再分析一下进入emacps_recv_handler函数分析一下。

错误原因
2:emacps_recv_handler函数是DMA函数的回调函数,以太网DMA收到数据包时候将会调用该函数。

void emacps_recv_handler(void *arg)
{
    struct pbuf *p;
    XEmacPs_Bd *rxbdset, *curbdptr;
    struct xemac_s *xemac;
    xemacpsif_s *xemacpsif;
    XEmacPs_BdRing *rxring;
    volatile s32_t bd_processed;
    s32_t rx_bytes, k;
    u32_t bdindex;
    u32_t regval;
    u32_t index;
    u32_t gigeversion;

    xemac = (struct xemac_s *)(arg);
    xemacpsif = (xemacpsif_s *)(xemac->state);
    rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);

#ifdef OS_IS_FREERTOS
    xInsideISR++;
#endif

    gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
    index = get_base_index_rxpbufsstorage (xemacpsif);
    /*
     * If Reception done interrupt is asserted, call RX call back function
     * to handle the processed BDs and then raise the according flag.
     */
    regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET);
    XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET, regval);
    if (gigeversion <= 2) {
            resetrx_on_no_rxdata(xemacpsif);
    }
//
    while(1) {

        bd_processed = XEmacPs_BdRingFromHwRx(rxring, XLWIP_CONFIG_N_RX_DESC, &rxbdset);
        if (bd_processed <= 0) {
            break;
        }

        for (k = 0, curbdptr=rxbdset; k < bd_processed; k++) {

            bdindex = XEMACPS_BD_TO_INDEX(rxring, curbdptr);
            p = (struct pbuf *)rx_pbufs_storage[index + bdindex];

            /*
             * Adjust the buffer size to the actual number of bytes received.
             */
#ifdef ZYNQMP_USE_JUMBO
            rx_bytes = XEmacPs_GetRxFrameSize(&xemacpsif->emacps, curbdptr);
#else
            rx_bytes = XEmacPs_BdGetLength(curbdptr);
#endif
            pbuf_realloc(p, rx_bytes);

            /* store it in the receive queue,
             * where it'll be processed by a different handler
             */
            if (pq_enqueue(xemacpsif->recv_q, (void*)p) < 0) {
#if LINK_STATS
                lwip_stats.link.memerr++;
                lwip_stats.link.drop++;
#endif
                pbuf_free(p);
            }
            curbdptr = XEmacPs_BdRingNext( rxring, curbdptr);
        }
        /* free up the BD's */
        XEmacPs_BdRingFree(rxring, bd_processed, rxbdset);
        setup_rx_bds(xemacpsif, rxring);  //函数在这里调用
#if !NO_SYS
        sys_sem_signal(&xemac->sem_rx_data_available);
#endif
    }

#ifdef OS_IS_FREERTOS
    xInsideISR--;
#endif
    return;
}


我们看到调用setup_rx_bds(xemacpsif, rxring); 的时候是在循环中使用。这样会多次调用他导致重复的释放db块,然后引起FreeCnt计数错误,发生错误后每次都增加FreeCnt的计数器。

解决办法
所以我们把setup_rx_bds(xemacpsif, rxring); 放到while循环外,避免多次调用导致可能的错误计数发生。

    while(1) {

        bd_processed = XEmacPs_BdRingFromHwRx(rxring, XLWIP_CONFIG_N_RX_DESC, &rxbdset);
        if (bd_processed <= 0) {
            break;
        }

        for (k = 0, curbdptr=rxbdset; k < bd_processed; k++) {

            bdindex = XEMACPS_BD_TO_INDEX(rxring, curbdptr);
            p = (struct pbuf *)rx_pbufs_storage[index + bdindex];

            /*
             * Adjust the buffer size to the actual number of bytes received.
             */
#ifdef ZYNQMP_USE_JUMBO
            rx_bytes = XEmacPs_GetRxFrameSize(&xemacpsif->emacps, curbdptr);
#else
            rx_bytes = XEmacPs_BdGetLength(curbdptr);
#endif
            pbuf_realloc(p, rx_bytes);

            /* store it in the receive queue,
             * where it'll be processed by a different handler
             */
            if (pq_enqueue(xemacpsif->recv_q, (void*)p) < 0) {
#if LINK_STATS
                lwip_stats.link.memerr++;
                lwip_stats.link.drop++;
#endif
                pbuf_free(p);
            }
            curbdptr = XEmacPs_BdRingNext( rxring, curbdptr);
        }
        /* free up the BD's */
        XEmacPs_BdRingFree(rxring, bd_processed, rxbdset);
//        setup_rx_bds(xemacpsif, rxring);  //函数在这里调用
#if !NO_SYS
        sys_sem_signal(&xemac->sem_rx_data_available);
#endif
    }
        setup_rx_bds(xemacpsif, rxring);  //放到这里
#ifdef OS_IS_FREERTOS
    xInsideISR--;
#endif
    return;
}

警告测试这样放置后解决该问题。

总结
所以解决他的两种方法:
1:参考Xlinx社区方法增大内存但是我试了试好像不管用 lwIP netif: ‘unable to alloc pbuf in recv_handler’ message
2:就是我们在循环外调用setup_rx_bds的方法
————————————————
版权声明:本文为CSDN博主「qq_21748131」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_21748131/article/details/123038734

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值