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);
 
 	return mask;
 }
diff --git a/drivers/net/wwan/wwan_hwsim.c b/drivers/net/wwan/wwan_hwsim.c
index 472cae544a2b..e5ecbc70658d 100644
--- a/drivers/net/wwan/wwan_hwsim.c
+++ b/drivers/net/wwan/wwan_hwsim.c
@@ -83,7 +83,8 @@ static void wwan_hwsim_port_stop(struct wwan_port *wport)
  *
  * Be aware that this processor is not fully V.250 compliant.
  */
-static int wwan_hwsim_port_tx(struct wwan_port *wport, struct sk_buff *in)
+static int wwan_hwsim_port_tx(struct wwan_port *wport, struct sk_buff *in,
+			      bool nonblock)
 {
 	struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
 	struct sk_buff *out;
diff --git a/include/linux/wwan.h b/include/linux/wwan.h
index 430a3a0817de..d7c8c6ac7594 100644
--- a/include/linux/wwan.h
+++ b/include/linux/wwan.h
@@ -6,6 +6,7 @@
 
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/poll.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 
@@ -38,17 +39,21 @@ enum wwan_port_type {
 struct wwan_port;
 
 /** struct wwan_port_ops - The WWAN port operations
- * @start: The routine for starting the WWAN port device.
- * @stop: The routine for stopping the WWAN port device.
+ * @start: The routine for starting the WWAN port device. Required.
+ * @stop: The routine for stopping the WWAN port device. Required.
  * @tx: The routine that sends WWAN port protocol data to the device.
+ *      May only block if nonblock is false. Required.
+ * @poll: A routine to set additional poll flags. Optional.
  *
  * The wwan_port_ops structure contains a list of low-level operations
- * that control a WWAN port device. All functions are mandatory.
+ * that control a WWAN port device.
  */
 struct wwan_port_ops {
 	int (*start)(struct wwan_port *port);
 	void (*stop)(struct wwan_port *port);
-	int (*tx)(struct wwan_port *port, struct sk_buff *skb);
+	int (*tx)(struct wwan_port *port, struct sk_buff *skb, bool nonblock);
+	__poll_t (*poll)(struct wwan_port *port, struct file *filp,
+			 poll_table *wait);
 };
 
 /**
