From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1B53FC48BC3 for ; Wed, 21 Feb 2024 12:23:40 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 79AB189B01; Wed, 21 Feb 2024 12:23:39 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=amd.com header.i=@amd.com header.b="gpuKFz0k"; dkim-atps=neutral Received: from NAM04-MW2-obe.outbound.protection.outlook.com (mail-mw2nam04on2089.outbound.protection.outlook.com [40.107.101.89]) by gabe.freedesktop.org (Postfix) with ESMTPS id D9DC210E724; Wed, 21 Feb 2024 12:23:38 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=An5mA+C1LmcQs/lcXo6evw9VDu/xIKdncgIgJKjbEeWfG3PjfUJQptlRmD7llxRnxE8GAY8XQuVanKTeRwe/Z223Mwt9il43f8qR541GzdmwDZLClbPxw67Ca87p3fgSMUd0gu1e2hPhNoaFC3TARcyuuRTRP+ozlIJ1thm9hjAQPMEeGW01z0nrev2x7QpLxI72zWldJsgzo8/j6US+cXMJil0jncZWdFSL/DV152dgZtBS7vhGP0wabte3CGWpdzjGQCrU3EPjbhN+1NFjmy7ibH0R+P+xGnkenNWJhcS28W2DmwHzyq+cI9M4bglnSRSM5vPLY70MEMB0yi5f+A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=sGpHBZv3WpCSl6C2B5CgqNL8wJ8Za6o0fuEDR1J6SFg=; b=TBBg8bUAcvnZy0MqpUJdXR2v/ks26mpdfUvYs6ERjkP3nVPoM5hj7QscWJZMVWR63Rvt69VP4D+rst07dLDMb+F+rZQvbQEC20MDQO6k8lS8PZwfQ5iIWFOIC6nftpqVF7urQXIMFPvNfJdOnTnwTa2+DV763aa7JABI2emf+88VKPQowM8p+DpLWxyjjaPvBZFu0nHffapka+y9aL8NdcRHIcAlFQV8hIrmw4AcZsQVV/A+Hem/aWiCptZuq+HRvb/0+EBGUYV4qpWGEn5+DWiMvC7YEkUafg/rPCzcReuJq4WwqkOtJ/RRHeHL8KTHXcngzi+c9fBin0RuS+an5A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=amd.com; dmarc=pass action=none header.from=amd.com; dkim=pass header.d=amd.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=sGpHBZv3WpCSl6C2B5CgqNL8wJ8Za6o0fuEDR1J6SFg=; b=gpuKFz0kQ73NdUtxQpHtLeASGLv2dy6A10whRq4TwbKzqtv3UHayqfeL9JF3e8e1LrJ/gKILQmJxJcLo95RTuE0xnb7sI8lbO0pR+E9Fg/JjegB9yLwskZlx3l5NjKACl8l2k/ZENJ0S4za7/KjYAyDETwVVffVd8z1kXMOpD5Y= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=amd.com; Received: from MN2PR12MB4342.namprd12.prod.outlook.com (2603:10b6:208:264::7) by PH0PR12MB8125.namprd12.prod.outlook.com (2603:10b6:510:293::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7316.20; Wed, 21 Feb 2024 12:23:35 +0000 Received: from MN2PR12MB4342.namprd12.prod.outlook.com ([fe80::c05f:756d:717e:e7c6]) by MN2PR12MB4342.namprd12.prod.outlook.com ([fe80::c05f:756d:717e:e7c6%6]) with mapi id 15.20.7316.018; Wed, 21 Feb 2024 12:23:35 +0000 Message-ID: <1936c7a5-79cf-4a12-b27e-e929ad97d3e1@amd.com> Date: Wed, 21 Feb 2024 17:53:27 +0530 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v6 1/3] drm/buddy: Implement tracking clear page feature To: Matthew Auld , dri-devel@lists.freedesktop.org, amd-gfx@lists.freedesktop.org, intel-gfx@lists.freedesktop.org Cc: christian.koenig@amd.com, alexander.deucher@amd.com, felix.kuehling@amd.com, mario.limonciello@amd.com References: <20240208155000.339325-1-Arunpravin.PaneerSelvam@amd.com> <09ad8b68-f91a-4ce0-aaa6-1eb29c120a06@intel.com> Content-Language: en-US From: "Paneer Selvam, Arunpravin" In-Reply-To: <09ad8b68-f91a-4ce0-aaa6-1eb29c120a06@intel.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-ClientProxiedBy: BMXP287CA0004.INDP287.PROD.OUTLOOK.COM (2603:1096:b00:2c::23) To MN2PR12MB4342.namprd12.prod.outlook.com (2603:10b6:208:264::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: MN2PR12MB4342:EE_|PH0PR12MB8125:EE_ X-MS-Office365-Filtering-Correlation-Id: dcffc466-8585-4f00-3f8d-08dc32d7ecf4 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: JeerbwFWO3fSiu4g2rbd+/D75zsbYNMBlenT9knhoUEd72aSrQBv0x6vY8/Ws6SzpqqxGI4Vy179O7gXLlrjdHgnPrRaprgLOAahuYVL+7HttxwEbvWvQTUMLixL2lkjlHQm5FgBrpviKQ4pRe9l7kYxJUj41lSUyhATnYAeArhnJ52vHrdECFYZagPbuODaGd9jJM69Eo7BdB5VV5a7yUkR1xF9DE3KP3udOuKmMs/HVVM6swZDmTglYoTNFnaMZgGEKRfANF2GOVB4PRFHW7UzseQ3/uU/eY5+ara4wyTwDzxQrcSnSLDViBhLZNAAlOgzCqPOZichGim4dF+N0A1VXsxJ//IdfK2DLQVj8w7pfR5anuKjES3Q5EY/yPv8pebyKN1PwjR0kros9fMWj89mXydTQEIvILzh9U7JCNHRMeNWYnKXzGhDkxUxRWBe4ZPJUwxhWtoRm8Wi4nW+6OVYoc6KdJqHCcYWBxKn2DzK4dDxNAGdCiStPCnzYlz6uE410SB8Ceufw3DZY7rGm1cX9Vka/bhz046CSci+0Mpyu1OAjS8Nlnqz8RVPxMf8 X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:MN2PR12MB4342.namprd12.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(230273577357003); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?NmJTSmZIWUl1ZUY4ZEJRODlGQk9WMEtITjBEenhzZXJNQ1d0RXhXOGE0YmtT?= =?utf-8?B?YkV6Z0lRYnBOVDhKZWlCUE9talBMVzFrTXhPQ3lrN1NxWFFJMW1oZC81YjEy?= =?utf-8?B?SmlKYWFNNUw4TnZWQzJWUzZIV1EvWE9zNEhTU0lzcjl5MURleWQ4YlI5VkVT?= =?utf-8?B?VlFnZ2NjVjZXWkhmTUp6eGdISGtUOGJZNmpFd0kzQTFDK01iSE9YRTFIY1ZC?= =?utf-8?B?ZStTYm00eTZmdWxlVm9LcmNzWkQyYytkUm9zdGlMSExmRmxiT1BvdTJLb252?= =?utf-8?B?dmJHckc5eUo4OHZKTlg1WHplcjRPZlR6S3VHVUZFNEtRaVpEQk1OV1lrR3li?= =?utf-8?B?NUI0MnZ6RXQ4Njc3N3A1UFdZUDFOMUhqeDAxVy9ocHMrNSt3VHBBdzByRjIv?= =?utf-8?B?d0FQZ2RRbnViSHpOY0RldnpERFMyT3lZaUQ3bkdOVXlJQlR0TnVMNkFsSHc0?= =?utf-8?B?NGZyanliSjRMZ3FOZm05YmhOQlozOWQ1bnU0RzMzeVM1ZTJ4ZzRIdDA0VnRz?= =?utf-8?B?T094eGZyVitXdG43RXdIWHM0NnNnaHAxZndEaHYxTllDZGFETWQ0TVVrcmxo?= =?utf-8?B?WmNHclBSRGYxaTlhbU5JYnFXS3VyeFFWaHFjM2MxeUpHa0ZnVmY5c1pvRVFq?= =?utf-8?B?SlFxenRlQnA4dWFDQTl6dTI0czlDRTl0ZWU2ZmZDUCtTL0wxdmtUU3YvMC9l?= =?utf-8?B?VVpHUDdkS0M0QnJOQW9iYzdHRW5VaEZGMm1uNzd0bjF2VjRxVHRVaXFnc3hw?= =?utf-8?B?bHBqblBhdk5PR3IveEdRWi8wNGJyRzVRM2NwU0d3RE9ZdUlLalZ4VmN5YVl4?= =?utf-8?B?ckVRdzBIOEQ1V0RMb2RTNEpObWhJN1loU1I3UGNuejRpTE85NnhPL0lWbHJV?= =?utf-8?B?UmtUeXpkUGhMV21ySG5YUkVEQk51Y285RE8xRkg5QlZnM3pvVUxDZldyUXNo?= =?utf-8?B?R1JzLzlkZnZsUTNEZ2RZMGRXbHNCS3JxM0RoZ0t0Z3FJYzN4aHRCK1JIM3F5?= =?utf-8?B?bUwxNFBKRlBoYkNxd25oSlJZa2RNWXYxdjZMakR3TzhkTjV2U1FiWTU1d2pC?= =?utf-8?B?eXdOcE9jNGxhSUVQQjZoa2VremRqUTcxblVrTDdnMVlzdGE3OGRFV1hJZGg0?= =?utf-8?B?aFJQdFVEeXJhSXZrdXUzU21uMTliNGJUTnpSSkZlWVBWV05QdXVyd051bDl3?= =?utf-8?B?VmJsZy8weVIvdzhCYjJGVlRRRlNTdHVuVy8yNVB1TmR2NjVIZERMQ3JsZ3VR?= =?utf-8?B?d2lld0pLK0pjOWtJTWY3Mi90VTFCYWZEaVArVjJWb3B6Mi9iUE1GbTJyYzhs?= =?utf-8?B?ZVFpczM2b1JoSndpcm9TYldWaTNIUHlFSEdJZ095NEZmUzNVVUM0dlQ1MVdC?= =?utf-8?B?cVhPSHl5OU1oOWpEVk5qZWlUa0NWVW9xbGN0WTE2eUF5Z0s4T09VWEp0ckR4?= =?utf-8?B?MW1KS1dSRllyNFMvWStkQjA2UlN4eE5zZXNXMHdYajlaMW96RDVPMFIrWUlU?= =?utf-8?B?ZmFJUnhVU01aSnVBRWJBdGEwY2lmRkhDSU43cTFaSzQxMURId2pvT2JlU0tx?= =?utf-8?B?YkUyR3NOUTljQmw2ZXBuZk5Zd0Vrck9vSFVqdnMzMnBaRW92RnY0TlpaeFZF?= =?utf-8?B?Z1RPU0w0OWlvYkU3QTk0Wk5KN0EyUUI0d2FWdXRyQ3MyRm5xZUdVKzc3QzZi?= =?utf-8?B?MHN3Q1pOeXprYXdZSDJTU1dtcEpSdVFjSGZFcHRXYWczWnFrKzVJQ08xV25t?= =?utf-8?B?a0xsSStGcDJac0tnYy9WTnBGTzlERWJGdVg2Y0hDS0JzVDhteXF2NlkzVVVS?= =?utf-8?B?THlyelJXNHY3bnIzSXNta0ZmaXE3OGpzRDdvcVM0alltM1ZOd2dERkVaa2J6?= =?utf-8?B?TGIwRi90UXZGUVlTSXVBcUh2MDQ2SSs0ZUp2OVB6UEpmM0U0RXhTZFN1R3Mv?= =?utf-8?B?T0VIWHBwTUdXMDhsUHlZUDgrU3d2K01sWmcyQ20vS2pNM2tZTTJrbWhCWTl0?= =?utf-8?B?OHdIUEZBNHlVajFNQy9YZE5sMVVVT3NrWmYyRlFaVTNBdXllbFcyajk2TDlL?= =?utf-8?B?Z1NtOHZ0V3NPbmFxczRwLzMwNHhVYk1NR0ZjMGQvOHhwbmk2d0J6ZC8xRHZm?= =?utf-8?Q?Sx+3un7dl44JWjYSSDOEhENzB?= X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-Network-Message-Id: dcffc466-8585-4f00-3f8d-08dc32d7ecf4 X-MS-Exchange-CrossTenant-AuthSource: MN2PR12MB4342.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Feb 2024 12:23:35.7815 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: iFBWYhIj72vGsWnIegiL4Hczb8lDvQVJzuyy1FP1jcA5U6deOTW+5vAmCjDXMfimPlnrEjsUCKxvrgJSuYsDNw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH0PR12MB8125 X-BeenThere: amd-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Discussion list for AMD gfx List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: amd-gfx-bounces@lists.freedesktop.org Sender: "amd-gfx" On 2/16/2024 5:33 PM, Matthew Auld wrote: > On 08/02/2024 15:49, Arunpravin Paneer Selvam wrote: >> - Add tracking clear page feature. >> >> - Driver should enable the DRM_BUDDY_CLEARED flag if it >>    successfully clears the blocks in the free path. On the otherhand, >>    DRM buddy marks each block as cleared. >> >> - Track the available cleared pages size >> >> - If driver requests cleared memory we prefer cleared memory >>    but fallback to uncleared if we can't find the cleared blocks. >>    when driver requests uncleared memory we try to use uncleared but >>    fallback to cleared memory if necessary. >> >> - When a block gets freed we clear it and mark the freed block as >> cleared, >>    when there are buddies which are cleared as well we can merge them. >>    Otherwise, we prefer to keep the blocks as separated. >> >> v1: (Christian) >>    - Depends on the flag check DRM_BUDDY_CLEARED, enable the block as >>      cleared. Else, reset the clear flag for each block in the list. >> >>    - For merging the 2 cleared blocks compare as below, >>      drm_buddy_is_clear(block) != drm_buddy_is_clear(buddy) >> >> v2: (Matthew) >>    - Add a wrapper drm_buddy_free_list_internal for the freeing of >> blocks >>      operation within drm buddy. >>    - Write a macro block_incompatible() to allocate the required blocks. >>    - Update the xe driver for the drm_buddy_free_list change in >> arguments. >> >> Signed-off-by: Arunpravin Paneer Selvam >> >> Signed-off-by: Matthew Auld >> Suggested-by: Christian König > > Probably needs a new unit test. Sure, I am working on it. I will send in a separate patch. > > I think we are missing something to forcefully re-merge everything at > fini()? In theory we can just call the defrag routine. Otherwise we > might trigger various warnings since the root(s) might still be split. I have added the full defrag in the fini() function. Please review the patch number 3. Thanks, Arun. > > Also one nit below. Otherwise I think looks good. > >> --- >>   drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c  |   6 +- >>   drivers/gpu/drm/drm_buddy.c                   | 192 ++++++++++++++---- >>   drivers/gpu/drm/i915/i915_ttm_buddy_manager.c |   6 +- >>   drivers/gpu/drm/tests/drm_buddy_test.c        |  10 +- >>   drivers/gpu/drm/xe/xe_ttm_vram_mgr.c          |   4 +- >>   include/drm/drm_buddy.h                       |  18 +- >>   6 files changed, 187 insertions(+), 49 deletions(-) >> >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c >> b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c >> index 8db880244324..c0c851409241 100644 >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c >> @@ -571,7 +571,7 @@ static int amdgpu_vram_mgr_new(struct >> ttm_resource_manager *man, >>       return 0; >>     error_free_blocks: >> -    drm_buddy_free_list(mm, &vres->blocks); >> +    drm_buddy_free_list(mm, &vres->blocks, 0); >>       mutex_unlock(&mgr->lock); >>   error_fini: >>       ttm_resource_fini(man, &vres->base); >> @@ -604,7 +604,7 @@ static void amdgpu_vram_mgr_del(struct >> ttm_resource_manager *man, >>         amdgpu_vram_mgr_do_reserve(man); >>   -    drm_buddy_free_list(mm, &vres->blocks); >> +    drm_buddy_free_list(mm, &vres->blocks, 0); >>       mutex_unlock(&mgr->lock); >>         atomic64_sub(vis_usage, &mgr->vis_usage); >> @@ -912,7 +912,7 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device >> *adev) >>           kfree(rsv); >>         list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, >> blocks) { >> -        drm_buddy_free_list(&mgr->mm, &rsv->allocated); >> +        drm_buddy_free_list(&mgr->mm, &rsv->allocated, 0); >>           kfree(rsv); >>       } >>       if (!adev->gmc.is_app_apu) >> diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c >> index f57e6d74fb0e..33ad0cfbd54c 100644 >> --- a/drivers/gpu/drm/drm_buddy.c >> +++ b/drivers/gpu/drm/drm_buddy.c >> @@ -57,6 +57,16 @@ static void list_insert_sorted(struct drm_buddy *mm, >>       __list_add(&block->link, node->link.prev, &node->link); >>   } >>   +static void clear_reset(struct drm_buddy_block *block) >> +{ >> +    block->header &= ~DRM_BUDDY_HEADER_CLEAR; >> +} >> + >> +static void mark_cleared(struct drm_buddy_block *block) >> +{ >> +    block->header |= DRM_BUDDY_HEADER_CLEAR; >> +} >> + >>   static void mark_allocated(struct drm_buddy_block *block) >>   { >>       block->header &= ~DRM_BUDDY_HEADER_STATE; >> @@ -223,6 +233,12 @@ static int split_block(struct drm_buddy *mm, >>       mark_free(mm, block->left); >>       mark_free(mm, block->right); >>   +    if (drm_buddy_block_is_clear(block)) { >> +        mark_cleared(block->left); >> +        mark_cleared(block->right); >> +        clear_reset(block); >> +    } >> + >>       mark_split(block); >>         return 0; >> @@ -273,6 +289,13 @@ static void __drm_buddy_free(struct drm_buddy *mm, >>           if (!drm_buddy_block_is_free(buddy)) >>               break; >>   +        if (drm_buddy_block_is_clear(block) != >> +            drm_buddy_block_is_clear(buddy)) >> +            break; >> + >> +        if (drm_buddy_block_is_clear(block)) >> +            mark_cleared(parent); >> + >>           list_del(&buddy->link); >>             drm_block_free(mm, block); >> @@ -295,26 +318,61 @@ void drm_buddy_free_block(struct drm_buddy *mm, >>   { >>       BUG_ON(!drm_buddy_block_is_allocated(block)); >>       mm->avail += drm_buddy_block_size(mm, block); >> +    if (drm_buddy_block_is_clear(block)) >> +        mm->clear_avail += drm_buddy_block_size(mm, block); >> + >>       __drm_buddy_free(mm, block); >>   } >>   EXPORT_SYMBOL(drm_buddy_free_block); >>   -/** >> - * drm_buddy_free_list - free blocks >> - * >> - * @mm: DRM buddy manager >> - * @objects: input list head to free blocks >> - */ >> -void drm_buddy_free_list(struct drm_buddy *mm, struct list_head >> *objects) >> +static void __drm_buddy_free_list(struct drm_buddy *mm, >> +                  struct list_head *objects, >> +                  bool mark_clear, >> +                  bool mark_dirty) >>   { >>       struct drm_buddy_block *block, *on; >>   +    WARN_ON(mark_dirty && mark_clear); >> + >>       list_for_each_entry_safe(block, on, objects, link) { >> +        if (mark_clear) >> +            mark_cleared(block); >> +        else if (mark_dirty) >> +            clear_reset(block); >>           drm_buddy_free_block(mm, block); >>           cond_resched(); >>       } >>       INIT_LIST_HEAD(objects); >>   } >> + >> +static void drm_buddy_free_list_internal(struct drm_buddy *mm, >> +                     struct list_head *objects) >> +{ >> +    /* >> +     * Don't touch the clear/dirty bit, since allocation is still >> internal >> +     * at this point. For example we might have just failed part of the >> +     * allocation. >> +     */ >> +    __drm_buddy_free_list(mm, objects, false, false); >> +} >> + >> +/** >> + * drm_buddy_free_list - free blocks >> + * >> + * @mm: DRM buddy manager >> + * @objects: input list head to free blocks >> + * @flags: optional flags like DRM_BUDDY_CLEARED >> + */ >> +void drm_buddy_free_list(struct drm_buddy *mm, >> +             struct list_head *objects, >> +             unsigned int flags) >> +{ >> +    bool mark_clear = flags & DRM_BUDDY_CLEARED; >> + >> +    WARN_ON(flags & ~(DRM_BUDDY_CLEARED)); >> + >> +    __drm_buddy_free_list(mm, objects, mark_clear, !mark_clear); >> +} >>   EXPORT_SYMBOL(drm_buddy_free_list); >>     static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) >> @@ -327,10 +385,19 @@ static inline bool contains(u64 s1, u64 e1, u64 >> s2, u64 e2) >>       return s1 <= s2 && e1 >= e2; >>   } >>   +static bool block_incompatible(struct drm_buddy_block *block, >> unsigned int flags) >> +{ >> +    bool needs_clear = flags & DRM_BUDDY_CLEAR_ALLOCATION; >> + >> +    return needs_clear != drm_buddy_block_is_clear(block); >> +} >> + >>   static struct drm_buddy_block * >> -alloc_range_bias(struct drm_buddy *mm, >> -         u64 start, u64 end, >> -         unsigned int order) >> +__alloc_range_bias(struct drm_buddy *mm, >> +           u64 start, u64 end, >> +           unsigned int order, >> +           unsigned long flags, >> +           bool fallback) >>   { >>       struct drm_buddy_block *block; >>       struct drm_buddy_block *buddy; >> @@ -369,6 +436,9 @@ alloc_range_bias(struct drm_buddy *mm, >>             if (contains(start, end, block_start, block_end) && >>               order == drm_buddy_block_order(block)) { >> +            if (!fallback && block_incompatible(block, flags)) >> +                continue; >> + >>               /* >>                * Find the free block within the range. >>                */ >> @@ -405,25 +475,52 @@ alloc_range_bias(struct drm_buddy *mm, >>   } >>     static struct drm_buddy_block * >> -get_maxblock(struct drm_buddy *mm, unsigned int order) >> +__drm_buddy_alloc_range_bias(struct drm_buddy *mm, >> +                 u64 start, u64 end, >> +                 unsigned int order, >> +                 unsigned long flags) >>   { >> -    struct drm_buddy_block *max_block = NULL, *node; >> +    struct drm_buddy_block *block; >> +    bool fallback = 0; >> + >> +    block = __alloc_range_bias(mm, start, end, order, >> +                   flags, fallback); >> +    if (IS_ERR(block)) >> +        return __alloc_range_bias(mm, start, end, order, >> +                      flags, !fallback); >> + >> +    return block; >> +} >> + >> +static struct drm_buddy_block * >> +get_maxblock(struct drm_buddy *mm, unsigned int order, >> +         unsigned long flags) >> +{ >> +    struct drm_buddy_block *max_block = NULL, *block = NULL; >>       unsigned int i; >>         for (i = order; i <= mm->max_order; ++i) { >> -        if (!list_empty(&mm->free_list[i])) { >> -            node = list_last_entry(&mm->free_list[i], >> -                           struct drm_buddy_block, >> -                           link); >> -            if (!max_block) { >> -                max_block = node; >> +        struct drm_buddy_block *tmp_block; >> + >> +        list_for_each_entry_reverse(tmp_block, &mm->free_list[i], >> link) { >> +            if (block_incompatible(tmp_block, flags)) >>                   continue; >> -            } >>   -            if (drm_buddy_block_offset(node) > >> -                drm_buddy_block_offset(max_block)) { >> -                max_block = node; >> -            } >> +            block = tmp_block; >> +            break; >> +        } >> + >> +        if (!block) >> +            continue; >> + >> +        if (!max_block) { >> +            max_block = block; >> +            continue; >> +        } >> + >> +        if (drm_buddy_block_offset(block) > >> +            drm_buddy_block_offset(max_block)) { >> +            max_block = block; >>           } >>       } >>   @@ -440,11 +537,29 @@ alloc_from_freelist(struct drm_buddy *mm, >>       int err; >>         if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { >> -        block = get_maxblock(mm, order); >> +        block = get_maxblock(mm, order, flags); >>           if (block) >>               /* Store the obtained block order */ >>               tmp = drm_buddy_block_order(block); >>       } else { >> +        for (tmp = order; tmp <= mm->max_order; ++tmp) { >> +            struct drm_buddy_block *tmp_block; >> + >> +            list_for_each_entry_reverse(tmp_block, >> &mm->free_list[tmp], link) { >> +                if (block_incompatible(tmp_block, flags)) >> +                    continue; >> + >> +                block = tmp_block; >> +                break; >> +            } >> + >> +            if (block) >> +                break; >> +        } >> +    } >> + >> +    if (!block) { >> +        /* Fallback method */ >>           for (tmp = order; tmp <= mm->max_order; ++tmp) { >>               if (!list_empty(&mm->free_list[tmp])) { >>                   block = list_last_entry(&mm->free_list[tmp], >> @@ -454,10 +569,10 @@ alloc_from_freelist(struct drm_buddy *mm, >>                       break; >>               } >>           } >> -    } >>   -    if (!block) >> -        return ERR_PTR(-ENOSPC); >> +        if (!block) >> +            return ERR_PTR(-ENOSPC); >> +    } >>         BUG_ON(!drm_buddy_block_is_free(block)); >>   @@ -524,6 +639,8 @@ static int __alloc_range(struct drm_buddy *mm, >>               mark_allocated(block); >>               total_allocated += drm_buddy_block_size(mm, block); >>               mm->avail -= drm_buddy_block_size(mm, block); >> +            if (drm_buddy_block_is_clear(block)) >> +                mm->clear_avail -= drm_buddy_block_size(mm, block); >>               list_add_tail(&block->link, &allocated); >>               continue; >>           } >> @@ -558,7 +675,7 @@ static int __alloc_range(struct drm_buddy *mm, >>           list_splice_tail(&allocated, blocks); >>           *total_allocated_on_err = total_allocated; >>       } else { >> -        drm_buddy_free_list(mm, &allocated); >> +        drm_buddy_free_list_internal(mm, &allocated); >>       } >>         return err; >> @@ -624,11 +741,11 @@ static int __alloc_contig_try_harder(struct >> drm_buddy *mm, >>               list_splice(&blocks_lhs, blocks); >>               return 0; >>           } else if (err != -ENOSPC) { >> -            drm_buddy_free_list(mm, blocks); >> +            drm_buddy_free_list_internal(mm, blocks); >>               return err; >>           } >>           /* Free blocks for the next iteration */ >> -        drm_buddy_free_list(mm, blocks); >> +        drm_buddy_free_list_internal(mm, blocks); >>       } >>         return -ENOSPC; >> @@ -684,6 +801,8 @@ int drm_buddy_block_trim(struct drm_buddy *mm, >>       list_del(&block->link); >>       mark_free(mm, block); >>       mm->avail += drm_buddy_block_size(mm, block); >> +    if (drm_buddy_block_is_clear(block)) >> +        mm->clear_avail += drm_buddy_block_size(mm, block); >>         /* Prevent recursively freeing this node */ >>       parent = block->parent; >> @@ -695,6 +814,8 @@ int drm_buddy_block_trim(struct drm_buddy *mm, >>       if (err) { >>           mark_allocated(block); >>           mm->avail -= drm_buddy_block_size(mm, block); >> +        if (drm_buddy_block_is_clear(block)) >> +            mm->clear_avail -= drm_buddy_block_size(mm, block); >>           list_add(&block->link, blocks); >>       } >>   @@ -782,7 +903,8 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, >>           do { >>               if (flags & DRM_BUDDY_RANGE_ALLOCATION) >>                   /* Allocate traversing within the range */ >> -                block = alloc_range_bias(mm, start, end, order); >> +                block = __drm_buddy_alloc_range_bias(mm, start, end, >> +                                     order, flags); >>               else >>                   /* Allocate from freelist */ >>                   block = alloc_from_freelist(mm, order, flags); >> @@ -808,6 +930,8 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, >>             mark_allocated(block); >>           mm->avail -= drm_buddy_block_size(mm, block); >> +        if (drm_buddy_block_is_clear(block)) >> +            mm->clear_avail -= drm_buddy_block_size(mm, block); >>           kmemleak_update_trace(block); >>           list_add_tail(&block->link, &allocated); >>   @@ -846,7 +970,7 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, >>       return 0; >>     err_free: >> -    drm_buddy_free_list(mm, &allocated); >> +    drm_buddy_free_list_internal(mm, &allocated); >>       return err; >>   } >>   EXPORT_SYMBOL(drm_buddy_alloc_blocks); >> @@ -879,8 +1003,8 @@ void drm_buddy_print(struct drm_buddy *mm, >> struct drm_printer *p) >>   { >>       int order; >>   -    drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: >> %lluMiB\n", >> -           mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20); >> +    drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: >> %lluMiB, clear_free: %lluMiB\n", >> +           mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, >> mm->clear_avail >> 20); >>         for (order = mm->max_order; order >= 0; order--) { >>           struct drm_buddy_block *block; >> diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c >> b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c >> index 0d735d5c2b35..942345548bc3 100644 >> --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c >> +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c >> @@ -126,7 +126,7 @@ static int i915_ttm_buddy_man_alloc(struct >> ttm_resource_manager *man, >>       return 0; >>     err_free_blocks: >> -    drm_buddy_free_list(mm, &bman_res->blocks); >> +    drm_buddy_free_list(mm, &bman_res->blocks, 0); >>       mutex_unlock(&bman->lock); >>   err_free_res: >>       ttm_resource_fini(man, &bman_res->base); >> @@ -141,7 +141,7 @@ static void i915_ttm_buddy_man_free(struct >> ttm_resource_manager *man, >>       struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); >>         mutex_lock(&bman->lock); >> -    drm_buddy_free_list(&bman->mm, &bman_res->blocks); >> +    drm_buddy_free_list(&bman->mm, &bman_res->blocks, 0); >>       bman->visible_avail += bman_res->used_visible_size; >>       mutex_unlock(&bman->lock); >>   @@ -345,7 +345,7 @@ int i915_ttm_buddy_man_fini(struct ttm_device >> *bdev, unsigned int type) >>       ttm_set_driver_manager(bdev, type, NULL); >>         mutex_lock(&bman->lock); >> -    drm_buddy_free_list(mm, &bman->reserved); >> +    drm_buddy_free_list(mm, &bman->reserved, 0); >>       drm_buddy_fini(mm); >>       bman->visible_avail += bman->visible_reserved; >>       WARN_ON_ONCE(bman->visible_avail != bman->visible_size); >> diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c >> b/drivers/gpu/drm/tests/drm_buddy_test.c >> index ea2af6bd9abe..e0860fce9ebd 100644 >> --- a/drivers/gpu/drm/tests/drm_buddy_test.c >> +++ b/drivers/gpu/drm/tests/drm_buddy_test.c >> @@ -83,7 +83,7 @@ static void >> drm_test_buddy_alloc_pathological(struct kunit *test) >>                                 top, max_order); >>       } >>   -    drm_buddy_free_list(&mm, &holes); >> +    drm_buddy_free_list(&mm, &holes, 0); >>         /* Nothing larger than blocks of chunk_size now available */ >>       for (order = 1; order <= max_order; order++) { >> @@ -95,7 +95,7 @@ static void >> drm_test_buddy_alloc_pathological(struct kunit *test) >>       } >>         list_splice_tail(&holes, &blocks); >> -    drm_buddy_free_list(&mm, &blocks); >> +    drm_buddy_free_list(&mm, &blocks, 0); >>       drm_buddy_fini(&mm); >>   } >>   @@ -190,7 +190,7 @@ static void >> drm_test_buddy_alloc_pessimistic(struct kunit *test) >>         list_del(&block->link); >>       drm_buddy_free_block(&mm, block); >> -    drm_buddy_free_list(&mm, &blocks); >> +    drm_buddy_free_list(&mm, &blocks, 0); >>       drm_buddy_fini(&mm); >>   } >>   @@ -236,7 +236,7 @@ static void >> drm_test_buddy_alloc_optimistic(struct kunit *test) >>                                  size, size, &tmp, flags), >>                             "buddy_alloc unexpectedly succeeded, it >> should be full!"); >>   -    drm_buddy_free_list(&mm, &blocks); >> +    drm_buddy_free_list(&mm, &blocks, 0); >>       drm_buddy_fini(&mm); >>   } >>   @@ -271,7 +271,7 @@ static void drm_test_buddy_alloc_limit(struct >> kunit *test) >>                           drm_buddy_block_size(&mm, block), >>                           BIT_ULL(mm.max_order) * PAGE_SIZE); >>   -    drm_buddy_free_list(&mm, &allocated); >> +    drm_buddy_free_list(&mm, &allocated, 0); >>       drm_buddy_fini(&mm); >>   } >>   diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c >> b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c >> index 115ec745e502..1ad678b62c4a 100644 >> --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c >> +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c >> @@ -196,7 +196,7 @@ static int xe_ttm_vram_mgr_new(struct >> ttm_resource_manager *man, >>       return 0; >>     error_free_blocks: >> -    drm_buddy_free_list(mm, &vres->blocks); >> +    drm_buddy_free_list(mm, &vres->blocks, 0); >>       mutex_unlock(&mgr->lock); >>   error_fini: >>       ttm_resource_fini(man, &vres->base); >> @@ -214,7 +214,7 @@ static void xe_ttm_vram_mgr_del(struct >> ttm_resource_manager *man, >>       struct drm_buddy *mm = &mgr->mm; >>         mutex_lock(&mgr->lock); >> -    drm_buddy_free_list(mm, &vres->blocks); >> +    drm_buddy_free_list(mm, &vres->blocks, 0); >>       mgr->visible_avail += vres->used_visible_size; >>       mutex_unlock(&mgr->lock); >>   diff --git a/include/drm/drm_buddy.h b/include/drm/drm_buddy.h >> index a5b39fc01003..d81c596dfa38 100644 >> --- a/include/drm/drm_buddy.h >> +++ b/include/drm/drm_buddy.h >> @@ -6,6 +6,7 @@ >>   #ifndef __DRM_BUDDY_H__ >>   #define __DRM_BUDDY_H__ >>   +#include >>   #include >>   #include >>   #include >> @@ -25,15 +26,19 @@ >>   #define DRM_BUDDY_RANGE_ALLOCATION        BIT(0) >>   #define DRM_BUDDY_TOPDOWN_ALLOCATION        BIT(1) >>   #define DRM_BUDDY_CONTIGUOUS_ALLOCATION        BIT(2) >> +#define DRM_BUDDY_CLEAR_ALLOCATION        BIT(3) >> +#define DRM_BUDDY_CLEARED            BIT(4) >>     struct drm_buddy_block { >>   #define DRM_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) >>   #define DRM_BUDDY_HEADER_STATE  GENMASK_ULL(11, 10) >> +#define DRM_BUDDY_HEADER_CLEAR  GENMASK_ULL(9, 9) > > I guess better to keep this sorted... > >> + >>   #define   DRM_BUDDY_ALLOCATED       (1 << 10) >>   #define   DRM_BUDDY_FREE       (2 << 10) >>   #define   DRM_BUDDY_SPLIT       (3 << 10) > > ...so maybe move here? > >>   /* Free to be used, if needed in the future */ >> -#define DRM_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6) >> +#define DRM_BUDDY_HEADER_UNUSED GENMASK_ULL(8, 6) >>   #define DRM_BUDDY_HEADER_ORDER  GENMASK_ULL(5, 0) >>       u64 header; >>   @@ -86,6 +91,7 @@ struct drm_buddy { >>       u64 chunk_size; >>       u64 size; >>       u64 avail; >> +    u64 clear_avail; >>   }; >>     static inline u64 >> @@ -112,6 +118,12 @@ drm_buddy_block_is_allocated(struct >> drm_buddy_block *block) >>       return drm_buddy_block_state(block) == DRM_BUDDY_ALLOCATED; >>   } >>   +static inline bool >> +drm_buddy_block_is_clear(struct drm_buddy_block *block) >> +{ >> +    return block->header & DRM_BUDDY_HEADER_CLEAR; >> +} >> + >>   static inline bool >>   drm_buddy_block_is_free(struct drm_buddy_block *block) >>   { >> @@ -150,7 +162,9 @@ int drm_buddy_block_trim(struct drm_buddy *mm, >>     void drm_buddy_free_block(struct drm_buddy *mm, struct >> drm_buddy_block *block); >>   -void drm_buddy_free_list(struct drm_buddy *mm, struct list_head >> *objects); >> +void drm_buddy_free_list(struct drm_buddy *mm, >> +             struct list_head *objects, >> +             unsigned int flags); >>     void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p); >>   void drm_buddy_block_print(struct drm_buddy *mm,