Skip to content

Commit fda4e19

Browse files
committed
Merge branch 'iupa-last-things-before-pm-conversion'
Alex Elder says: ==================== net: ipa: last things before PM conversion This series contains a few remaining changes needed before fully switching over to using runtime power management rather than the previous "IPA clock" mechanism. The first patch moves the calls to enable and disable the IPA interrupt as a system wakeup interrupt into "ipa_clock.c" with the rest of the power-related code. The second adds a flag to make it possible to distinguish runtime suspend from system suspend. The third and fourth patches arrange for the ->start_xmit path to resume hardware if necessary, to ensure it is powered. If power is not active, the TX queue is stopped, and arrangements are made for the queue to be restarted once hardware power is active again. The fifth patch keeps the TX queue active during suspend. This isn't necessary for system suspend but it's important for runtime suspend. And the last patch makes it so we don't hold the hardware active while the modem network device is open. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 8db102a + 8dc181f commit fda4e19

File tree

4 files changed

+111
-20
lines changed

4 files changed

+111
-20
lines changed

drivers/net/ipa/ipa_clock.c

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ struct ipa_interconnect {
4747
/**
4848
* enum ipa_power_flag - IPA power flags
4949
* @IPA_POWER_FLAG_RESUMED: Whether resume from suspend has been signaled
50+
* @IPA_POWER_FLAG_SYSTEM: Hardware is system (not runtime) suspended
5051
* @IPA_POWER_FLAG_COUNT: Number of defined power flags
5152
*/
5253
enum ipa_power_flag {
5354
IPA_POWER_FLAG_RESUMED,
55+
IPA_POWER_FLAG_SYSTEM,
5456
IPA_POWER_FLAG_COUNT, /* Last; not a flag */
5557
};
5658

@@ -281,6 +283,27 @@ int ipa_clock_put(struct ipa *ipa)
281283
return pm_runtime_put(&ipa->pdev->dev);
282284
}
283285

286+
static int ipa_suspend(struct device *dev)
287+
{
288+
struct ipa *ipa = dev_get_drvdata(dev);
289+
290+
__set_bit(IPA_POWER_FLAG_SYSTEM, ipa->clock->flags);
291+
292+
return pm_runtime_force_suspend(dev);
293+
}
294+
295+
static int ipa_resume(struct device *dev)
296+
{
297+
struct ipa *ipa = dev_get_drvdata(dev);
298+
int ret;
299+
300+
ret = pm_runtime_force_resume(dev);
301+
302+
__clear_bit(IPA_POWER_FLAG_SYSTEM, ipa->clock->flags);
303+
304+
return ret;
305+
}
306+
284307
/* Return the current IPA core clock rate */
285308
u32 ipa_clock_rate(struct ipa *ipa)
286309
{
@@ -299,25 +322,35 @@ u32 ipa_clock_rate(struct ipa *ipa)
299322
*/
300323
static void ipa_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
301324
{
302-
/* Just report the event, and let system resume handle the rest.
303-
* More than one endpoint could signal this; if so, ignore
304-
* all but the first.
325+
/* To handle an IPA interrupt we will have resumed the hardware
326+
* just to handle the interrupt, so we're done. If we are in a
327+
* system suspend, trigger a system resume.
305328
*/
306-
if (!test_and_set_bit(IPA_POWER_FLAG_RESUMED, ipa->clock->flags))
307-
pm_wakeup_dev_event(&ipa->pdev->dev, 0, true);
329+
if (!__test_and_set_bit(IPA_POWER_FLAG_RESUMED, ipa->clock->flags))
330+
if (test_bit(IPA_POWER_FLAG_SYSTEM, ipa->clock->flags))
331+
pm_wakeup_dev_event(&ipa->pdev->dev, 0, true);
308332

309333
/* Acknowledge/clear the suspend interrupt on all endpoints */
310334
ipa_interrupt_suspend_clear_all(ipa->interrupt);
311335
}
312336

313-
void ipa_power_setup(struct ipa *ipa)
337+
int ipa_power_setup(struct ipa *ipa)
314338
{
339+
int ret;
340+
315341
ipa_interrupt_add(ipa->interrupt, IPA_IRQ_TX_SUSPEND,
316342
ipa_suspend_handler);
343+
344+
ret = device_init_wakeup(&ipa->pdev->dev, true);
345+
if (ret)
346+
ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND);
347+
348+
return ret;
317349
}
318350

