rndis: support iob offload

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2023-02-14 17:16:46 +08:00 committed by Xiang Xiao
parent 51c30289ae
commit 16ea80e53b
7 changed files with 146 additions and 38 deletions

View File

@ -97,6 +97,7 @@ CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_PKTSIZE=1514 CONFIG_NET_ETH_PKTSIZE=1514
CONFIG_NET_ICMP=y CONFIG_NET_ICMP=y
CONFIG_NET_ICMP_SOCKET=y CONFIG_NET_ICMP_SOCKET=y
CONFIG_NET_LL_GUARDSIZE=50
CONFIG_NET_LOOPBACK=y CONFIG_NET_LOOPBACK=y
CONFIG_NET_PKT=y CONFIG_NET_PKT=y
CONFIG_NET_ROUTE=y CONFIG_NET_ROUTE=y

View File

@ -97,6 +97,7 @@ CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_PKTSIZE=1514 CONFIG_NET_ETH_PKTSIZE=1514
CONFIG_NET_ICMP=y CONFIG_NET_ICMP=y
CONFIG_NET_ICMP_SOCKET=y CONFIG_NET_ICMP_SOCKET=y
CONFIG_NET_LL_GUARDSIZE=50
CONFIG_NET_LOOPBACK=y CONFIG_NET_LOOPBACK=y
CONFIG_NET_PKT=y CONFIG_NET_PKT=y
CONFIG_NET_ROUTE=y CONFIG_NET_ROUTE=y

View File

@ -52,6 +52,7 @@ CONFIG_NETUTILS_TELNETD=y
CONFIG_NET_ARP_SEND=y CONFIG_NET_ARP_SEND=y
CONFIG_NET_BROADCAST=y CONFIG_NET_BROADCAST=y
CONFIG_NET_ICMP=y CONFIG_NET_ICMP=y
CONFIG_NET_LL_GUARDSIZE=50
CONFIG_NET_LOOPBACK=y CONFIG_NET_LOOPBACK=y
CONFIG_NET_SOCKOPTS=y CONFIG_NET_SOCKOPTS=y
CONFIG_NET_STATISTICS=y CONFIG_NET_STATISTICS=y

View File

@ -100,6 +100,7 @@ CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_PKTSIZE=1500 CONFIG_NET_ETH_PKTSIZE=1500
CONFIG_NET_ICMP=y CONFIG_NET_ICMP=y
CONFIG_NET_ICMP_SOCKET=y CONFIG_NET_ICMP_SOCKET=y
CONFIG_NET_LL_GUARDSIZE=50
CONFIG_NET_LOOPBACK=y CONFIG_NET_LOOPBACK=y
CONFIG_NET_PKT=y CONFIG_NET_PKT=y
CONFIG_NET_ROUTE=y CONFIG_NET_ROUTE=y

View File

@ -97,6 +97,7 @@ CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_PKTSIZE=1514 CONFIG_NET_ETH_PKTSIZE=1514
CONFIG_NET_ICMP=y CONFIG_NET_ICMP=y
CONFIG_NET_ICMP_SOCKET=y CONFIG_NET_ICMP_SOCKET=y
CONFIG_NET_LL_GUARDSIZE=50
CONFIG_NET_LOOPBACK=y CONFIG_NET_LOOPBACK=y
CONFIG_NET_PKT=y CONFIG_NET_PKT=y
CONFIG_NET_ROUTE=y CONFIG_NET_ROUTE=y

View File

@ -53,6 +53,7 @@ CONFIG_NET_ARP_SEND=y
CONFIG_NET_BROADCAST=y CONFIG_NET_BROADCAST=y
CONFIG_NET_ICMP=y CONFIG_NET_ICMP=y
CONFIG_NET_ICMP_SOCKET=y CONFIG_NET_ICMP_SOCKET=y
CONFIG_NET_LL_GUARDSIZE=50
CONFIG_NET_LOOPBACK=y CONFIG_NET_LOOPBACK=y
CONFIG_NET_STATISTICS=y CONFIG_NET_STATISTICS=y
CONFIG_NET_TCP=y CONFIG_NET_TCP=y

View File

