diff --git a/drivers/net/ipa/ipa_clock.c b/drivers/net/ipa/ipa_clock.c
index 8f25107c1f1e7..ed7ef72fbb78a 100644
--- a/drivers/net/ipa/ipa_clock.c
+++ b/drivers/net/ipa/ipa_clock.c
@@ -48,11 +48,15 @@ struct ipa_interconnect {
  * enum ipa_power_flag - IPA power flags
  * @IPA_POWER_FLAG_RESUMED:	Whether resume from suspend has been signaled
  * @IPA_POWER_FLAG_SYSTEM:	Hardware is system (not runtime) suspended
+ * @IPA_POWER_FLAG_STOPPED:	Modem TX is disabled by ipa_start_xmit()
+ * @IPA_POWER_FLAG_STARTED:	Modem TX was enabled by ipa_runtime_resume()
  * @IPA_POWER_FLAG_COUNT:	Number of defined power flags
  */
 enum ipa_power_flag {
 	IPA_POWER_FLAG_RESUMED,
 	IPA_POWER_FLAG_SYSTEM,
+	IPA_POWER_FLAG_STOPPED,
+	IPA_POWER_FLAG_STARTED,
 	IPA_POWER_FLAG_COUNT,		/* Last; not a flag */
 };
 
@@ -60,6 +64,7 @@ enum ipa_power_flag {
  * struct ipa_clock - IPA clocking information
  * @dev:		IPA device pointer
  * @core:		IPA core clock
+ * @spinlock:		Protects modem TX queue enable/disable
  * @flags:		Boolean state flags
  * @interconnect_count:	Number of elements in interconnect[]
  * @interconnect:	Interconnect array
@@ -67,6 +72,7 @@ enum ipa_power_flag {
 struct ipa_clock {
 	struct device *dev;
 	struct clk *core;
+	spinlock_t spinlock;	/* used with STOPPED/STARTED power flags */
 	DECLARE_BITMAP(flags, IPA_POWER_FLAG_COUNT);
 	u32 interconnect_count;
 	struct ipa_interconnect *interconnect;
@@ -334,6 +340,69 @@ static void ipa_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
 	ipa_interrupt_suspend_clear_all(ipa->interrupt);
 }
 
+/* The next few functions coordinate stopping and starting the modem
+ * network device transmit queue.
+ *
+ * Transmit can be running concurrent with power resume, and there's a
+ * chance the resume completes before the transmit path stops the queue,
+ * leaving the queue in a stopped state.  The next two functions are used
+ * to avoid this: ipa_power_modem_queue_stop() is used by ipa_start_xmit()
+ * to conditionally stop the TX queue; and ipa_power_modem_queue_start()
+ * is used by ipa_runtime_resume() to conditionally restart it.
+ *
+ * Two flags and a spinlock are used.  If the queue is stopped, the STOPPED
+ * power flag is set.  And if the queue is started, the STARTED flag is set.
+ * The queue is only started on resume if the STOPPED flag is set.  And the
+ * queue is only started in ipa_start_xmit() if the STARTED flag is *not*
+ * set.  As a result, the queue remains operational if the two activites
+ * happen concurrently regardless of the order they complete.  The spinlock
+ * ensures the flag and TX queue operations are done atomically.
+ *
+ * The first function stops the modem netdev transmit queue, but only if
+ * the STARTED flag is *not* set.  That flag is cleared if it was set.
+ * If the queue is stopped, the STOPPED flag is set.  This is called only
+ * from the power ->runtime_resume operation.
+ */
+void ipa_power_modem_queue_stop(struct ipa *ipa)
+{
+	struct ipa_clock *clock = ipa->clock;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clock->spinlock, flags);
+
+	if (!__test_and_clear_bit(IPA_POWER_FLAG_STARTED, clock->flags)) {
+		netif_stop_queue(ipa->modem_netdev);
+		__set_bit(IPA_POWER_FLAG_STOPPED, clock->flags);
+	}
+
+	spin_unlock_irqrestore(&clock->spinlock, flags);
+}
+
+/* This function starts the modem netdev transmit queue, but only if the
+ * STOPPED flag is set.  That flag is cleared if it was set.  If the queue
+ * was restarted, the STARTED flag is set; this allows ipa_start_xmit()
+ * to skip stopping the queue in the event of a race.
+ */
+void ipa_power_modem_queue_wake(struct ipa *ipa)
+{
+	struct ipa_clock *clock = ipa->clock;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clock->spinlock, flags);
+
+	if (__test_and_clear_bit(IPA_POWER_FLAG_STOPPED, clock->flags)) {
+		__set_bit(IPA_POWER_FLAG_STARTED, clock->flags);
+		netif_wake_queue(ipa->modem_netdev);
+	}
+
+	spin_unlock_irqrestore(&clock->spinlock, flags);
+}
+
+/* This function clears the STARTED flag once the TX queue is operating */
+{
+	clear_bit(IPA_POWER_FLAG_STARTED, ipa->clock->flags);
+}
+
 int ipa_power_setup(struct ipa *ipa)
 {
 	int ret;
@@ -383,6 +452,7 @@ ipa_clock_init(struct device *dev, const struct ipa_clock_data *data)
 	}
 	clock->dev = dev;
 	clock->core = clk;
+	spin_lock_init(&clock->spinlock);
 	clock->interconnect_count = data->interconnect_count;
 
 	ret = ipa_interconnect_init(clock, dev, data->interconnect_data);
diff --git a/drivers/net/ipa/ipa_clock.h b/drivers/net/ipa/ipa_clock.h
index 5c53241336a1a..64cd15981b1da 100644
--- a/drivers/net/ipa/ipa_clock.h
+++ b/drivers/net/ipa/ipa_clock.h
@@ -22,6 +22,24 @@ extern const struct dev_pm_ops ipa_pm_ops;
  */
 u32 ipa_clock_rate(struct ipa *ipa);
 
+/**
+ * ipa_power_modem_queue_stop() - Possibly stop the modem netdev TX queue
+ * @ipa:	IPA pointer
+ */
+void ipa_power_modem_queue_stop(struct ipa *ipa);
+
+/**
+ * ipa_power_modem_queue_wake() - Possibly wake the modem netdev TX queue
+ * @ipa:	IPA pointer
+ */
+void ipa_power_modem_queue_wake(struct ipa *ipa);
+
+/**
+ * ipa_power_modem_queue_active() - Report modem netdev TX queue active
+ * @ipa:	IPA pointer
+ */
+void ipa_power_modem_queue_active(struct ipa *ipa);
+
 /**
  * ipa_power_setup() - Set up IPA power management
  * @ipa:	IPA pointer
diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c
index c8724af935b85..16d87910305e1 100644
--- a/drivers/net/ipa/ipa_modem.c
+++ b/drivers/net/ipa/ipa_modem.c
@@ -130,6 +130,7 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 	if (ret < 1) {
 		/* If a resume won't happen, just drop the packet */
 		if (ret < 0 && ret != -EINPROGRESS) {
+			ipa_power_modem_queue_active(ipa);
 			pm_runtime_put_noidle(dev);
 			goto err_drop_skb;
 		}
@@ -138,13 +139,15 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 		 * until we're resumed; ipa_modem_resume() arranges for the
 		 * TX queue to be started again.
 		 */
-		netif_stop_queue(netdev);
+		ipa_power_modem_queue_stop(ipa);
 
 		(void)pm_runtime_put(dev);
 
 		return NETDEV_TX_BUSY;
 	}
 
+	ipa_power_modem_queue_active(ipa);
+
 	ret = ipa_endpoint_skb_tx(endpoint, skb);
 
 	(void)pm_runtime_put(dev);
@@ -241,7 +244,7 @@ static void ipa_modem_wake_queue_work(struct work_struct *work)
 {
 	struct ipa_priv *priv = container_of(work, struct ipa_priv, work);
 
-	netif_wake_queue(priv->ipa->modem_netdev);
+	ipa_power_modem_queue_wake(priv->ipa);
 }
 
 /** ipa_modem_resume() - resume callback for runtime_pm
