Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp4047464pxj; Tue, 15 Jun 2021 14:18:48 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyEl9gpqyKM0HXcgvgcOd6eYJg0CrfQ7Xj9Jzr+A9j3zzupt15ttPdcePZXONVTBKGDiqL0 X-Received: by 2002:a17:906:228b:: with SMTP id p11mr1574946eja.169.1623791928596; Tue, 15 Jun 2021 14:18:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1623791928; cv=none; d=google.com; s=arc-20160816; b=vK3gsWqPHS/z2IELkG/f3Wqn9uCRhBRUWlBACA3bvzylr+dqGGlqEv5ngX1/FTQGWS AfSgKb+pCvljtmA+giEHhWCo6WJKPaQDyRGEPNRPBMkVmMBnpEdRRCs6c9me9noVWZRv g+a988JzUxWjbqB+r5LwJ+eM0agy4I7TWq2jPji2qDm2+loR1eIOzG0VwIEAIMH8S/ol ZMNV4380DWkfI3YHhUpAJdOkXVIxN0fLI21MU+y5ZK5eifHNhxh0utb3dsmTiWfDa+Y+ 8oCs4sOR1sYRn5gOGYqrjKKdr5/WXO7fFqtCu7sUH0ex7uB/ErZDkMS5ptGrwjQ5JwcQ G27w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:subject:message-id:date:from:in-reply-to :references:mime-version:dkim-signature; bh=3Awujr/Y6+41OzNXavuItFD+FkpQLXtfnUO7aKQrUyQ=; b=wdy+Ix2z0qdTTlsd4vjAGxoyFw3t7korH+7umUeROhBLLQN7nkfxEtzIYgP17BhqqD ReUhGHrPGSQoY/gfxGg2VzmsMAFXONNfc8BgQTkGbqYf2T8rSsT+UlC38Q53nzixVP3I Q19HEMnG9q9ajMn+fJw5Y5SgreTUecj24tUsUZOsfE9ajQyJ/335Qg5KSg9POhjXLHX9 dzDM+/Cds9JXljvqfzs0WBZbtflvq6yT1BuL1Thp8RR+M55E4HhqhT/xpBLTgkZa1cco VLcIWVgj/3d5osvWdHAIOEL20IYsccwqgIJAsBWA8+9gGrLq59icbgTI1nMT0fj77SnD WLvg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=vCqncKYL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id m11si90256ejc.708.2021.06.15.14.18.15; Tue, 15 Jun 2021 14:18:48 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=vCqncKYL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231433AbhFOVRq (ORCPT + 99 others); Tue, 15 Jun 2021 17:17:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47072 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231416AbhFOVRq (ORCPT ); Tue, 15 Jun 2021 17:17:46 -0400 Received: from mail-pl1-x634.google.com (mail-pl1-x634.google.com [IPv6:2607:f8b0:4864:20::634]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7054BC061574 for ; Tue, 15 Jun 2021 14:15:40 -0700 (PDT) Received: by mail-pl1-x634.google.com with SMTP id 11so9119365plk.12 for ; Tue, 15 Jun 2021 14:15:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=3Awujr/Y6+41OzNXavuItFD+FkpQLXtfnUO7aKQrUyQ=; b=vCqncKYL64Z3hdL1T/RremxZ/laqN4mZ1Xq01ai0PehoiSc72IBK66XLU3mh+asdzl zGmN1ZFs+BfygglD7iWme0kObzmQGVbw2vzqY/HzvuHGFoa9l27UgLkOVVnuaZWoWLYM 26QTN4oS38B7KZBVbmgcj3otPU+XV4T5NNOohJnGUVfS7olFLQNTyXgQ0IoZOUDpYxVY I73HGM/ntPoVSnAB9F0uyYZqkvC4t+4YAP9vL6WabHmmwL42X5VpjOCUkBWKjx38KFw6 UdYD7TpneUDoNRrzZsmZAl49FEfFlgz9axyElHyDXUm7kNYnzy+bjOxqqhnw4OKvqPh+ NS+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=3Awujr/Y6+41OzNXavuItFD+FkpQLXtfnUO7aKQrUyQ=; b=MVZK5zPdHLTgmrr2LnoS4EP8A+eNPAHn1wZmAvH/ejIrE+v5YALUJs3rj+ER6qfpeB ZeWymOf2z7e62FeiYjvFWGCwklITFQWkS7Pe5X3rQ8nMSR9wIskE3vUY3q3eYKg/h5LC UHOwG3GQ1aSH6WpUpe+sNjw1K8k7FUwnccNGsV+NeRZKO3tyLm+/Y/J31lnKVE+Si2w1 mVmaSS5KLuBNRmTvH44u0cgj0iPLzdi9g7Q4FbfLxTNQpRZYmj07uIE3zkY+JXGNFdEy P50kjHTi1MI95VpRu/wAlclqguA6wZdEIDdA3ainXuhFaF2otTlmI+wxgQpPW7qgSAI9 DRPw== X-Gm-Message-State: AOAM530l+ehVaS9LRP7s4bvNIEYWZdTWld/YLbQOGcnrtHEpF4tyR7JF 0ZQFW+FOAGWTB3UoCEN+oA07nCqpK/BSgP96Cn814Q== X-Received: by 2002:a17:90a:d590:: with SMTP id v16mr1205348pju.205.1623791739791; Tue, 15 Jun 2021 14:15:39 -0700 (PDT) MIME-Version: 1.0 References: <20210615133229.213064-1-stephan@gerhold.net> <20210615133229.213064-4-stephan@gerhold.net> In-Reply-To: <20210615133229.213064-4-stephan@gerhold.net> From: Loic Poulain Date: Tue, 15 Jun 2021 23:24:41 +0200 Message-ID: Subject: Re: [PATCH net-next 3/3] net: wwan: Allow WWAN drivers to provide blocking tx and poll function To: Stephan Gerhold Cc: "David S. Miller" , Jakub Kicinski , Bjorn Andersson , Aleksander Morgado , Sergey Ryazanov , Johannes Berg , M Chetan Kumar , Ohad Ben-Cohen , Mathieu Poirier , Network Development , linux-remoteproc@vger.kernel.org, linux-arm-msm , phone-devel@vger.kernel.org, open list , ~postmarketos/upstreaming@lists.sr.ht Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Stephan, On Tue, 15 Jun 2021 at 15:34, Stephan Gerhold wrote: > > At the moment, the WWAN core provides wwan_port_txon/off() to implement > blocking writes. The tx() port operation should not block, instead > wwan_port_txon/off() should be called when the TX queue is full or has > free space again. > > However, in some cases it is not straightforward to make use of that > functionality. For example, the RPMSG API used by rpmsg_wwan_ctrl.c > does not provide any way to be notified when the TX queue has space > again. Instead, it only provides the following operations: > > - rpmsg_send(): blocking write (wait until there is space) > - rpmsg_trysend(): non-blocking write (return error if no space) > - rpmsg_poll(): set poll flags depending on TX queue state > > Generally that's totally sufficient for implementing a char device, > but it does not fit well to the currently provided WWAN port ops. > > Most of the time, using the non-blocking rpmsg_trysend() in the > WWAN tx() port operation works just fine. However, with high-frequent > writes to the char device it is possible to trigger a situation > where this causes issues. For example, consider the following > (somewhat unrealistic) example: > > # dd if=/dev/zero bs=1000 of=/dev/wwan0p2QMI > dd: error writing '/dev/wwan0p2QMI': Resource temporarily unavailable > 1+0 records out > > This fails immediately after writing the first record. It's likely > only a matter of time until this triggers issues for some real application > (e.g. ModemManager sending a lot of large QMI packets). > > The rpmsg_char device does not have this problem, because it uses > rpmsg_trysend() and rpmsg_poll() to support non-blocking operations. > Make it possible to use the same in the RPMSG WWAN driver by extending > the tx() operation with a "nonblock" parameter and adding an optional > poll() callback. This integrates nicely with the RPMSG API and does > not break other WWAN drivers. > > With these changes, the dd example above blocks instead of exiting > with an error. > > Cc: Loic Poulain > Signed-off-by: Stephan Gerhold > --- > Note that rpmsg_poll() is an optional callback currently only implemented > by the qcom_smd RPMSG provider. However, it should be easy to implement > this for other RPMSG providers when needed. > > Another potential solution suggested by Loic Poulain in [1] is to always > use the blocking rpmsg_send() from a workqueue/kthread and disable TX > until it is done. I think this could also work (perhaps a bit more > difficult to implement) but the main disadvantage is that I don't see > a way to return any kind of error to the client with this approach. > I assume we return immediately from the write() to the char device > after scheduling the rpmsg_send(), so we already reported success > when rpmsg_send() returns. > > At the end all that matters to me is that it works properly, so I'm > open for any other suggestions. :) > > [1]: https://lore.kernel.org/linux-arm-msm/CAMZdPi_-Qa=JnThHs_h-144dAfSAjF5s+QdBawdXZ3kk8Mx8ng@mail.gmail.com/ > --- > drivers/net/wwan/iosm/iosm_ipc_port.c | 3 ++- > drivers/net/wwan/mhi_wwan_ctrl.c | 3 ++- > drivers/net/wwan/rpmsg_wwan_ctrl.c | 17 +++++++++++++++-- > drivers/net/wwan/wwan_core.c | 9 ++++++--- > drivers/net/wwan/wwan_hwsim.c | 3 ++- > include/linux/wwan.h | 13 +++++++++---- > 6 files changed, 36 insertions(+), 12 deletions(-) > > diff --git a/drivers/net/wwan/iosm/iosm_ipc_port.c b/drivers/net/wwan/iosm/iosm_ipc_port.c > index beb944847398..2f874e41ceff 100644 > --- a/drivers/net/wwan/iosm/iosm_ipc_port.c > +++ b/drivers/net/wwan/iosm/iosm_ipc_port.c > @@ -31,7 +31,8 @@ static void ipc_port_ctrl_stop(struct wwan_port *port) > } > > /* transfer control data to modem */ > -static int ipc_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb) > +static int ipc_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb, > + bool nonblock) > { > struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port); > > diff --git a/drivers/net/wwan/mhi_wwan_ctrl.c b/drivers/net/wwan/mhi_wwan_ctrl.c > index 1bc6b69aa530..9754f014d348 100644 > --- a/drivers/net/wwan/mhi_wwan_ctrl.c > +++ b/drivers/net/wwan/mhi_wwan_ctrl.c > @@ -139,7 +139,8 @@ static void mhi_wwan_ctrl_stop(struct wwan_port *port) > mhi_unprepare_from_transfer(mhiwwan->mhi_dev); > } > > -static int mhi_wwan_ctrl_tx(struct wwan_port *port, struct sk_buff *skb) > +static int mhi_wwan_ctrl_tx(struct wwan_port *port, struct sk_buff *skb, > + bool nonblock) > { > struct mhi_wwan_dev *mhiwwan = wwan_port_get_drvdata(port); > int ret; > diff --git a/drivers/net/wwan/rpmsg_wwan_ctrl.c b/drivers/net/wwan/rpmsg_wwan_ctrl.c > index de226cdb69fd..63f431eada39 100644 > --- a/drivers/net/wwan/rpmsg_wwan_ctrl.c > +++ b/drivers/net/wwan/rpmsg_wwan_ctrl.c > @@ -54,12 +54,16 @@ static void rpmsg_wwan_ctrl_stop(struct wwan_port *port) > rpwwan->ept = NULL; > } > > -static int rpmsg_wwan_ctrl_tx(struct wwan_port *port, struct sk_buff *skb) > +static int rpmsg_wwan_ctrl_tx(struct wwan_port *port, struct sk_buff *skb, > + bool nonblock) > { > struct rpmsg_wwan_dev *rpwwan = wwan_port_get_drvdata(port); > int ret; > > - ret = rpmsg_trysend(rpwwan->ept, skb->data, skb->len); > + if (nonblock) > + ret = rpmsg_trysend(rpwwan->ept, skb->data, skb->len); > + else > + ret = rpmsg_send(rpwwan->ept, skb->data, skb->len); > if (ret) > return ret; > > @@ -67,10 +71,19 @@ static int rpmsg_wwan_ctrl_tx(struct wwan_port *port, struct sk_buff *skb) > return 0; > } > > +static __poll_t rpmsg_wwan_ctrl_poll(struct wwan_port *port, struct file *filp, > + poll_table *wait) > +{ > + struct rpmsg_wwan_dev *rpwwan = wwan_port_get_drvdata(port); > + > + return rpmsg_poll(rpwwan->ept, filp, wait); > +} > + > static const struct wwan_port_ops rpmsg_wwan_pops = { > .start = rpmsg_wwan_ctrl_start, > .stop = rpmsg_wwan_ctrl_stop, > .tx = rpmsg_wwan_ctrl_tx, > + .poll = rpmsg_wwan_ctrl_poll, > }; > > static struct device *rpmsg_wwan_find_parent(struct device *dev) > diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c > index 7e728042fc41..c7fd0b897f87 100644 > --- a/drivers/net/wwan/wwan_core.c > +++ b/drivers/net/wwan/wwan_core.c > @@ -500,7 +500,8 @@ static void wwan_port_op_stop(struct wwan_port *port) > mutex_unlock(&port->ops_lock); > } > > -static int wwan_port_op_tx(struct wwan_port *port, struct sk_buff *skb) > +static int wwan_port_op_tx(struct wwan_port *port, struct sk_buff *skb, > + bool nonblock) > { > int ret; > > @@ -510,7 +511,7 @@ static int wwan_port_op_tx(struct wwan_port *port, struct sk_buff *skb) > goto out_unlock; > } > > - ret = port->ops->tx(port, skb); > + ret = port->ops->tx(port, skb, nonblock); > > out_unlock: > mutex_unlock(&port->ops_lock); > @@ -637,7 +638,7 @@ static ssize_t wwan_port_fops_write(struct file *filp, const char __user *buf, > return -EFAULT; > } > > - ret = wwan_port_op_tx(port, skb); > + ret = wwan_port_op_tx(port, skb, !!(filp->f_flags & O_NONBLOCK)); > if (ret) { > kfree_skb(skb); > return ret; > @@ -659,6 +660,8 @@ static __poll_t wwan_port_fops_poll(struct file *filp, poll_table *wait) > mask |= EPOLLIN | EPOLLRDNORM; > if (!port->ops) > mask |= EPOLLHUP | EPOLLERR; > + else if (port->ops->poll) > + mask |= port->ops->poll(port, filp, wait); I'm not sure it useful here because EPOLLOUT flag is already set above, right? > > return mask; > } Regards, Loic