@ -70,6 +70,14 @@
(CONFIG_NET_ETH_PKTSIZE + CONFIG_NET_GUARDSIZE + RNDIS_PACKET_HDR_SIZE) (CONFIG_NET_ETH_PKTSIZE + CONFIG_NET_GUARDSIZE + RNDIS_PACKET_HDR_SIZE)
#define CONFIG_RNDIS_BULKOUT_REQLEN CONFIG_RNDIS_BULKIN_REQLEN #define CONFIG_RNDIS_BULKOUT_REQLEN CONFIG_RNDIS_BULKIN_REQLEN
static_assert(CONFIG_NET_LL_GUARDSIZE >= RNDIS_PACKET_HDR_SIZE + ETH_HDRLEN,
"CONFIG_NET_LL_GUARDSIZE cannot be less than ETH_HDRLEN"
" + RNDIS_PACKET_HDR_SIZE");
static_assert((CONFIG_NET_LL_GUARDSIZE % 4) == 2,
"CONFIG_NET_LL_GUARDSIZE - ETH_HDRLEN "
"should be aligned to 4 bytes");
#define RNDIS_NCONFIGS (1) #define RNDIS_NCONFIGS (1)
#define RNDIS_CONFIGID (1) #define RNDIS_CONFIGID (1)
#define RNDIS_CONFIGIDNONE (0) #define RNDIS_CONFIGIDNONE (0)
@ -108,6 +116,8 @@ struct rndis_req_s
{ {
FAR struct rndis_req_s *flink; /* Implements a singly linked list */ FAR struct rndis_req_s *flink; /* Implements a singly linked list */
FAR struct usbdev_req_s *req; /* The contained request */ FAR struct usbdev_req_s *req; /* The contained request */
FAR struct iob_s *iob; /* IOB offload */
FAR uint8_t *buf; /* Use malloc buffer when config IOB_LEN < CONFIG_RNDIS_BULKIN_REQLEN */
}; };
/* This structure describes the internal state of the driver */ /* This structure describes the internal state of the driver */
@ -632,6 +642,14 @@ static void rndis_freewrreq(FAR struct rndis_dev_s *priv,
FAR struct rndis_req_s *req) FAR struct rndis_req_s *req)
{ {
DEBUGASSERT(req != NULL); DEBUGASSERT(req != NULL);
if (req->iob)
{
/* In ep submit case, need release iob chain when write complete */
iob_free_chain(req->iob);
req->iob = NULL;
}
sq_addlast((FAR sq_entry_t *)req, &priv->reqlist); sq_addlast((FAR sq_entry_t *)req, &priv->reqlist);
rndis_submit_rdreq(priv); rndis_submit_rdreq(priv);
} }
@ -665,11 +683,6 @@ static bool rndis_allocnetreq(FAR struct rndis_dev_s *priv)
} }
priv->net_req = rndis_allocwrreq(priv); priv->net_req = rndis_allocwrreq(priv);
if (priv->net_req)
{
priv->netdev.d_buf = &priv->net_req->req->buf[RNDIS_PACKET_HDR_SIZE];
priv->netdev.d_len = CONFIG_NET_ETH_PKTSIZE;
}
leave_critical_section(flags); leave_critical_section(flags);
return priv->net_req != NULL; return priv->net_req != NULL;
@ -699,8 +712,6 @@ static void rndis_sendnetreq(FAR struct rndis_dev_s *priv)
EP_SUBMIT(priv->epbulkin, priv->net_req->req); EP_SUBMIT(priv->epbulkin, priv->net_req->req);
priv->net_req = NULL; priv->net_req = NULL;
priv->netdev.d_buf = NULL;
priv->netdev.d_len = 0;
leave_critical_section(flags); leave_critical_section(flags);
} }
@ -724,11 +735,55 @@ static void rndis_freenetreq(FAR struct rndis_dev_s *priv)
rndis_freewrreq(priv, priv->net_req); rndis_freewrreq(priv, priv->net_req);
priv->net_req = NULL; priv->net_req = NULL;
priv->netdev.d_buf = NULL;
priv->netdev.d_len = 0;
leave_critical_section(flags); leave_critical_section(flags);
} }
/****************************************************************************
* Name: rndis_iob2buf
*
* Description:
* Map the appropriate location of req iob to buf.
*
* Input Parameters:
* priv: pointer to RNDIS device driver structure
* req: the request whose buffer we should fill
* Assumptions:
* Caller holds the network lock
*
****************************************************************************/
static void rndis_iob2buf(FAR struct rndis_dev_s *priv,
FAR struct rndis_req_s *req)
{
uint16_t llhdrlen = NET_LL_HDRLEN(&priv->netdev);
uint32_t offset = CONFIG_NET_LL_GUARDSIZE - llhdrlen -
RNDIS_PACKET_HDR_SIZE;
/* ----------------------------------------------------------------
* |<--- CONFIG_NET_LL_GUARDSIZE ---->|<-- io_len/io_pktlen(0) -->|
* ---------------------------------------------------------------|
* |unused | rndis hdr size |llhdrlen |<-- io_len/io_pktlen(0) -->|
* ---------------------------------------------------------------|
* |unused | req->buf(0) |
* ---------------------------------------------------------------|
*/
if (req->iob->io_flink == NULL)
{
req->req->buf = &req->iob->io_data[offset];
req->req->len = CONFIG_RNDIS_BULKIN_REQLEN;
}
else
{
req->req->buf = req->buf;
iob_copyout(&req->req->buf[RNDIS_PACKET_HDR_SIZE], req->iob,
req->iob->io_pktlen + llhdrlen, -llhdrlen);
iob_free_chain(req->iob);
req->iob = NULL;
}
}
/**************************************************************************** /****************************************************************************
* Name: rndis_allocrxreq * Name: rndis_allocrxreq
* *
@ -748,13 +803,33 @@ static void rndis_freenetreq(FAR struct rndis_dev_s *priv)
static bool rndis_allocrxreq(FAR struct rndis_dev_s *priv) static bool rndis_allocrxreq(FAR struct rndis_dev_s *priv)
{ {
FAR struct iob_s *iob;
if (priv->rx_req != NULL) if (priv->rx_req != NULL)
{ {
return true; return true;
} }
priv->rx_req = rndis_allocwrreq(priv); /* Prepare buffer to receivce data from usb driver */
return priv->rx_req != NULL;
iob = iob_tryalloc(false);
if (iob == NULL)
{
return false;
}
iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE);
if ((priv->rx_req = rndis_allocwrreq(priv)) == NULL)
{
iob_free_chain(iob);
return false;
}
priv->rx_req->iob = iob;
rndis_iob2buf(priv, priv->rx_req);
return true;
} }
/**************************************************************************** /****************************************************************************
@ -777,9 +852,15 @@ static void rndis_giverxreq(FAR struct rndis_dev_s *priv)
DEBUGASSERT(priv->net_req == NULL); DEBUGASSERT(priv->net_req == NULL);
priv->net_req = priv->rx_req; priv->net_req = priv->rx_req;
priv->netdev.d_buf = &priv->net_req->req->buf[RNDIS_PACKET_HDR_SIZE];
priv->netdev.d_len = CONFIG_NET_ETH_PKTSIZE;
priv->rx_req = NULL; priv->rx_req = NULL;
/* Move iob from net_req to netdev */
netdev_iob_release(&priv->netdev);
priv->netdev.d_iob = priv->net_req->iob;
priv->netdev.d_len = priv->net_req->iob->io_pktlen;
priv->net_req->iob = NULL;
} }
/**************************************************************************** /****************************************************************************
@ -801,20 +882,23 @@ static void rndis_giverxreq(FAR struct rndis_dev_s *priv)
****************************************************************************/ ****************************************************************************/
static uint16_t rndis_fillrequest(FAR struct rndis_dev_s *priv, static uint16_t rndis_fillrequest(FAR struct rndis_dev_s *priv,
FAR struct usbdev_req_s *req) FAR struct rndis_req_s *req)
{ {
size_t datalen; size_t datalen;
req->len = 0; req->req->len = 0;
datalen = MIN(priv->netdev.d_len, datalen = MIN(priv->netdev.d_len,
CONFIG_RNDIS_BULKIN_REQLEN - RNDIS_PACKET_HDR_SIZE); CONFIG_RNDIS_BULKIN_REQLEN - RNDIS_PACKET_HDR_SIZE);
if (datalen > 0) if (datalen > 0)
{ {
/* Send the required headers */ /* Move iob from netdev to net_req and send the required headers */
req->iob = priv->netdev.d_iob;
netdev_iob_clear(&priv->netdev);
rndis_iob2buf(priv, req);
FAR struct rndis_packet_msg *msg = FAR struct rndis_packet_msg *msg =
(FAR struct rndis_packet_msg *)req->buf; (FAR struct rndis_packet_msg *)req->req->buf;
memset(msg, 0, RNDIS_PACKET_HDR_SIZE); memset(msg, 0, RNDIS_PACKET_HDR_SIZE);
msg->msgtype = RNDIS_PACKET_MSG; msg->msgtype = RNDIS_PACKET_MSG;
@ -822,11 +906,11 @@ static uint16_t rndis_fillrequest(FAR struct rndis_dev_s *priv,
msg->dataoffset = RNDIS_PACKET_HDR_SIZE - 8; msg->dataoffset = RNDIS_PACKET_HDR_SIZE - 8;
msg->datalen = datalen; msg->datalen = datalen;
req->flags = USBDEV_REQFLAGS_NULLPKT; req->req->flags = USBDEV_REQFLAGS_NULLPKT;
req->len = datalen + RNDIS_PACKET_HDR_SIZE; req->req->len = datalen + RNDIS_PACKET_HDR_SIZE;
} }
return req->len; return req->req->len;
} }
/**************************************************************************** /****************************************************************************
@ -852,7 +936,9 @@ static void rndis_rxdispatch(FAR void *arg)
priv->netdev.d_len = priv->current_rx_datagram_size; priv->netdev.d_len = priv->current_rx_datagram_size;
leave_critical_section(flags); leave_critical_section(flags);
hdr = (FAR struct eth_hdr_s *)priv->netdev.d_buf; hdr = (FAR struct eth_hdr_s *)
&priv->netdev.d_iob->io_data[CONFIG_NET_LL_GUARDSIZE -
NET_LL_HDRLEN(&priv->netdev)];
/* We only accept IP packets of the configured type and ARP packets */ /* We only accept IP packets of the configured type and ARP packets */
@ -965,7 +1051,7 @@ static int rndis_transmit(FAR struct rndis_dev_s *priv)
/* Queue the packet */ /* Queue the packet */
rndis_fillrequest(priv, priv->net_req->req); rndis_fillrequest(priv, priv->net_req);
rndis_sendnetreq(priv); rndis_sendnetreq(priv);
if (!rndis_allocnetreq(priv)) if (!rndis_allocnetreq(priv))
@ -1110,9 +1196,10 @@ static inline int rndis_recvpacket(FAR struct rndis_dev_s *priv,
priv->current_rx_datagram_offset = msg->dataoffset + 8; priv->current_rx_datagram_offset = msg->dataoffset + 8;
if (priv->current_rx_datagram_offset < reqlen) if (priv->current_rx_datagram_offset < reqlen)
{ {
memcpy(&priv->rx_req->req->buf[RNDIS_PACKET_HDR_SIZE], iob_trycopyin(priv->rx_req->iob,
&reqbuf[priv->current_rx_datagram_offset], &reqbuf[priv->current_rx_datagram_offset],
reqlen - priv->current_rx_datagram_offset); reqlen - priv->current_rx_datagram_offset,
-NET_LL_HDRLEN(&priv->netdev), false);
} }
} }
else else
@ -1136,8 +1223,8 @@ static inline int rndis_recvpacket(FAR struct rndis_dev_s *priv,
if ((index + copysize) <= CONFIG_NET_ETH_PKTSIZE) if ((index + copysize) <= CONFIG_NET_ETH_PKTSIZE)
{ {
memcpy(&priv->rx_req->req->buf[RNDIS_PACKET_HDR_SIZE + index], iob_trycopyin(priv->rx_req->iob, reqbuf, copysize,
reqbuf, copysize); priv->rx_req->iob->io_pktlen, false);
} }
else else
{ {
@ -1721,7 +1808,13 @@ static FAR struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep,
req = EP_ALLOCREQ(ep); req = EP_ALLOCREQ(ep);
if (req != NULL) if (req != NULL)
{ {
/* rdreq/epintin_req/ctrlreq use fixed memory
* reqcontainer use iob dynamically when needed
*/
req->len = len; req->len = len;
if (len > 0)
{
req->buf = EP_ALLOCBUFFER(ep, len); req->buf = EP_ALLOCBUFFER(ep, len);
if (req->buf == NULL) if (req->buf == NULL)
@ -1730,6 +1823,11 @@ static FAR struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep,
req = NULL; req = NULL;
} }
} }
else
{
req->buf = NULL;
}
}
return req; return req;
} }
@ -2109,9 +2207,11 @@ static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
* size. * size.
*/ */
reqlen = 64; if (CONFIG_IOB_BUFSIZE >= CONFIG_RNDIS_BULKIN_REQLEN)
{
if (CONFIG_RNDIS_BULKIN_REQLEN > reqlen) reqlen = 0;
}
else
{ {
reqlen = CONFIG_RNDIS_BULKIN_REQLEN; reqlen = CONFIG_RNDIS_BULKIN_REQLEN;
} }
@ -2128,6 +2228,7 @@ static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
goto errout; goto errout;
} }
reqcontainer->buf = reqcontainer->req->buf;
reqcontainer->req->priv = reqcontainer; reqcontainer->req->priv = reqcontainer;
reqcontainer->req->callback = rndis_wrcomplete; reqcontainer->req->callback = rndis_wrcomplete;
@ -2269,6 +2370,7 @@ static void usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
reqcontainer = (struct rndis_req_s *)sq_remfirst(&priv->reqlist); reqcontainer = (struct rndis_req_s *)sq_remfirst(&priv->reqlist);
if (reqcontainer->req != NULL) if (reqcontainer->req != NULL)
{ {
reqcontainer->req->buf = reqcontainer->buf;
usbclass_freereq(priv->epbulkin, reqcontainer->req); usbclass_freereq(priv->epbulkin, reqcontainer->req);
} }
} }