From patchwork Thu Dec 1 15:52:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jyri Sarha X-Patchwork-Id: 9456483 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9FFA260585 for ; Thu, 1 Dec 2016 15:52:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9322F284F9 for ; Thu, 1 Dec 2016 15:52:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 87B49284FC; Thu, 1 Dec 2016 15:52:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E699E284F9 for ; Thu, 1 Dec 2016 15:52:23 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 599756E074; Thu, 1 Dec 2016 15:52:19 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from lelnx194.ext.ti.com (lelnx194.ext.ti.com [198.47.27.80]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0E60B6E074 for ; Thu, 1 Dec 2016 15:52:16 +0000 (UTC) Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by lelnx194.ext.ti.com (8.15.1/8.15.1) with ESMTP id uB1FqC4I016199; Thu, 1 Dec 2016 09:52:12 -0600 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id uB1FqCSA007681; Thu, 1 Dec 2016 09:52:12 -0600 Received: from dlep32.itg.ti.com (157.170.170.100) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.3.294.0; Thu, 1 Dec 2016 09:52:11 -0600 Received: from jadmar.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id uB1Fq8Bf020069; Thu, 1 Dec 2016 09:52:10 -0600 From: Jyri Sarha To: Subject: [PATCH RFC 1/3] drm/drm_bridge: adjust bridge module's refcount Date: Thu, 1 Dec 2016 17:52:04 +0200 Message-ID: X-Mailer: git-send-email 1.9.1 In-Reply-To: References: MIME-Version: 1.0 Cc: Jyri Sarha , tomi.valkeinen@ti.com, laurent.pinchart@ideasonboard.com 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-Virus-Scanned: ClamAV using ClamSMTP Store the module that provides the bridge and adjust its reference count accordingly. The bridge module unload should not be allowed while the bridge is attached. To do this safely we need to add reference counting to drm_bridge objects. This has impact to both bridge drivers and the drivers using the bridges. Signed-off-by: Jyri Sarha --- drivers/gpu/drm/drm_bridge.c | 78 +++++++++++++++++++++++++++++++++++++++----- include/drm/drm_bridge.h | 10 +++++- 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 0ee052b..4b0ff45 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -60,6 +61,39 @@ static DEFINE_MUTEX(bridge_lock); static LIST_HEAD(bridge_list); +static void drm_bridge_release(struct kref *ref) +{ + struct drm_bridge *bridge = container_of(ref, struct drm_bridge, kref); + + kfree(bridge); +} + +struct drm_bridge *drm_bridge_alloc(struct module *module) +{ + struct drm_bridge *bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); + + if (!bridge) + return NULL; + + bridge->module = module; + kref_init(&bridge->kref); + + return bridge; +} +EXPORT_SYMBOL(drm_bridge_alloc); + +void drm_bridge_get(struct drm_bridge *bridge) +{ + kref_get(&bridge->kref); +} +EXPORT_SYMBOL(drm_bridge_get); + +void drm_bridge_put(struct drm_bridge *bridge) +{ + kref_put(&bridge->kref, drm_bridge_release); +} +EXPORT_SYMBOL(drm_bridge_put); + /** * drm_bridge_add - add the given bridge to the global bridge list * @@ -70,6 +104,8 @@ */ int drm_bridge_add(struct drm_bridge *bridge) { + drm_bridge_get(bridge); + mutex_lock(&bridge_lock); list_add_tail(&bridge->list, &bridge_list); mutex_unlock(&bridge_lock); @@ -88,6 +124,8 @@ void drm_bridge_remove(struct drm_bridge *bridge) mutex_lock(&bridge_lock); list_del_init(&bridge->list); mutex_unlock(&bridge_lock); + + drm_bridge_put(bridge); } EXPORT_SYMBOL(drm_bridge_remove); @@ -108,18 +146,35 @@ void drm_bridge_remove(struct drm_bridge *bridge) */ int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge) { + int ret = 0; + if (!dev || !bridge) return -EINVAL; + mutex_lock(&bridge_lock); + if (bridge->dev) - return -EBUSY; + ret = -EBUSY; + /* Check that the bridge is still part of the list */ + else if (list_empty(&bridge->list)) + ret = -ENOENT; + else if (!try_module_get(bridge->module)) + ret = -ENOENT; + else + bridge->dev = dev; - bridge->dev = dev; + mutex_unlock(&bridge_lock); - if (bridge->funcs->attach) - return bridge->funcs->attach(bridge); + if (ret) + return ret; - return 0; + if (bridge->funcs->attach) { + ret = bridge->funcs->attach(bridge); + if (ret) + module_put(bridge->module); + } + + return ret; } EXPORT_SYMBOL(drm_bridge_attach); @@ -144,6 +199,8 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (bridge->funcs->detach) bridge->funcs->detach(bridge); + module_put(bridge->module); + bridge->dev = NULL; } EXPORT_SYMBOL(drm_bridge_detach); @@ -312,15 +369,17 @@ void drm_bridge_enable(struct drm_bridge *bridge) #ifdef CONFIG_OF /** - * of_drm_find_bridge - find the bridge corresponding to the device node in - * the global bridge list + * of_drm_get_bridge - find the bridge corresponding to the device node in + * the global bridge list and increase its refcount. + * It is caller responsibility to call drm_bridge_put() + * when it no longer needs the object. * * @np: device node * * RETURNS: * drm_bridge control struct on success, NULL on failure */ -struct drm_bridge *of_drm_find_bridge(struct device_node *np) +struct drm_bridge *of_drm_get_bridge(struct device_node *np) { struct drm_bridge *bridge; @@ -328,6 +387,7 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np) list_for_each_entry(bridge, &bridge_list, list) { if (bridge->of_node == np) { + drm_bridge_get(bridge); mutex_unlock(&bridge_lock); return bridge; } @@ -336,7 +396,7 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np) mutex_unlock(&bridge_lock); return NULL; } -EXPORT_SYMBOL(of_drm_find_bridge); +EXPORT_SYMBOL(of_drm_get_bridge); #endif MODULE_AUTHOR("Ajay Kumar "); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 530a1d6..cd39b7c 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -192,15 +193,22 @@ struct drm_bridge { #ifdef CONFIG_OF struct device_node *of_node; #endif + struct kref kref; + struct module *module; + struct list_head list; const struct drm_bridge_funcs *funcs; void *driver_private; }; +struct drm_bridge *drm_bridge_alloc(struct module *module); +void drm_bridge_get(struct drm_bridge *bridge); +void drm_bridge_put(struct drm_bridge *bridge); + int drm_bridge_add(struct drm_bridge *bridge); void drm_bridge_remove(struct drm_bridge *bridge); -struct drm_bridge *of_drm_find_bridge(struct device_node *np); +struct drm_bridge *of_drm_get_bridge(struct device_node *np); int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge); void drm_bridge_detach(struct drm_bridge *bridge);