319351
void ipa_power_teardown(struct ipa *ipa)
320352
{
353+
(void)device_init_wakeup(&ipa->pdev->dev, false);
321354
ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND);
322355
}
323356

@@ -381,8 +414,8 @@ void ipa_clock_exit(struct ipa_clock *clock)
381414
}
382415

383416
const struct dev_pm_ops ipa_pm_ops = {
384-
.suspend = pm_runtime_force_suspend,
385-
.resume = pm_runtime_force_resume,
417+
.suspend = ipa_suspend,
418+
.resume = ipa_resume,
386419
.runtime_suspend = ipa_runtime_suspend,
387420
.runtime_resume = ipa_runtime_resume,
388421
.runtime_idle = ipa_runtime_idle,

drivers/net/ipa/ipa_clock.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ u32 ipa_clock_rate(struct ipa *ipa);
2525
/**
2626
* ipa_power_setup() - Set up IPA power management
2727
* @ipa: IPA pointer
28+
*
29+
* Return: 0 if successful, or a negative error code
2830
*/
29-
void ipa_power_setup(struct ipa *ipa);
31+
int ipa_power_setup(struct ipa *ipa);
3032

3133
/**
3234
* ipa_power_teardown() - Inverse of ipa_power_setup()

drivers/net/ipa/ipa_main.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,7 @@ int ipa_setup(struct ipa *ipa)
101101
if (ret)
102102
return ret;
103103

104-
ipa_power_setup(ipa);
105-
106-
ret = device_init_wakeup(dev, true);
104+
ret = ipa_power_setup(ipa);
107105
if (ret)
108106
goto err_gsi_teardown;
109107

@@ -154,7 +152,6 @@ int ipa_setup(struct ipa *ipa)
154152
err_endpoint_teardown:
155153
ipa_endpoint_teardown(ipa);
156154
ipa_power_teardown(ipa);
157-
(void)device_init_wakeup(dev, false);
158155
err_gsi_teardown:
159156
gsi_teardown(&ipa->gsi);
160157

@@ -181,7 +178,6 @@ static void ipa_teardown(struct ipa *ipa)
181178
ipa_endpoint_disable_one(command_endpoint);
182179
ipa_endpoint_teardown(ipa);
183180
ipa_power_teardown(ipa);
184-
(void)device_init_wakeup(&ipa->pdev->dev, false);
185181
gsi_teardown(&ipa->gsi);
186182
}
187183

drivers/net/ipa/ipa_modem.c

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/netdevice.h>
1010
#include <linux/skbuff.h>
1111
#include <linux/if_rmnet.h>
12+
#include <linux/pm_runtime.h>
1213
#include <linux/remoteproc/qcom_rproc.h>
1314

1415
#include "ipa.h"
@@ -33,9 +34,14 @@ enum ipa_modem_state {
3334
IPA_MODEM_STATE_STOPPING,
3435
};
3536

36-
/** struct ipa_priv - IPA network device private data */
37+
/**
38+
* struct ipa_priv - IPA network device private data
39+
* @ipa: IPA pointer
40+
* @work: Work structure used to wake the modem netdev TX queue
41+
*/
3742
struct ipa_priv {
3843
struct ipa *ipa;
44+
struct work_struct work;
3945
};
4046

4147
/** ipa_open() - Opens the modem network interface */
@@ -59,6 +65,8 @@ static int ipa_open(struct net_device *netdev)
5965

6066
netif_start_queue(netdev);
6167

68+
(void)ipa_clock_put(ipa);
69+
6270
return 0;
6371

6472
err_disable_tx:
@@ -74,12 +82,17 @@ static int ipa_stop(struct net_device *netdev)
7482
{
7583
struct ipa_priv *priv = netdev_priv(netdev);
7684
struct ipa *ipa = priv->ipa;
85+
int ret;
86+
87+
ret = ipa_clock_get(ipa);
88+
if (WARN_ON(ret < 0))
89+
goto out_clock_put;
7790

7891
netif_stop_queue(netdev);
7992

8093
ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]);
8194
ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
82-
95+
out_clock_put:
8396
(void)ipa_clock_put(ipa);
8497

