Skip to content

Commit

Permalink
drivers: dma: intel_adsp_gpdma: fix issue with stop and PM refcounts
Browse files Browse the repository at this point in the history
The DMA interface allows start and stop to be called multiple
times and driver should ensure nothing bad happens if the calls
are not balanced.

Fix an issue where after a start-stop sequence the DMA would be
powered down, and then a subsequent stop would result in a crash
as driver accesses registers of a powered down hardware block.

Fix the issue by handling stop without actually reading the hw
registers to check channel status.

(cherry picked from commit c7e3ccd)

Original-Link: thesofproject/sof#8503
Original-Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
GitOrigin-RevId: c7e3ccd
Change-Id: I9373f09038d2eccf6007c7aac440d1b747e0f3b6
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/zephyr/+/5129136
Tested-by: ChromeOS Prod (Robot) <chromeos-ci-prod@chromeos-bot.iam.gserviceaccount.com>
Commit-Queue: Fabio Baltieri <fabiobaltieri@google.com>
Reviewed-by: Yuval Peress <peress@google.com>
Reviewed-by: Fabio Baltieri <fabiobaltieri@google.com>
Tested-by: Fabio Baltieri <fabiobaltieri@google.com>
Reviewed-by: Keith Short <keithshort@chromium.org>
  • Loading branch information
kv2019i authored and Chromeos LUCI committed Dec 23, 2023
1 parent ef42965 commit 2053902
Showing 1 changed file with 12 additions and 0 deletions.
12 changes: 12 additions & 0 deletions drivers/dma/dma_dw_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <soc.h>
#include "dma_dw_common.h"
Expand Down Expand Up @@ -546,14 +547,25 @@ int dw_dma_stop(const struct device *dev, uint32_t channel)
const struct dw_dma_dev_cfg *const dev_cfg = dev->config;
struct dw_dma_dev_data *dev_data = dev->data;
struct dw_dma_chan_data *chan_data = &dev_data->chan[channel];
enum pm_device_state pm_state;
int ret = 0;

if (channel >= DW_CHAN_COUNT) {
ret = -EINVAL;
goto out;
}

/*
* skip if device is not active. if we get an error for state_get,
* do not skip but check actual hardware state and stop if
* needed
*/
ret = pm_device_state_get(dev, &pm_state);
if (!ret && pm_state != PM_DEVICE_STATE_ACTIVE)
goto out;

if (!dw_dma_is_enabled(dev, channel) && chan_data->state != DW_DMA_SUSPENDED) {
ret = 0;
goto out;
}

Expand Down

0 comments on commit 2053902

Please sign in to comment.