nuttx/mm/iob/iob_update_pktlen.c
zhanghongyu b934555fd1 mm/iob: Support alloc IOB via malloc
Support the network interface card driver to receive zero copies of packets and send and receive giant frame packets, allowing drivers to initialize the DMA buffer to the iob structure, and we can apply for IOB with large memory

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
2024-04-26 01:06:21 +08:00

161 lines
4.1 KiB
C

/****************************************************************************
* mm/iob/iob_update_pktlen.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/mm/iob.h>
#include "iob.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: iob_update_pktlen
*
* Description:
* This function will update packet length of the iob, it will be
* trimmed if the current length of the iob chain is greater than the
* new length, and will be grown if less than new length.
*
* Returned Value:
* The new effective iob packet length, or a negated errno value on error.
*
****************************************************************************/
int iob_update_pktlen(FAR struct iob_s *iob, unsigned int pktlen,
bool throttled)
{
FAR struct iob_s *penultimate;
FAR struct iob_s *next;
int remain = pktlen;
int ninqueue = 0;
int nrequire = 0;
uint16_t len;
/* The data offset must be less than CONFIG_IOB_BUFSIZE */
if (iob == NULL)
{
return -EINVAL;
}
/* Calculate the total entries of the data in the I/O buffer chain */
next = iob;
while (next != NULL)
{
ninqueue++;
penultimate = next;
if (remain > 0)
{
nrequire++;
remain -= IOB_BUFSIZE(next) - next->io_offset;
}
next = next->io_flink;
}
if (remain > 0)
{
nrequire += (remain + CONFIG_IOB_BUFSIZE - 1) / CONFIG_IOB_BUFSIZE;
}
if (nrequire == 0)
{
nrequire = 1;
}
/* Trim inqueue entries if needed */
if (nrequire < ninqueue)
{
/* Loop until complete the trim */
next = iob;
penultimate = NULL;
while (next != NULL)
{
if (nrequire-- <= 0)
{
if (penultimate != NULL)
{
penultimate->io_flink = NULL;
}
iob_free_chain(next);
break;
}
else
{
penultimate = next;
next = next->io_flink;
}
}
}
else if (nrequire > ninqueue)
{
/* Start from the last IOB */
next = penultimate;
/* Loop to extend the link */
while (next != NULL && nrequire > ninqueue)
{
next->io_flink = iob_tryalloc(throttled);
next = next->io_flink;
ninqueue++;
}
}
iob->io_pktlen = pktlen;
/* Update size of each iob */
next = iob;
while (next != NULL && pktlen > 0)
{
if (pktlen + next->io_offset > IOB_BUFSIZE(next))
{
len = IOB_BUFSIZE(next) - next->io_offset;
}
else
{
len = pktlen;
}
next->io_len = len;
pktlen -= len;
next = next->io_flink;
}
/* Adjust final pktlen if it's not fully increased (e.g. alloc fail) */
iob->io_pktlen -= pktlen;
return iob->io_pktlen;
}