Skip to content

Commit fbe930a

Browse files
tmlemanfabiobaltieri
authored andcommitted
driver: gpdma: balance the pm usage
Because the DMA driver allows multiple start and stop calls for the same instance and the same channel, we cannot rely on the error codes returned by these functions to notify the device's power manager that a device is still in use. Signed-off-by: Tomasz Leman <[email protected]>
1 parent 00991e4 commit fbe930a

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

drivers/dma/dma_dw_common.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <zephyr/device.h>
1313
#include <zephyr/init.h>
1414
#include <zephyr/drivers/dma.h>
15+
#include <zephyr/pm/device_runtime.h>
1516
#include <soc.h>
1617
#include "dma_dw_common.h"
1718

@@ -508,6 +509,7 @@ int dw_dma_start(const struct device *dev, uint32_t channel)
508509

509510
/* enable the channel */
510511
dw_write(dev_cfg->base, DW_DMA_CHAN_EN, DW_CHAN_UNMASK(channel));
512+
ret = pm_device_runtime_get(dev);
511513

512514
out:
513515
return ret;
@@ -577,7 +579,7 @@ int dw_dma_stop(const struct device *dev, uint32_t channel)
577579
}
578580
#endif
579581
chan_data->state = DW_DMA_IDLE;
580-
582+
ret = pm_device_runtime_put(dev);
581583
out:
582584
return ret;
583585
}

drivers/dma/dma_intel_adsp_gpdma.c

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,29 +161,48 @@ static int intel_adsp_gpdma_config(const struct device *dev, uint32_t channel,
161161

162162
static int intel_adsp_gpdma_start(const struct device *dev, uint32_t channel)
163163
{
164-
int ret;
164+
int ret = 0;
165+
bool first_use = false;
166+
enum pm_device_state state;
167+
168+
/* We need to power-up device before using it. So in case of a GPDMA, we need to check if
169+
* the current instance is already active, and if not, we let the power manager know that
170+
* we want to use it.
171+
*/
172+
if (pm_device_state_get(dev, &state) != -ENOSYS) {
173+
first_use = state != PM_DEVICE_STATE_ACTIVE;
174+
if (first_use) {
175+
ret = pm_device_runtime_get(dev);
176+
}
177+
}
178+
179+
if (ret < 0) {
180+
return ret;
181+
}
165182

166183
intel_adsp_gpdma_llp_enable(dev, channel);
167184
ret = dw_dma_start(dev, channel);
168185
if (ret != 0) {
169186
intel_adsp_gpdma_llp_disable(dev, channel);
170187
}
171188

172-
if (ret == 0) {
173-
ret = pm_device_runtime_get(dev);
189+
/* Device usage is counted by the calls of dw_dma_start and dw_dma_stop. For the first use,
190+
* we need to make sure that the pm_device_runtime_get and pm_device_runtime_put functions
191+
* calls are balanced.
192+
*/
193+
if (first_use) {
194+
ret = pm_device_runtime_put(dev);
174195
}
175196

176197
return ret;
177198
}
178199

179200
static int intel_adsp_gpdma_stop(const struct device *dev, uint32_t channel)
180201
{
181-
int ret;
202+
int ret = dw_dma_stop(dev, channel);
182203

183-
ret = dw_dma_stop(dev, channel);
184204
if (ret == 0) {
185205
intel_adsp_gpdma_llp_disable(dev, channel);
186-
ret = pm_device_runtime_put(dev);
187206
}
188207

189208
return ret;

0 commit comments

Comments
 (0)