From patchwork Thu Aug 23 08:25:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chunming Zhou X-Patchwork-Id: 10573547 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E9B4F14BD for ; Thu, 23 Aug 2018 08:27:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D32BF2BA16 for ; Thu, 23 Aug 2018 08:27:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C696E2BA1B; Thu, 23 Aug 2018 08:27:35 +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=-5.2 required=2.0 tests=BAD_ENC_HEADER,BAYES_00, MAILING_LIST_MULTI,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 658BD2BA16 for ; Thu, 23 Aug 2018 08:27:34 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 71DC46E4ED; Thu, 23 Aug 2018 08:27:33 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from NAM05-BY2-obe.outbound.protection.outlook.com (mail-eopbgr710049.outbound.protection.outlook.com [40.107.71.49]) by gabe.freedesktop.org (Postfix) with ESMTPS id 48E7F6E4E1; Thu, 23 Aug 2018 08:27:31 +0000 (UTC) Received: from DM3PR12CA0056.namprd12.prod.outlook.com (2603:10b6:0:56::24) by BY2PR12MB0241.namprd12.prod.outlook.com (2a01:111:e400:585d::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1059.21; Thu, 23 Aug 2018 08:27:28 +0000 Received: from BY2NAM03FT050.eop-NAM03.prod.protection.outlook.com (2a01:111:f400:7e4a::204) by DM3PR12CA0056.outlook.office365.com (2603:10b6:0:56::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.1080.14 via Frontend Transport; Thu, 23 Aug 2018 08:27:27 +0000 Received-SPF: None (protection.outlook.com: amd.com does not designate permitted sender hosts) Received: from SATLEXCHOV02.amd.com (165.204.84.17) by BY2NAM03FT050.mail.protection.outlook.com (10.152.85.137) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.20.1080.9 via Frontend Transport; Thu, 23 Aug 2018 08:27:27 +0000 Received: from zhoucm1.amd.com (10.34.1.3) by SATLEXCHOV02.amd.com (10.181.40.72) with Microsoft SMTP Server id 14.3.389.1; Thu, 23 Aug 2018 03:27:25 -0500 From: Chunming Zhou To: Subject: [PATCH 5/5] drm: add syncobj timeline support v2 Date: Thu, 23 Aug 2018 16:25:42 +0800 Message-ID: <20180823082542.2998-5-david1.zhou@amd.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20180823082542.2998-1-david1.zhou@amd.com> References: <20180823082542.2998-1-david1.zhou@amd.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-Forefront-Antispam-Report: CIP:165.204.84.17; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(136003)(396003)(346002)(39860400002)(376002)(2980300002)(428003)(199004)(189003)(105586002)(478600001)(53416004)(2906002)(48376002)(2351001)(316002)(68736007)(426003)(11346002)(16586007)(8936002)(86362001)(104016004)(1076002)(336012)(4326008)(54906003)(2616005)(575784001)(305945005)(106466001)(476003)(5660300001)(51416003)(36756003)(7696005)(47776003)(97736004)(6666003)(8676002)(53936002)(81166006)(356003)(126002)(486006)(50226002)(446003)(72206003)(14444005)(50466002)(6916009)(186003)(76176011)(26005)(81156014)(77096007); DIR:OUT; SFP:1101; SCL:1; SRVR:BY2PR12MB0241; H:SATLEXCHOV02.amd.com; FPR:; SPF:None; LANG:en; PTR:InfoDomainNonexistent; A:1; MX:1; X-Microsoft-Exchange-Diagnostics: 1; BY2NAM03FT050; 1:6TKAJdY7pbnAMYcmUZwhoBSNos9iRDuACrZlRE+PD4lxKuaik/xA5YS/5IlxvdbGMbkBVr9/jGqqWedCr2meKO5dkS0i0qTMC/sMAz0AegsTLqXqU4TIJ/36uwQpO4KZ X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: b4c66ec1-f5bd-4e0c-b581-08d608d242ae X-Microsoft-Antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989137)(5600074)(711020)(4534165)(4627221)(201703031133081)(201702281549075)(8990107)(2017052603328)(7153060); SRVR:BY2PR12MB0241; X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0241; 3:i6EkbuCl4FdveYxqcVU9op1LsI0w5bBbChGLGz5oM6B+Pg0wxPChEb22vKWXJa0DlC9hhkMKQbXh6BJWoMwC3blZU6gj0a7ds8DQKaL5CRnxMXMt7b9I5fA5dyt0I9MQXwzYhFKzff4a0oTDP8bHowjpqVl+xKml0zbmGcqH3gNMguS0sHjIy6Pgb3w0h4FhPmpXwLWPGe013Y+iQQ5NjwpWw1zNL2eOjZZO0cuQ18gmcrLYUm+7rim/Gch2zbwMBhyRPDH8DFr4P41FcihAjJaUGIOJ3+5Bbf4oDKkuu+FH5TLm2NCMtBG7IcLpUM4gO0etqEBvHdCYQoshkmX7pLGiQK3Gv296NXiGZJ83IEA=; 25:5Z2mXj9MlojUSHt+NQBSfNLcpTfEaDjdvh3tD32mIPEgZ+Ur3AX/j7UaR/yD8VqWaDNKp4qG/iFbJptSZe6cVcFtGWFDfPOXi79zjBaQ7c7Bz5gwvFOtdXMH+sPrbsFPzZqmU1R7S5sEOvC4UTpX6a6l3pHz4TMuWi8whHaJ+0mZihom3kQkjFu/uUXmtmFmQxbmm0JKS/TapSo2/TSzFjnyWpeO64kUQxrNkTbFnRVRCTiy0sSyVU2jnzlZYJdJ8DVMlhsYJYlU+OCO0g2avUqZPfDTx4jOlm7IXCtOmegvCkAr6dHJ0ay5ipg76JwZLJ3zaz9pPsgr111xOWuk4w== X-MS-TrafficTypeDiagnostic: BY2PR12MB0241: X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0241; 31:JmCb/dCvbsFbUMeX7i2K0fCB1CA1+f10TZOKlGC/IScvht/ibx0X8VSkJBVpezX91X9zLE1z43i5ySkmnnZ9GAeGpxxPt8t5BtD62D1Vdl9BOMaISSUrPS4Ev3hjfTiFiZjVwIwvHKDlP7QH1lQgG83eHwlxQaWycCiw0supUOoZqVz/wNhBZ18Uf5zTRrbmqEVT139ov8HZqh1ql33FPFzYjpMpZUy8CL51NliISbc=; 20:YUbmXAUpIKH5eHWxhOPZc1Qa8soU7bEatZCrpS1Y/l6FYMCArZFmcu8xHK5A4tbKTsL+nuAeMAxSz0wAXt0iLuKe6NtvfFKKg5+lLuH3TvrOJ38deJcBeahUMEdTMrEBJ3lapg26+Ql6xMLavglKZ0BNLQKjzmjG1FUClnURGsdk4uJvXZdrMvZC3yeIP8GlikapWMO6ImMcVX3MlcNo6VYzMvLyOiYS07EeX8EFjrmC34b2HNECdasgNrECnc92e3n+ZvTlyST/y0oc55u47XXzYmwAafnRncKEWgnubATE48qNzCz1UJ/73qblzhy55IU2ADeGFF4A8uKPpyp4kJO6CUh0fSOm0yYe209IN7A1JKn+ecJmg1U73O/Kufyuy78Vs/Ld2YY1M3b6F/ymkBKbekaDW2taBZtnRMLob0kJgBwle/hGooIj9+aZbE6iPNkXoUynPBc48zkRLdwmBm1lMizBvokf1W828ClGPPU1F/Yd6TPP9fq6LfW42VOg X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110)(788757137089); X-MS-Exchange-SenderADCheck: 1 X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(3231311)(944501410)(52105095)(93006095)(93003095)(10201501046)(3002001)(6055026)(149027)(150027)(6041310)(20161123560045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123564045)(20161123558120)(20161123562045)(201708071742011)(7699016); SRVR:BY2PR12MB0241; BCL:0; PCL:0; RULEID:; SRVR:BY2PR12MB0241; X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0241; 4:F6EXobrsWc3xIv6w2ASxj/sdgGg4VZi89fTvpSaPyWtGyGFDBLGAlN+mIAFzP5NYBPFpk4Q0D6u7JErRDnDtElb01rDfk8Bd2lEakHko3a8ipPU/jBjRwvYdzOknjFR9ewBdDIHt4lF+w00K0DCd1iznyUYXWYjVLbirs4hNZmudXt8xwW5dGFFnOgeAm0HK3WjkhwgCpYM/QkWl/f0yIGMNwEO1POCknHfxOv0W9mx2+X5aq9Cj9PpZ2hCMISD6LIpcCz9yK90n9jKMntBP+YYjXM7Kb5y68pX0q6DDa6eGO1cBuCO5ZYDzKS2dnq+htIB3vJCLKItEFgOcL3OsEg== X-Forefront-PRVS: 0773BB46AC X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BY2PR12MB0241; 23:beR6TtBpQtk4v6grRlRzCG0Zg9kPudCqfaUtbbYyf?= oE+thogsF9yQ34cAvrYpWndIYL3nhb1FEV496l/oaKHsauwGDhb6O2Vxb1idW+xsfWrjAyeEQBABuuAJ1bLwWkQsUu98TCCPwsqwQEwh5KOe8uhYqqK+sNreGvYRhopTuyaAI25M7EUE3DOZTA9qPTYjwCRflWCOVOegMxCvXhUZi0XdimVvy6eOcsGbBDb+YFAEdsPo7HhPCpS+AAlWeIDxq17gdZZPoP5KV4uPEKQytijkkV3i27iNguutTg/m86yc8sMMy1Gg58btabWE4xU59SOCiErihKOwcJRChmCPTkTrL39rjJaAase4SytDZtBQZ2NXTN1eaosJIsDiEk71AElf52YwOD6u/vRHOF+pobR2SdcV8YRLHymaYHcPlg692PWoUIgBDyKH0R2RoPFU0PXD3weR32IeyymARI/upOHKRpQp+tHRM08XF4mcSXLFjn5uS58aE924XPMMUZ+gVtYFMGFta9Q9wXIYZi2eihYSCgRUoRR6KNXYXOOA2Xjix//GXaRW429Go4juDOi4xFZ6ajnG7NAwncCc6XnFWFNcEOzSGswgdYoHp5IiGN3Mdw2/CDftsj7d2I3CBYkJTxmUEgkWfDj6gkZP73k21dw47gJmJR/PfWtH/i49WPXsHOCZ1JRIDFCYcLfXiSer8R6xB/RpOssMmoFusVod2cvxmRrBiPCq1y8lERugpRNb3EB4sVyIPoX0+jRhl84d4V8V/wR9YrtOhVar9gsB+sIHifVPN9+MCukD58Bj6glxHOuxyWeStJAbK/HayvCPLl8+HLG0Iym193cWz9SeJe/tfY35MdkW/nBkO+oDpvP0kJdNJq37tCMY1c6DpSKEnw9BOVHIWqDBeR/KbhlwtpO8P2CW8A5rfwBEvBwePv9yfP2L9Vtffl/0ToYcVpTis4R7t2+xjZUXwy9qrp3uHuLKw2VDL+feCPWPb8br9qxoY/dPG734a9kHyyiDKOwXsqQLnEQsPAlDs+N+kRhD96YhL6bJIsEER69zsbYsy/dT5hx3nLaA8Qjx/E2UMe0dOjRB0JToNGOC2Eh8pgnIFW3rxNTaqWzmg7R3WrsLF4bj8PXjar5TbSc3qsPYD4jG1G5jO2HzZv5NT1GEvmg3CDwm+KfK2ZGulxru14nJAAbOwkso9yHCkv8/Jw80c38vp6MffhW3ug5cH0OHhTdZQ== X-Microsoft-Antispam-Message-Info: e2bOA+C5uBmZxscyqnvp8OdCVOIu/YXx/POqaZxRYwnRiOValv4BAoIQZ1PuNECPXmLhwYej+kydG8drRxoqZAFl4wjb4fUTtTZeUA3pO2lwBEGG7zckZ7y0tzYRKQ296SFmFFHtj49ZchaDa3aBs3yCn9aJyeysPNBpDcdUNMUyJ35fVBpPQAnSjGI7y7Sa5CMJaZ2ttOEHQbMAPISZcds1WEjfr70fnq/6TnlzdIJ5U21rIDbN1QFyVfzYgn1vIk7u09jzz8LWY2EfVsyMP/btqorDzS5ySCyfo/3/uPBunIThsJ3jbj0upZ+wnSTfDbZhkNc3Unt6TXaIazXXIRnFVfcbFImHcs9icvQ2BFQ= X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0241; 6:almmKTF8+tZ8zXrL2wjZ6GLWsB0usAXFEZc2R8+IV1kAT2//emqCGx9wgZEBT3ZWxjhnvK1PfnW7s1pDs28xAjNy7/hinbs5JyPKalT68M/Xd0oTkFoLT3warIY8x09PqAZicJSZzj/V3wMHgci1fa7Dc0V1jxMEEevPzh8Noxxa+MqS2XF9k81LHGf/r4LRnRknBola5KjIQ8PaSxirpAncF1pGeGx1F99rFo9LTph/rkLFHI8tiU5+sOrqY1HjI+DzLn1bPdKjCHjt1v44FgEXgXF+IbJBWqQR8/H3KQ4OXJgh1aVejEzJNEjtBbup+SrtpxPpn2ouL5UUCUjF/QE8Xy+KkCFew5U0yt6TJYs9x2hwOpi+rVJHliDBBRCbXMg+5jgatPtKVSxWk/nS6xKoGFI9bxEew1BTRG2oh5gQJLO84MTb91/36of14qfcYuiD3Sa8EICj95tSebwZPw==; 5:dHkRf5GJH572FYYEpwqIykXuMRB/Nt9m2incNMwUIth3NjlpoyUfyvt46jAWgwtZdzcjlFibACPS7xSpjiltBDXJXr3Bg/RPTBp5nyf1co4qHT288iurIDI4lH2PtwGSh/9x9cU7zsSk0eFWqfLUGNKeCHAWGu+4AgZfFNBLFrw=; 7:4CbOV7FB2aTAjcwoU/qCGeY40QFPWDxtm5N5NlsRX/K9B0FXpJWXpQaLXtrkThUAKflwOUvOro+ji7CiY71Gr+a8Z3zQz70ggvycwiKXc+mCbibAvWDJNqRLDZCE+BToVfakKM7zvE+v7se8lZu3VA+ykRiY3hGSZNNoI660ZHgxN4FxMCK1YqWvt4i00oet5iY2ICJL2KKCYGPJgh2gQKvOmHhvbCa4s9IB+6kJqW6VSvhx52wNFoxMW9jAHa9O SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0241; 20:2bbkGV09ft2YsLwH5nlCtAYGkUTpq0iR1BlRgM1nJtaaqRcMtiHytUhkm3+kLquvdYec66reRCv7VSwRPwJWDMjM9y2WX6Qzq43dh2zcctTFIzV3BHriObE/VZq49mI5wz+zdoptfi/WAyWZfPkC+A5feFY9Ibbttzky0tJr5CL9EnHz8y+PIlFSVMAtGSBf2n6miKYXOFsALcHy3UjZzsCxVclMutQG4a+tCK5VqdtlIC08hzew50aAp8O03USC X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Aug 2018 08:27:27.1747 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: b4c66ec1-f5bd-4e0c-b581-08d608d242ae X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d; Ip=[165.204.84.17]; Helo=[SATLEXCHOV02.amd.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2PR12MB0241 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: amd-gfx@lists.freedesktop.org, Daniel Rakos , Dave Airlie , Christian Konig Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP VK_KHR_timeline_semaphore: This extension introduces a new type of semaphore that has an integer payload identifying a point in a timeline. Such timeline semaphores support the following operations: * Host query - A host operation that allows querying the payload of the timeline semaphore. * Host wait - A host operation that allows a blocking wait for a timeline semaphore to reach a specified value. * Device wait - A device operation that allows waiting for a timeline semaphore to reach a specified value. * Device signal - A device operation that allows advancing the timeline semaphore to a specified value. Since it's a timeline, that means the front time point(PT) always is signaled before the late PT. a. signal PT design: Signal PT fence N depends on PT[N-1] fence and signal opertion fence, when PT[N] fence is signaled, the timeline will increase to value of PT[N]. b. wait PT design: Wait PT fence is signaled by reaching timeline point value, when timeline is increasing, will compare wait PTs value with new timeline value, if PT value is lower than timeline value, then wait PT will be signaled, otherwise keep in list. semaphore wait operation can wait on any point of timeline, so need a RB tree to order them. And wait PT could ahead of signal PT, we need a sumission fence to perform that. v2: 1. remove unused DRM_SYNCOBJ_CREATE_TYPE_NORMAL. (Christian) 2. move unexposed denitions to .c file. (Daniel Vetter) 3. split up the change to drm_syncobj_find_fence() in a separate patch. (Christian) 4. split up the change to drm_syncobj_replace_fence() in a separate patch. 5. drop the submission_fence implementation and instead use wait_event() for that. (Christian) 6. WARN_ON(point != 0) for NORMAL type syncobj case. (Daniel Vetter) TODO: 1. CPU query and wait on timeline semaphore. 2. test application (Daniel Vetter) Signed-off-by: Chunming Zhou Cc: Christian Konig Cc: Dave Airlie Cc: Daniel Rakos Cc: Daniel Vetter --- drivers/gpu/drm/drm_syncobj.c | 383 +++++++++++++++++++++++++++++++++++++++--- include/drm/drm_syncobj.h | 28 +++ include/uapi/drm/drm.h | 1 + 3 files changed, 389 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 6227df2cc0a4..f738d78edf65 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -56,6 +56,44 @@ #include "drm_internal.h" #include +struct drm_syncobj_stub_fence { + struct dma_fence base; + spinlock_t lock; +}; + +static const char *drm_syncobj_stub_fence_get_name(struct dma_fence *fence) +{ + return "syncobjstub"; +} + +static bool drm_syncobj_stub_fence_enable_signaling(struct dma_fence *fence) +{ + return !dma_fence_is_signaled(fence); +} + +static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { + .get_driver_name = drm_syncobj_stub_fence_get_name, + .get_timeline_name = drm_syncobj_stub_fence_get_name, + .enable_signaling = drm_syncobj_stub_fence_enable_signaling, + .release = NULL, +}; + +struct drm_syncobj_wait_pt { + struct drm_syncobj_stub_fence base; + u64 value; + struct rb_node node; +}; +struct drm_syncobj_signal_pt { + struct drm_syncobj_stub_fence base; + struct dma_fence *signal_fence; + struct dma_fence *pre_pt_base; + struct dma_fence_cb signal_cb; + struct dma_fence_cb pre_pt_cb; + struct drm_syncobj *syncobj; + u64 value; + struct list_head list; +}; + /** * drm_syncobj_find - lookup and reference a sync object. * @file_private: drm file private pointer @@ -137,6 +175,150 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, spin_unlock(&syncobj->lock); } +static void drm_syncobj_timeline_signal_wait_pts(struct drm_syncobj *syncobj) +{ + struct rb_node *node = NULL; + struct drm_syncobj_wait_pt *wait_pt = NULL; + + spin_lock(&syncobj->lock); + for(node = rb_first(&syncobj->syncobj_timeline.wait_pt_tree); + node != NULL; ) { + wait_pt = rb_entry(node, struct drm_syncobj_wait_pt, node); + node = rb_next(node); + if (wait_pt->value <= syncobj->syncobj_timeline.timeline) { + dma_fence_signal(&wait_pt->base.base); + rb_erase(&wait_pt->node, + &syncobj->syncobj_timeline.wait_pt_tree); + RB_CLEAR_NODE(&wait_pt->node); + /* kfree(wait_pt) is excuted by fence put */ + dma_fence_put(&wait_pt->base.base); + } else { + /* the loop is from left to right, the later entry value is + * bigger, so don't need to check any more */ + break; + } + } + spin_unlock(&syncobj->lock); +} + + +static void pt_fence_cb(struct drm_syncobj_signal_pt *signal_pt) +{ + struct dma_fence *fence = NULL; + struct drm_syncobj *syncobj; + + fence = signal_pt->signal_fence; + signal_pt->signal_fence = NULL; + dma_fence_put(fence); + fence = signal_pt->pre_pt_base; + signal_pt->pre_pt_base = NULL; + dma_fence_put(fence); + + syncobj = signal_pt->syncobj; + spin_lock(&syncobj->lock); + list_del(&signal_pt->list); + syncobj->syncobj_timeline.timeline = signal_pt->value; + spin_unlock(&syncobj->lock); + /* kfree(signal_pt) will be executed by below fence put */ + dma_fence_put(&signal_pt->base.base); + drm_syncobj_timeline_signal_wait_pts(syncobj); +} +static void pt_signal_fence_func(struct dma_fence *fence, + struct dma_fence_cb *cb) +{ + struct drm_syncobj_signal_pt *signal_pt = + container_of(cb, struct drm_syncobj_signal_pt, signal_cb); + + if (signal_pt->pre_pt_base && + !dma_fence_is_signaled(signal_pt->pre_pt_base)) + return; + + pt_fence_cb(signal_pt); +} +static void pt_pre_fence_func(struct dma_fence *fence, + struct dma_fence_cb *cb) +{ + struct drm_syncobj_signal_pt *signal_pt = + container_of(cb, struct drm_syncobj_signal_pt, pre_pt_cb); + + if (signal_pt->signal_fence && + !dma_fence_is_signaled(signal_pt->pre_pt_base)) + return; + + pt_fence_cb(signal_pt); +} + +static int drm_syncobj_timeline_replace_fence(struct drm_syncobj *syncobj, + struct dma_fence *fence, + u64 point) +{ + struct drm_syncobj_signal_pt *signal_pt = + kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL); + struct drm_syncobj_signal_pt *tail_pt; + struct dma_fence *tail_pt_fence = NULL; + int ret = 0; + + if (!signal_pt) + return -ENOMEM; + if (syncobj->syncobj_timeline.signal_point >= point) { + DRM_WARN("A later signal is ready!"); + goto out; + } + if (fence) + dma_fence_get(fence); + spin_lock(&syncobj->lock); + spin_lock_init(&signal_pt->base.lock); + dma_fence_init(&signal_pt->base.base, + &drm_syncobj_stub_fence_ops, + &signal_pt->base.lock, + syncobj->syncobj_timeline.timeline_context, point); + signal_pt->signal_fence = + rcu_dereference_protected(fence, + lockdep_is_held(&fence->lock)); + if (!list_empty(&syncobj->syncobj_timeline.signal_pt_list)) { + tail_pt = list_last_entry(&syncobj->syncobj_timeline.signal_pt_list, + struct drm_syncobj_signal_pt, list); + tail_pt_fence = &tail_pt->base.base; + if (dma_fence_is_signaled(tail_pt_fence)) + tail_pt_fence = NULL; + } + if (tail_pt_fence) + signal_pt->pre_pt_base = + dma_fence_get(rcu_dereference_protected(tail_pt_fence, + lockdep_is_held(&tail_pt_fence->lock))); + + signal_pt->value = point; + syncobj->syncobj_timeline.signal_point = point; + signal_pt->syncobj = syncobj; + INIT_LIST_HEAD(&signal_pt->list); + list_add_tail(&signal_pt->list, &syncobj->syncobj_timeline.signal_pt_list); + spin_unlock(&syncobj->lock); + wake_up_all(&syncobj->syncobj_timeline.wq); + /** + * Every pt is depending on signal fence and previous pt fence, add + * callbacks to them + */ + if (!dma_fence_is_signaled(signal_pt->signal_fence)) + dma_fence_add_callback(signal_pt->signal_fence, + &signal_pt->signal_cb, + pt_signal_fence_func); + else + pt_signal_fence_func(signal_pt->signal_fence, + &signal_pt->signal_cb); + if (signal_pt->pre_pt_base && !dma_fence_is_signaled(signal_pt->pre_pt_base)) + dma_fence_add_callback(signal_pt->pre_pt_base, + &signal_pt->pre_pt_cb, + pt_pre_fence_func); + else + pt_pre_fence_func(signal_pt->pre_pt_base, &signal_pt->pre_pt_cb); + + + return 0; +out: + kfree(signal_pt); + return ret; +} + /** * drm_syncobj_replace_fence - replace fence in a sync object. * @syncobj: Sync object to replace fence in @@ -152,6 +334,11 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, struct dma_fence *old_fence; struct drm_syncobj_cb *cur, *tmp; + if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) { + drm_syncobj_timeline_replace_fence(syncobj, fence, + point); + return; + } if (fence) dma_fence_get(fence); @@ -174,28 +361,6 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, } EXPORT_SYMBOL(drm_syncobj_replace_fence); -struct drm_syncobj_stub_fence { - struct dma_fence base; - spinlock_t lock; -}; - -static const char *drm_syncobj_stub_fence_get_name(struct dma_fence *fence) -{ - return "syncobjstub"; -} - -static bool drm_syncobj_stub_fence_enable_signaling(struct dma_fence *fence) -{ - return !dma_fence_is_signaled(fence); -} - -static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { - .get_driver_name = drm_syncobj_stub_fence_get_name, - .get_timeline_name = drm_syncobj_stub_fence_get_name, - .enable_signaling = drm_syncobj_stub_fence_enable_signaling, - .release = NULL, -}; - static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) { struct drm_syncobj_stub_fence *fence; @@ -215,6 +380,121 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) return 0; } +static struct drm_syncobj_wait_pt * +drm_syncobj_timeline_lookup_wait_pt(struct drm_syncobj *syncobj, u64 point) +{ + struct rb_node *node = syncobj->syncobj_timeline.wait_pt_tree.rb_node; + struct drm_syncobj_wait_pt *wait_pt = NULL; + + + spin_lock(&syncobj->lock); + while(node) { + int result = point - wait_pt->value; + + wait_pt = rb_entry(node, struct drm_syncobj_wait_pt, node); + if (result < 0) + node = node->rb_left; + else if (result > 0) + node = node->rb_right; + else + break; + } + spin_unlock(&syncobj->lock); + + return wait_pt; +} + +static struct drm_syncobj_wait_pt * +drm_syncobj_timeline_create_wait_pt(struct drm_syncobj *syncobj, u64 point) +{ + struct drm_syncobj_wait_pt *wait_pt; + struct rb_node **new = &(syncobj->syncobj_timeline.wait_pt_tree.rb_node), *parent = NULL; + + wait_pt = kzalloc(sizeof(*wait_pt), GFP_KERNEL); + if (!wait_pt) + return NULL; + spin_lock_init(&wait_pt->base.lock); + dma_fence_init(&wait_pt->base.base, + &drm_syncobj_stub_fence_ops, + &wait_pt->base.lock, + syncobj->syncobj_timeline.timeline_context, point); + wait_pt->value = point; + + /* wait pt must be in an order, so that we can easily lookup and signal + * it */ + spin_lock(&syncobj->lock); + if (point <= syncobj->syncobj_timeline.timeline) + dma_fence_signal(&wait_pt->base.base); + while(*new) { + struct drm_syncobj_wait_pt *this = + rb_entry(*new, struct drm_syncobj_wait_pt, node); + int result = wait_pt->value - this->value; + + parent = *new; + if (result < 0) + new = &((*new)->rb_left); + else if (result > 0) + new = &((*new)->rb_right); + else + goto exist; + } + + rb_link_node(&wait_pt->node, parent, new); + rb_insert_color(&wait_pt->node, &syncobj->syncobj_timeline.wait_pt_tree); + spin_unlock(&syncobj->lock); + return wait_pt; +exist: + spin_unlock(&syncobj->lock); + dma_fence_put(&wait_pt->base.base); + wait_pt = drm_syncobj_timeline_lookup_wait_pt(syncobj, point); + return wait_pt; +} + +static struct dma_fence * +drm_syncobj_timeline_point_get(struct drm_syncobj *syncobj, u64 point, u64 flag) +{ + struct drm_syncobj_wait_pt *wait_pt; + + /* already signaled, simply return a signaled stub fence */ + if (point <= syncobj->syncobj_timeline.timeline) { + struct drm_syncobj_stub_fence *fence; + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (fence == NULL) + return NULL; + + spin_lock_init(&fence->lock); + dma_fence_init(&fence->base, &drm_syncobj_stub_fence_ops, + &fence->lock, 0, 0); + dma_fence_signal(&fence->base); + return &fence->base; + } + + /* check if the wait pt exists */ + wait_pt = drm_syncobj_timeline_lookup_wait_pt(syncobj, point); + if (!wait_pt) { + /* This is a new wait pt, so create it */ + wait_pt = drm_syncobj_timeline_create_wait_pt(syncobj, point); + if (!wait_pt) + return NULL; + } + if (wait_pt) { + struct dma_fence *fence; + int ret = + wait_event_interruptible_timeout(syncobj->syncobj_timeline.wq, + wait_pt->value <= syncobj->syncobj_timeline.signal_point, + msecs_to_jiffies(10000)); /* wait 10s */ + + if (ret <= 0) + return NULL; + rcu_read_lock(); + fence = dma_fence_get_rcu(&wait_pt->base.base); + rcu_read_unlock(); + return fence; + } + return NULL; +} + /** * drm_syncobj_find_fence - lookup and reference the fence in a sync object * @file_private: drm file private pointer @@ -240,7 +520,17 @@ int drm_syncobj_find_fence(struct drm_file *file_private, if (!syncobj) return -ENOENT; - *fence = drm_syncobj_fence_get(syncobj); + if (syncobj->type == DRM_SYNCOBJ_TYPE_NORMAL) { + /* NORMAL syncobj doesn't care point value */ + WARN_ON(point != 0); + *fence = drm_syncobj_fence_get(syncobj); + } else if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) { + *fence = drm_syncobj_timeline_point_get(syncobj, point, + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT); + } else { + DRM_ERROR("Don't support this type syncobj\n"); + *fence = NULL; + } if (!*fence) { ret = -EINVAL; } @@ -249,6 +539,34 @@ int drm_syncobj_find_fence(struct drm_file *file_private, } EXPORT_SYMBOL(drm_syncobj_find_fence); +static void drm_syncobj_timeline_fini(struct drm_syncobj *syncobj, + struct drm_syncobj_timeline *syncobj_timeline) +{ + struct rb_node *node = NULL; + struct drm_syncobj_wait_pt *wait_pt = NULL; + struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp; + + spin_lock(&syncobj->lock); + for(node = rb_first(&syncobj_timeline->wait_pt_tree); + node != NULL; ) { + wait_pt = rb_entry(node, struct drm_syncobj_wait_pt, node); + node = rb_next(node); + rb_erase(&wait_pt->node, + &syncobj_timeline->wait_pt_tree); + RB_CLEAR_NODE(&wait_pt->node); + /* kfree(wait_pt) is excuted by fence put */ + dma_fence_put(&wait_pt->base.base); + } + list_for_each_entry_safe(signal_pt, tmp, + &syncobj_timeline->signal_pt_list, list) { + list_del(&signal_pt->list); + dma_fence_put(signal_pt->signal_fence); + dma_fence_put(signal_pt->pre_pt_base); + dma_fence_put(&signal_pt->base.base); + } + spin_unlock(&syncobj->lock); +} + /** * drm_syncobj_free - free a sync object. * @kref: kref to free. @@ -261,10 +579,23 @@ void drm_syncobj_free(struct kref *kref) struct drm_syncobj, refcount); drm_syncobj_replace_fence(syncobj, NULL, 0); + drm_syncobj_timeline_fini(syncobj, &syncobj->syncobj_timeline); kfree(syncobj); } EXPORT_SYMBOL(drm_syncobj_free); +static void drm_syncobj_timeline_init(struct drm_syncobj_timeline + *syncobj_timeline) +{ + syncobj_timeline->timeline_context = dma_fence_context_alloc(1); + syncobj_timeline->timeline = 0; + syncobj_timeline->signal_point = 0; + init_waitqueue_head(&syncobj_timeline->wq); + + syncobj_timeline->wait_pt_tree = RB_ROOT; + INIT_LIST_HEAD(&syncobj_timeline->signal_pt_list); +} + /** * drm_syncobj_create - create a new syncobj * @out_syncobj: returned syncobj @@ -290,6 +621,12 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, kref_init(&syncobj->refcount); INIT_LIST_HEAD(&syncobj->cb_list); spin_lock_init(&syncobj->lock); + if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE) { + syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE; + drm_syncobj_timeline_init(&syncobj->syncobj_timeline); + } else { + syncobj->type = DRM_SYNCOBJ_TYPE_NORMAL; + } if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) { ret = drm_syncobj_assign_null_handle(syncobj); diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index 335ec501001a..342b3ced3e56 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -30,6 +30,25 @@ struct drm_syncobj_cb; +enum drm_syncobj_type { + DRM_SYNCOBJ_TYPE_NORMAL, + DRM_SYNCOBJ_TYPE_TIMELINE +}; + +struct drm_syncobj_timeline { + wait_queue_head_t wq; + u64 timeline_context; + /** + * @timeline: syncobj timeline + */ + u64 timeline; + u64 signal_point; + + + struct rb_root wait_pt_tree; + struct list_head signal_pt_list; +}; + /** * struct drm_syncobj - sync object. * @@ -40,6 +59,15 @@ struct drm_syncobj { * @refcount: Reference count of this object. */ struct kref refcount; + /** + * @type: indicate syncobj type + */ + enum drm_syncobj_type type; + /** + * @syncobj_timeline: timeline + */ + struct drm_syncobj_timeline syncobj_timeline; + /** * @fence: * NULL or a pointer to the fence bound to this object. diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 300f336633f2..cebdb2541eb7 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -717,6 +717,7 @@ struct drm_prime_handle { struct drm_syncobj_create { __u32 handle; #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0) +#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1) __u32 flags; };