From patchwork Tue May 17 16:27:15 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jon Hunter X-Patchwork-Id: 9114181 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E7CA49F30C for ; Tue, 17 May 2016 16:27:27 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E907C20303 for ; Tue, 17 May 2016 16:27:26 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id DCEFD2034B for ; Tue, 17 May 2016 16:27:25 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 01CE16E68A; Tue, 17 May 2016 16:27:24 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from hqemgate14.nvidia.com (hqemgate14.nvidia.com [216.228.121.143]) by gabe.freedesktop.org (Postfix) with ESMTPS id 221616E68A for ; Tue, 17 May 2016 16:27:22 +0000 (UTC) Received: from hqnvupgp08.nvidia.com (Not Verified[216.228.121.13]) by hqemgate14.nvidia.com id ; Tue, 17 May 2016 09:27:22 -0700 Received: from HQMAIL105.nvidia.com ([172.20.187.12]) by hqnvupgp08.nvidia.com (PGP Universal service); Tue, 17 May 2016 09:26:10 -0700 X-PGP-Universal: processed; by hqnvupgp08.nvidia.com on Tue, 17 May 2016 09:26:10 -0700 Received: from HQMAIL112.nvidia.com (172.18.146.18) by HQMAIL105.nvidia.com (172.20.187.12) with Microsoft SMTP Server (TLS) id 15.0.1130.7; Tue, 17 May 2016 16:27:20 +0000 Received: from HQMAIL106.nvidia.com (172.18.146.12) by HQMAIL112.nvidia.com (172.18.146.18) with Microsoft SMTP Server (TLS) id 15.0.1130.7; Tue, 17 May 2016 16:27:20 +0000 Received: from hqnvemgw02.nvidia.com (172.16.227.111) by HQMAIL106.nvidia.com (172.18.146.12) with Microsoft SMTP Server id 15.0.1130.7 via Frontend Transport; Tue, 17 May 2016 16:27:20 +0000 Received: from jonathanh-lm.nvidia.com (Not Verified[10.21.132.103]) by hqnvemgw02.nvidia.com with Trustwave SEG (v7, 5, 5, 8150) id ; Tue, 17 May 2016 09:27:20 -0700 From: Jon Hunter To: Thierry Reding , David Airlie , Stephen Warren , Alexandre Courbot Subject: [PATCH] drm/tegra: Fix crash caused by reference count imbalance Date: Tue, 17 May 2016 17:27:15 +0100 Message-ID: <1463502435-29217-1-git-send-email-jonathanh@nvidia.com> X-Mailer: git-send-email 2.1.4 X-NVConfidentiality: public MIME-Version: 1.0 Cc: linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Jon Hunter X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-5.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Commit d2307dea14a4 ("drm/atomic: use connector references (v3)") added reference counting for DRM connectors and this caused a crash when exercising system suspend on Tegra114 Dalmore. The Tegra DSI driver implements a Tegra specific function, tegra_dsi_connector_duplicate_state(), to duplicate the connector state and destroys the state using the generic helper function, drm_atomic_helper_connector_destroy_state(). Following commit d2307dea14a4 ("drm/atomic: use connector references (v3)") there is now an imbalance in the connector reference count because the Tegra function to duplicate state does not take a reference when duplicating the state information. However, the generic helper function to destroy the state information assumes a reference has been taken and during system suspend, when the connector state is destroyed, this leads to a crash because we attempt to put the reference for an object that has already been freed. Fix this by aligning tegra_dsi_connector_duplicate_state() with commit d2307dea14a4 ("drm/atomic: use connector references (v3)"), so that we take a reference on a connector if crtc is set. By fixing tegra_dsi_connector_duplicate_state() to take a reference, although a crash was no longer seen, it was then observed that after each system suspend-resume cycle, the reference would be one greater than before the suspend-resume cycle. Following commit d2307dea14a4 ("drm/atomic: use connector references (v3)"), it was found that we also need to put the reference when calling the function tegra_dsi_connector_reset() before freeing the state. Fix this by updating tegra_dsi_connector_reset() to call the function __drm_atomic_helper_connector_destroy_state() in order to put the reference for the connector. Finally, add a warning if allocating memory for the state information fails in tegra_dsi_connector_reset(). Fixes: d2307dea14a4 ("drm/atomic: use connector references (v3)") Signed-off-by: Jon Hunter --- drivers/gpu/drm/tegra/dsi.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 44e102799195..68aaa4c33cd8 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -745,13 +745,18 @@ static void tegra_dsi_soft_reset(struct tegra_dsi *dsi) static void tegra_dsi_connector_reset(struct drm_connector *connector) { - struct tegra_dsi_state *state = - kzalloc(sizeof(*state), GFP_KERNEL); + struct tegra_dsi_state *state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state) { + if (WARN_ON(!state)) + return; + + if (connector->state) { + __drm_atomic_helper_connector_destroy_state(connector, + connector->state); kfree(connector->state); - __drm_atomic_helper_connector_reset(connector, &state->base); } + + __drm_atomic_helper_connector_reset(connector, &state->base); } static struct drm_connector_state * @@ -764,6 +769,9 @@ tegra_dsi_connector_duplicate_state(struct drm_connector *connector) if (!copy) return NULL; + if (copy->base.crtc) + drm_connector_reference(connector); + return ©->base; }