8598
return 0;
@@ -93,13 +106,15 @@ static int ipa_stop(struct net_device *netdev)
93106
* NETDEV_TX_OK: Success
94107
* NETDEV_TX_BUSY: Error while transmitting the skb. Try again later
95108
*/
96-
static int ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev)
109+
static netdev_tx_t
110+
ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev)
97111
{
98112
struct net_device_stats *stats = &netdev->stats;
99113
struct ipa_priv *priv = netdev_priv(netdev);
100114
struct ipa_endpoint *endpoint;
101115
struct ipa *ipa = priv->ipa;
102116
u32 skb_len = skb->len;
117+
struct device *dev;
103118
int ret;
104119

105120
if (!skb_len)
@@ -109,7 +124,31 @@ static int ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev)
109124
if (endpoint->data->qmap && skb->protocol != htons(ETH_P_MAP))
110125
goto err_drop_skb;
111126

127+
/* The hardware must be powered for us to transmit */
128+
dev = &ipa->pdev->dev;
129+
ret = pm_runtime_get(dev);
130+
if (ret < 1) {
131+
/* If a resume won't happen, just drop the packet */
132+
if (ret < 0 && ret != -EINPROGRESS) {
133+
pm_runtime_put_noidle(dev);
134+
goto err_drop_skb;
135+
}
136+
137+
/* No power (yet). Stop the network stack from transmitting
138+
* until we're resumed; ipa_modem_resume() arranges for the
139+
* TX queue to be started again.
140+
*/
141+
netif_stop_queue(netdev);
142+
143+
(void)pm_runtime_put(dev);
144+
145+
return NETDEV_TX_BUSY;
146+
}
147+
112148
ret = ipa_endpoint_skb_tx(endpoint, skb);
149+
150+
(void)pm_runtime_put(dev);
151+
113152
if (ret) {
114153
if (ret != -E2BIG)
115154
return NETDEV_TX_BUSY;
@@ -183,12 +222,28 @@ void ipa_modem_suspend(struct net_device *netdev)
183222
if (!(netdev->flags & IFF_UP))
184223
return;
185224

186-
netif_stop_queue(netdev);
187-
188225
ipa_endpoint_suspend_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]);
189226
ipa_endpoint_suspend_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
190227
}
191228

229+
/**
230+
* ipa_modem_wake_queue_work() - enable modem netdev queue
231+
* @work: Work structure
232+
*
233+
* Re-enable transmit on the modem network device. This is called
234+
* in (power management) work queue context, scheduled when resuming
235+
* the modem. We can't enable the queue directly in ipa_modem_resume()
236+
* because transmits restart the instant the queue is awakened; but the
237+
* device power state won't be ACTIVE until *after* ipa_modem_resume()
238+
* returns.
239+
*/
240+
static void ipa_modem_wake_queue_work(struct work_struct *work)
241+
{
242+
struct ipa_priv *priv = container_of(work, struct ipa_priv, work);
243+
244+
netif_wake_queue(priv->ipa->modem_netdev);
245+
}
246+
192247
/** ipa_modem_resume() - resume callback for runtime_pm
193248
* @dev: pointer to device
194249
*
@@ -205,7 +260,8 @@ void ipa_modem_resume(struct net_device *netdev)
205260
ipa_endpoint_resume_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
206261
ipa_endpoint_resume_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]);
207262

208-
netif_wake_queue(netdev);
263+
/* Arrange for the TX queue to be restarted */
264+
(void)queue_pm_work(&priv->work);
209265
}
210266

211267
int ipa_modem_start(struct ipa *ipa)
@@ -233,6 +289,7 @@ int ipa_modem_start(struct ipa *ipa)
233289
SET_NETDEV_DEV(netdev, &ipa->pdev->dev);
234290
priv = netdev_priv(netdev);
235291
priv->ipa = ipa;
292+
INIT_WORK(&priv->work, ipa_modem_wake_queue_work);
236293
ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]->netdev = netdev;
237294
ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]->netdev = netdev;
238295
ipa->modem_netdev = netdev;
@@ -277,6 +334,9 @@ int ipa_modem_stop(struct ipa *ipa)
277334

278335
/* Clean up the netdev and endpoints if it was started */
279336
if (netdev) {
337+
struct ipa_priv *priv = netdev_priv(netdev);
338+
339+
cancel_work_sync(&priv->work);
280340
/* If it was opened, stop it first */
281341
if (netdev->flags & IFF_UP)
282342
(void)ipa_stop(netdev);

0 commit comments

Comments
 (0)