Use pm_runtime_resume_and_get() instead of pm_runtime_get_sync()
to deal with usage counter. pm_runtime_get_sync() increases the
usage counter even when it failed, which makes callers to forget
to decrease the usage counter and resulted in reference leak.
pm_runtime_resume_and_get() function decreases the usage counter
when it failed internally so it can avoid the reference leak.
Changelog v1:
- Fix an build error reported by kernel test robot of Intel.
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Reported-by: kernel test robot <lkp@intel.com>
static void decon_atomic_enable(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
static void decon_atomic_enable(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
- pm_runtime_get_sync(ctx->dev);
+ ret = pm_runtime_resume_and_get(ctx->dev);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev, "failed to enable DECON device.\n");
+ return;
+ }
exynos_drm_pipe_clk_enable(crtc, true);
exynos_drm_pipe_clk_enable(crtc, true);
static void decon_atomic_enable(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
static void decon_atomic_enable(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
if (!ctx->suspended)
return;
if (!ctx->suspended)
return;
- pm_runtime_get_sync(ctx->dev);
+ ret = pm_runtime_resume_and_get(ctx->dev);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev, "failed to enable DECON device.\n");
+ return;
+ }
if (dsi->state & DSIM_STATE_ENABLED)
return;
if (dsi->state & DSIM_STATE_ENABLED)
return;
- pm_runtime_get_sync(dsi->dev);
+ ret = pm_runtime_resume_and_get(dsi->dev);
+ if (ret < 0) {
+ dev_err(dsi->dev, "failed to enable DSI device.\n");
+ return;
+ }
+
dsi->state |= DSIM_STATE_ENABLED;
if (dsi->panel) {
dsi->state |= DSIM_STATE_ENABLED;
if (dsi->panel) {
{
struct fimc_context *ctx =
container_of(ipp, struct fimc_context, ipp);
{
struct fimc_context *ctx =
container_of(ipp, struct fimc_context, ipp);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(ctx->dev);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to enable FIMC device.\n");
+ return ret;
+ }
- pm_runtime_get_sync(ctx->dev);
ctx->task = task;
fimc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier);
ctx->task = task;
fimc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier);
writel(val, ctx->regs + SHADOWCON);
}
writel(val, ctx->regs + SHADOWCON);
}
-static void fimd_clear_channels(struct exynos_drm_crtc *crtc)
+static int fimd_clear_channels(struct exynos_drm_crtc *crtc)
{
struct fimd_context *ctx = crtc->ctx;
unsigned int win, ch_enabled = 0;
{
struct fimd_context *ctx = crtc->ctx;
unsigned int win, ch_enabled = 0;
/* Hardware is in unknown state, so ensure it gets enabled properly */
/* Hardware is in unknown state, so ensure it gets enabled properly */
- pm_runtime_get_sync(ctx->dev);
+ ret = pm_runtime_resume_and_get(ctx->dev);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to enable FIMD device.\n");
+ return ret;
+ }
clk_prepare_enable(ctx->bus_clk);
clk_prepare_enable(ctx->lcd_clk);
clk_prepare_enable(ctx->bus_clk);
clk_prepare_enable(ctx->lcd_clk);
clk_disable_unprepare(ctx->bus_clk);
pm_runtime_put(ctx->dev);
clk_disable_unprepare(ctx->bus_clk);
pm_runtime_put(ctx->dev);
- pm_runtime_get_sync(ctx->dev);
+ if (pm_runtime_resume_and_get(ctx->dev) < 0) {
+ dev_warn(ctx->dev, "failed to enable FIMD device.\n");
+ return;
+ }
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags))
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags))
if (ctx->encoder)
exynos_dpi_bind(drm_dev, ctx->encoder);
if (ctx->encoder)
exynos_dpi_bind(drm_dev, ctx->encoder);
- if (is_drm_iommu_supported(drm_dev))
- fimd_clear_channels(ctx->crtc);
+ if (is_drm_iommu_supported(drm_dev)) {
+ int ret;
+
+ ret = fimd_clear_channels(ctx->crtc);
+ if (ret < 0)
+ return ret;
+ }
return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
}
return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
}
g2d->runqueue_node = g2d_get_runqueue_node(g2d);
if (g2d->runqueue_node) {
g2d->runqueue_node = g2d_get_runqueue_node(g2d);
if (g2d->runqueue_node) {
- pm_runtime_get_sync(g2d->dev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(g2d->dev);
+ if (ret < 0) {
+ dev_err(g2d->dev, "failed to enable G2D device.\n");
+ return;
+ }
+
g2d_dma_start(g2d, g2d->runqueue_node);
}
}
g2d_dma_start(g2d, g2d->runqueue_node);
}
}
struct gsc_context *ctx = container_of(ipp, struct gsc_context, ipp);
int ret;
struct gsc_context *ctx = container_of(ipp, struct gsc_context, ipp);
int ret;
- pm_runtime_get_sync(ctx->dev);
+ ret = pm_runtime_resume_and_get(ctx->dev);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to enable GScaler device.\n");
+ return ret;
+ }
+
ctx->task = task;
ret = gsc_reset(ctx);
ctx->task = task;
ret = gsc_reset(ctx);
{
struct rot_context *rot =
container_of(ipp, struct rot_context, ipp);
{
struct rot_context *rot =
container_of(ipp, struct rot_context, ipp);
- pm_runtime_get_sync(rot->dev);
+ ret = pm_runtime_resume_and_get(rot->dev);
+ if (ret < 0) {
+ dev_err(rot->dev, "failed to enable ROTATOR device.\n");
+ return ret;
+ }
rot->task = task;
rotator_src_set_fmt(rot, task->src.buf.fourcc);
rot->task = task;
rotator_src_set_fmt(rot, task->src.buf.fourcc);
struct drm_exynos_ipp_task_rect *src_pos = &task->src.rect;
struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect;
const struct scaler_format *src_fmt, *dst_fmt;
struct drm_exynos_ipp_task_rect *src_pos = &task->src.rect;
struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect;
const struct scaler_format *src_fmt, *dst_fmt;
src_fmt = scaler_get_format(task->src.buf.fourcc);
dst_fmt = scaler_get_format(task->dst.buf.fourcc);
src_fmt = scaler_get_format(task->src.buf.fourcc);
dst_fmt = scaler_get_format(task->dst.buf.fourcc);
- pm_runtime_get_sync(scaler->dev);
- if (scaler_reset(scaler)) {
- pm_runtime_put(scaler->dev);
+ ret = pm_runtime_resume_and_get(scaler->dev);
+ if (ret < 0)
+ return ret;
+
+ if (scaler_reset(scaler))
/* Should be called with hdata->mutex mutex held. */
static void hdmiphy_enable(struct hdmi_context *hdata)
{
/* Should be called with hdata->mutex mutex held. */
static void hdmiphy_enable(struct hdmi_context *hdata)
{
if (hdata->powered)
return;
if (hdata->powered)
return;
- pm_runtime_get_sync(hdata->dev);
+ ret = pm_runtime_resume_and_get(hdata->dev);
+ if (ret < 0) {
+ dev_err(hdata->dev, "failed to enable HDMIPHY device.\n");
+ return;
+ }
if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
DRM_DEV_DEBUG_KMS(hdata->dev,
if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
DRM_DEV_DEBUG_KMS(hdata->dev,
static void mixer_atomic_enable(struct exynos_drm_crtc *crtc)
{
struct mixer_context *ctx = crtc->ctx;
static void mixer_atomic_enable(struct exynos_drm_crtc *crtc)
{
struct mixer_context *ctx = crtc->ctx;
if (test_bit(MXR_BIT_POWERED, &ctx->flags))
return;
if (test_bit(MXR_BIT_POWERED, &ctx->flags))
return;
- pm_runtime_get_sync(ctx->dev);
+ ret = pm_runtime_resume_and_get(ctx->dev);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to enable MIXER device.\n");
+ return;
+ }
exynos_drm_pipe_clk_enable(crtc, true);
exynos_drm_pipe_clk_enable(crtc, true);