From 16ea80e53b3386836ffb86015dbd142e0243cc1c Mon Sep 17 00:00:00 2001 From: zhanghongyu Date: Tue, 14 Feb 2023 17:16:46 +0800 Subject: [PATCH] rndis: support iob offload Signed-off-by: zhanghongyu --- .../cxd56xx/spresense/configs/rndis/defconfig | 1 + .../spresense/configs/rndis_smp/defconfig | 1 + .../freedom-k28f/configs/nshsdusb/defconfig | 1 + .../lc823450-xgevk/configs/krndis/defconfig | 1 + .../lc823450-xgevk/configs/rndis/defconfig | 1 + .../stm32f4discovery/configs/rndis/defconfig | 1 + drivers/usbdev/rndis.c | 178 ++++++++++++++---- 7 files changed, 146 insertions(+), 38 deletions(-) diff --git a/boards/arm/cxd56xx/spresense/configs/rndis/defconfig b/boards/arm/cxd56xx/spresense/configs/rndis/defconfig index 91ab248d3e..f0a222a822 100644 --- a/boards/arm/cxd56xx/spresense/configs/rndis/defconfig +++ b/boards/arm/cxd56xx/spresense/configs/rndis/defconfig @@ -97,6 +97,7 @@ CONFIG_NET_BROADCAST=y CONFIG_NET_ETH_PKTSIZE=1514 CONFIG_NET_ICMP=y CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_LL_GUARDSIZE=50 CONFIG_NET_LOOPBACK=y CONFIG_NET_PKT=y CONFIG_NET_ROUTE=y diff --git a/boards/arm/cxd56xx/spresense/configs/rndis_smp/defconfig b/boards/arm/cxd56xx/spresense/configs/rndis_smp/defconfig index 83dcb66291..ba138d0bb4 100644 --- a/boards/arm/cxd56xx/spresense/configs/rndis_smp/defconfig +++ b/boards/arm/cxd56xx/spresense/configs/rndis_smp/defconfig @@ -97,6 +97,7 @@ CONFIG_NET_BROADCAST=y CONFIG_NET_ETH_PKTSIZE=1514 CONFIG_NET_ICMP=y CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_LL_GUARDSIZE=50 CONFIG_NET_LOOPBACK=y CONFIG_NET_PKT=y CONFIG_NET_ROUTE=y diff --git a/boards/arm/kinetis/freedom-k28f/configs/nshsdusb/defconfig b/boards/arm/kinetis/freedom-k28f/configs/nshsdusb/defconfig index c356216f41..7cf27d4f0f 100644 --- a/boards/arm/kinetis/freedom-k28f/configs/nshsdusb/defconfig +++ b/boards/arm/kinetis/freedom-k28f/configs/nshsdusb/defconfig @@ -52,6 +52,7 @@ CONFIG_NETUTILS_TELNETD=y CONFIG_NET_ARP_SEND=y CONFIG_NET_BROADCAST=y CONFIG_NET_ICMP=y +CONFIG_NET_LL_GUARDSIZE=50 CONFIG_NET_LOOPBACK=y CONFIG_NET_SOCKOPTS=y CONFIG_NET_STATISTICS=y diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/krndis/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/krndis/defconfig index 07fa399688..95bc96c44e 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/krndis/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/krndis/defconfig @@ -100,6 +100,7 @@ CONFIG_NET_BROADCAST=y CONFIG_NET_ETH_PKTSIZE=1500 CONFIG_NET_ICMP=y CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_LL_GUARDSIZE=50 CONFIG_NET_LOOPBACK=y CONFIG_NET_PKT=y CONFIG_NET_ROUTE=y diff --git a/boards/arm/lc823450/lc823450-xgevk/configs/rndis/defconfig b/boards/arm/lc823450/lc823450-xgevk/configs/rndis/defconfig index fad049b3e6..a3f3a83399 100644 --- a/boards/arm/lc823450/lc823450-xgevk/configs/rndis/defconfig +++ b/boards/arm/lc823450/lc823450-xgevk/configs/rndis/defconfig @@ -97,6 +97,7 @@ CONFIG_NET_BROADCAST=y CONFIG_NET_ETH_PKTSIZE=1514 CONFIG_NET_ICMP=y CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_LL_GUARDSIZE=50 CONFIG_NET_LOOPBACK=y CONFIG_NET_PKT=y CONFIG_NET_ROUTE=y diff --git a/boards/arm/stm32/stm32f4discovery/configs/rndis/defconfig b/boards/arm/stm32/stm32f4discovery/configs/rndis/defconfig index 0fa2449d30..52c295d8af 100644 --- a/boards/arm/stm32/stm32f4discovery/configs/rndis/defconfig +++ b/boards/arm/stm32/stm32f4discovery/configs/rndis/defconfig @@ -53,6 +53,7 @@ CONFIG_NET_ARP_SEND=y CONFIG_NET_BROADCAST=y CONFIG_NET_ICMP=y CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_LL_GUARDSIZE=50 CONFIG_NET_LOOPBACK=y CONFIG_NET_STATISTICS=y CONFIG_NET_TCP=y diff --git a/drivers/usbdev/rndis.c b/drivers/usbdev/rndis.c index de31b6ea3b..765275febb 100644 --- a/drivers/usbdev/rndis.c +++ b/drivers/usbdev/rndis.c @@ -70,6 +70,14 @@ (CONFIG_NET_ETH_PKTSIZE + CONFIG_NET_GUARDSIZE + RNDIS_PACKET_HDR_SIZE) #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_CONFIGID (1) #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 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 */ @@ -632,6 +642,14 @@ static void rndis_freewrreq(FAR struct rndis_dev_s *priv, FAR struct rndis_req_s *req) { 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); rndis_submit_rdreq(priv); } @@ -665,11 +683,6 @@ static bool rndis_allocnetreq(FAR struct rndis_dev_s *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); 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); priv->net_req = NULL; - priv->netdev.d_buf = NULL; - priv->netdev.d_len = 0; leave_critical_section(flags); } @@ -723,12 +734,56 @@ static void rndis_freenetreq(FAR struct rndis_dev_s *priv) irqstate_t flags = enter_critical_section(); rndis_freewrreq(priv, priv->net_req); - priv->net_req = NULL; - priv->netdev.d_buf = NULL; - priv->netdev.d_len = 0; + priv->net_req = NULL; + 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 * @@ -748,13 +803,33 @@ static void rndis_freenetreq(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) { return true; } - priv->rx_req = rndis_allocwrreq(priv); - return priv->rx_req != NULL; + /* Prepare buffer to receivce data from usb driver */ + + 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; } /**************************************************************************** @@ -776,10 +851,16 @@ static void rndis_giverxreq(FAR struct rndis_dev_s *priv) DEBUGASSERT(priv->rx_req != NULL); DEBUGASSERT(priv->net_req == NULL); - 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->net_req = priv->rx_req; + 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, - FAR struct usbdev_req_s *req) + FAR struct rndis_req_s *req) { size_t datalen; - req->len = 0; + req->req->len = 0; datalen = MIN(priv->netdev.d_len, CONFIG_RNDIS_BULKIN_REQLEN - RNDIS_PACKET_HDR_SIZE); 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 *)req->buf; + (FAR struct rndis_packet_msg *)req->req->buf; memset(msg, 0, RNDIS_PACKET_HDR_SIZE); 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->datalen = datalen; - req->flags = USBDEV_REQFLAGS_NULLPKT; - req->len = datalen + RNDIS_PACKET_HDR_SIZE; + req->req->flags = USBDEV_REQFLAGS_NULLPKT; + 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; 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 */ @@ -965,7 +1051,7 @@ static int rndis_transmit(FAR struct rndis_dev_s *priv) /* Queue the packet */ - rndis_fillrequest(priv, priv->net_req->req); + rndis_fillrequest(priv, priv->net_req); rndis_sendnetreq(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; if (priv->current_rx_datagram_offset < reqlen) { - memcpy(&priv->rx_req->req->buf[RNDIS_PACKET_HDR_SIZE], - &reqbuf[priv->current_rx_datagram_offset], - reqlen - priv->current_rx_datagram_offset); + iob_trycopyin(priv->rx_req->iob, + &reqbuf[priv->current_rx_datagram_offset], + reqlen - priv->current_rx_datagram_offset, + -NET_LL_HDRLEN(&priv->netdev), false); } } else @@ -1136,8 +1223,8 @@ static inline int rndis_recvpacket(FAR struct rndis_dev_s *priv, if ((index + copysize) <= CONFIG_NET_ETH_PKTSIZE) { - memcpy(&priv->rx_req->req->buf[RNDIS_PACKET_HDR_SIZE + index], - reqbuf, copysize); + iob_trycopyin(priv->rx_req->iob, reqbuf, copysize, + priv->rx_req->iob->io_pktlen, false); } else { @@ -1721,13 +1808,24 @@ static FAR struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep, req = EP_ALLOCREQ(ep); if (req != NULL) { - req->len = len; - req->buf = EP_ALLOCBUFFER(ep, len); + /* rdreq/epintin_req/ctrlreq use fixed memory + * reqcontainer use iob dynamically when needed + */ - if (req->buf == NULL) + req->len = len; + if (len > 0) { - EP_FREEREQ(ep, req); - req = NULL; + req->buf = EP_ALLOCBUFFER(ep, len); + + if (req->buf == NULL) + { + EP_FREEREQ(ep, req); + req = NULL; + } + } + else + { + req->buf = NULL; } } @@ -2109,9 +2207,11 @@ static int usbclass_bind(FAR struct usbdevclass_driver_s *driver, * size. */ - reqlen = 64; - - if (CONFIG_RNDIS_BULKIN_REQLEN > reqlen) + if (CONFIG_IOB_BUFSIZE >= CONFIG_RNDIS_BULKIN_REQLEN) + { + reqlen = 0; + } + else { reqlen = CONFIG_RNDIS_BULKIN_REQLEN; } @@ -2128,6 +2228,7 @@ static int usbclass_bind(FAR struct usbdevclass_driver_s *driver, goto errout; } + reqcontainer->buf = reqcontainer->req->buf; reqcontainer->req->priv = reqcontainer; 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); if (reqcontainer->req != NULL) { + reqcontainer->req->buf = reqcontainer->buf; usbclass_freereq(priv->epbulkin, reqcontainer->req); } }