From nobody Fri Oct 3 11:27:52 2025 Received: from NAM12-MW2-obe.outbound.protection.outlook.com (mail-mw2nam12on2066.outbound.protection.outlook.com [40.107.244.66]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E59C531DD91; Tue, 2 Sep 2025 14:32:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.244.66 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756823555; cv=fail; b=ImAOfc8t81vECkj5ghrPNGA8uUgrYtY49tNHH0r/lPwUpzVP5VXyO75XKs4B3uphO8NjnEpod5i3Af6TpQZyhnFzbPTd/CPZa13m4o22i1+M53TUw+pywRh0DJ6RQNg78zTifyakuYjH30fsnsa/L1kOXZMcTW24CaUcrOKt9wg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756823555; c=relaxed/simple; bh=zQvQecoSNHXjqzMm5mo3nv00fwH4jSk2BT+Bew0MI+k=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=dIVK5sL1glRmcx7pWs3LlTVI0PZf+5hJL5mN7HFhkWKHjq6awQ7gwORYze5pueD2Btu8/70pHsiZiLMMvyQy45rJZ8X4z0xbeVePsmPtOlZWYBwyCUNU/FgMZBiVoMF8zylFypMg2qaq/oSu/SYSIVIt6+FAf6XlbKH8NLydOSk= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=scCzfmmI; arc=fail smtp.client-ip=40.107.244.66 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="scCzfmmI" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=U+quE0z5yLPTE+cSZWat2ZZ8DO0xbQyxVEok1nOd2gwaQaaZ1BdGRlYOCOWIlu7ZcJ6t5yTIR4wjJ/htY+Kslif5qMOxDna6wzbGgOBOohUYAu865jWEbs1ujYV/3XFy/gRRk5g80NqhWwNOOltGEpO4QNpN5KPNLB6MBKb10U6JceRLuTKnxMBdfoE+EDQMF5+mpszKBnqzt2stn62soceyUPrqDUequ6dd7k2QYOcgRVY54I3i1W1j9y/YDwdxa3IkPp4N/5vknuzaw5U7eqZiBC9YgcZkZ0tYHV1cxNkjOsBohtMFRd14deTrs0pso4Caiqfsi98dntE5orqYRA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=lASg07l09fDMnINEnSgEePKgQSXpwmH4Nfj0nIZ1EDI=; b=oLWzYDBAO69yoC38GiPqtu0GOE3vpZvY2jPWpBykhODjAly6qzcwUF8uymYMJoZsvYvU7B1vLwrOte3GddgAJvySGvlodz2MavY5Hr5+7XfeUM6GDUBkAZIG6zizGTM7DKIG5yp0FgLjGw6lTKPOc2mi3Pk6l/9IvdnpjAf5K+jm33o8x2FF3aSFJscrlQJt9py1RRRaF388gkHTJvWgGfRV0MWesAUvgJYXm9DhDuXhBezPEkynoOtH6/KemfsCGtz/CLzVXZzHF9qWm/Ed6XiaR1NcKTXfhCdggsGxPTJJim6xiBF+W4CMeMjCgflcTRbyTgyaj1JbJAR91K5o/A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=lASg07l09fDMnINEnSgEePKgQSXpwmH4Nfj0nIZ1EDI=; b=scCzfmmI8mpT8yChIm8YS+C4B9OSu2yc3XXnQlO1CoBexjNHoct1UJ4xrPAqUf28sBKigsj90VmzrdNA0qkrTtUTKkt+G8XNORgLmIojJtI4XUqr/6xq5xWy3kmWTHscL6xs5PxpgJWTf4OvhGWnk06hbe+EWPoETZNqht395wUfgzHUqJQKtaP2IVj/SYy3/uGATR2eqCSZdZ93H9TMGMU59NRs/xuOsPaxmDJbiKx14/ZOZMIyHMuhKz2duIRoOhTOPrrM5FxHbEI8pJQGc/JuRIKgSK7spfheEfB2P0ONFoWkXL07W67WNbm69w+L1UlPc0BArKGLPDgrOta1tg== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) by SJ2PR12MB8955.namprd12.prod.outlook.com (2603:10b6:a03:542::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9052.21; Tue, 2 Sep 2025 14:32:28 +0000 Received: from CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::6e37:569f:82ee:3f99]) by CH2PR12MB3990.namprd12.prod.outlook.com ([fe80::6e37:569f:82ee:3f99%3]) with mapi id 15.20.9052.027; Tue, 2 Sep 2025 14:32:28 +0000 From: Alexandre Courbot Date: Tue, 02 Sep 2025 23:32:01 +0900 Subject: [PATCH v3 07/11] gpu: nova-core: firmware: process and prepare the GSP firmware Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250902-nova_firmware-v3-7-56854d9c5398@nvidia.com> References: <20250902-nova_firmware-v3-0-56854d9c5398@nvidia.com> In-Reply-To: <20250902-nova_firmware-v3-0-56854d9c5398@nvidia.com> To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann Cc: John Hubbard , Alistair Popple , Joel Fernandes , Timur Tabi , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, Alexandre Courbot X-Mailer: b4 0.14.2 X-ClientProxiedBy: TYCP286CA0225.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:3c5::13) To CH2PR12MB3990.namprd12.prod.outlook.com (2603:10b6:610:28::18) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CH2PR12MB3990:EE_|SJ2PR12MB8955:EE_ X-MS-Office365-Filtering-Correlation-Id: adbb5d51-1739-4957-3e37-08ddea2d8b1e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|10070799003|7416014|1800799024|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?YXJ2azl0L2k5b0RnbkFIWmJVWjVnQS9rUTNnd1duMnRyS0xvUVAwR211RmJH?= =?utf-8?B?QjNPV05waGNnMk9JWFJHZW5kRUZRRm00Ui9EUWFaSWFwelBSL0VBSVgxZHdU?= =?utf-8?B?dFRHNm5zMDkvMTZPMjJWNTVwMk94U2RabGRiUW10eGpEUVQxRHNxd0FVT2JN?= =?utf-8?B?R1B2dHJDREhjOFBSMzdheHlFR2d6NkhzR01XTzJleEtUOG9QM2k5Njc5cmJY?= =?utf-8?B?UzE2anFtcjgzTTNTS2wzYWhYVCtLcDI2R0QvNll5R3dsazhCVHRIMkhwbXVw?= =?utf-8?B?bFFOVHpnR0J2ZzY4MGVlRDIvQ3VlQjdEZkFNK3NNclVidVZNWHd2eDh5OWgx?= =?utf-8?B?RWlrN3ZtbC9JUnlINmNkNlBPTE5JQ2NpZmM5Z0tMczVSZ0hSREp1ZVFOUzkw?= =?utf-8?B?djlGa0FSNXpsTldtbW9nbjAvaWMrMFF4UTFpMHhIelFuV0pCWGZUcXF2bTUz?= =?utf-8?B?UThHdXh1M3dxZnN0OHNlWnRyNkt5UTNZOGR5M0U4Q3ExWEpJbFRlV2R1Lzdm?= =?utf-8?B?alJlNzVRcy80dC9uOE1oMUFRd2tVQ2ZITFRHL2xCNnFlbDl5aVkxajFlWGsz?= =?utf-8?B?YllQTHVEZTQ4K21udFhhNEdjRUxrSEo2ei9nMzRML29zVUo0TlVuK3RyQms3?= =?utf-8?B?ZzZmalU0TUlLejR4S2JNWHh4dnY2bEw0YWN3VWF4VGV4S3Jyc3Z6QlU3Wlh6?= =?utf-8?B?d0ExZ0U3U0hLblRmeHdDYThJT21Wd3JBcG0reWRURmdtZ0QvYkFYeWpaTVBH?= =?utf-8?B?TXp0Tzd4Wnc4UTVoS21FcHpsL1QvbGEvWFlMQ3NkeFY0dFo2dTBvUk84L0JT?= =?utf-8?B?MUY5ZmQzdFBKZ3JIVHVXalE1ZWU3dzVsTzhNZWRQWUZ2eWZlRFFKZ3JzRjJO?= =?utf-8?B?eG84eFF1UittZHNOR0M3N044b2p0WEtqdEpPdnBBS2FXZk1VV2paSG0wRm50?= =?utf-8?B?cWx6bzVYOE1rSUhieTFqc2U5bG5vYWJJMkdlMU55aC9ZWDNGMDVlK053ZjBE?= =?utf-8?B?cnhVNGs1N0RZaURaenJaV0Vxd1IwZ2d6QUVSaHZnMkNVcm5YNGRnWFZheS9q?= =?utf-8?B?RjMyOUpFekljWWFncHlrM3MzKy94RFl6YU8yVSswMi9EdWxyVEExR2l2WlUv?= =?utf-8?B?b1VFNmpXSXpqK3EwSFBxb01GSi9UZTBrRExHaXlPdm5jR0ordkpmMVp4UWE4?= =?utf-8?B?WVA2bS9CTlBhZjVvc1hZWjNzeldHRHRHaXppdWZOdFlBL1d6ZTB3eTU1RGJs?= =?utf-8?B?cXgvZ0dhem1EanhiVmJCVVEzNVpvLytBN1E3cmVOTURzZGNycUJ0MnZwbmRY?= =?utf-8?B?UktDOXNicm8vc3ZTUCtHWXFUS3dHd3VxT2xjbEtwMXN0M0NnSUpyRUtodjda?= =?utf-8?B?bzBjeHF2ZlF4clVpNDVqY0dsNy9iL1BDSFNVV1FIVkN2UllpajBpT2lEYXhU?= =?utf-8?B?eWdSZmVqSVU5bEpDakc3aHY3K3BtMCtxeWhMQ0lDL1ZkK0JORjlBWDhTTjV1?= =?utf-8?B?eUhrU1JSNG95ODNMVkZmN3ZtTDk3SGdkTGhyWmoxVUFXcHN4SjA5amlCbGNo?= =?utf-8?B?c2JET01IMUJyNnhiWW9xd3NXaVdWRVdLZmNUSlpMczRxQm1uUHJXVEd0SEJ1?= =?utf-8?B?b0pMek1iNTlkSW8zYkt4VVBhaVY5ekRyZEFlTnd1aDRJbGE0STROUVNlQytM?= =?utf-8?B?R0JIT1VGbG5KMDAySkxCaHYzeG5EZ3lwSHgvZ1NML3M4MUtJOWlZZlQ3L3NJ?= =?utf-8?B?RzBsMFA2ekc4TzBBbTMzL0dWVWtnNVVpZkVwcVNmbnpyZzdVcFJUeE9Ma0dS?= =?utf-8?B?MmFYM1ZENHduclZiWHFQNk9ZQjlINkNkRUgyTWQ4Ulg1WGFFWW84aVlLSWZp?= =?utf-8?B?SWRQcHVSWUxRQTMwQ2pYVTFVTitJUzg4clNnU3B4bVhHZkhtdExiUmtiVklr?= =?utf-8?B?T0xwUk83aldtKzFRZ3dZKzZ2dGJCRDYzZWFtQ1J6U1lPMUEvSDdZYUJNVlBn?= =?utf-8?B?b2twdU1wZFNRPT0=?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CH2PR12MB3990.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(366016)(376014)(10070799003)(7416014)(1800799024)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?OG5iSmhMc1RaRVkxQW4yamU1TWVpdmpremhpaG9DMGNyNVdRd2RGRnhXaUVD?= =?utf-8?B?RHpxVFl2dXdLcVhPZW9xL0FsSUtxU0FRM3huZnRNb3ZxK1V5SElQZWg2ZE94?= =?utf-8?B?SE1tODVSYkhqUmZSMHdKdDN6bkU3UllTUWF1WFRFdGxnVVR0MlNxY0hHaVIv?= =?utf-8?B?enNSZU9xSXltdGVWVDlLK21Cc2dDWXVTR3ZyUVR0Z2FnSGRWcDRxbGdYd2Zh?= =?utf-8?B?ZExVZUJsNVJoWFdTVjViaXFkbk9VMFdNOWdxekhROWpLemlKdkJXYUw2YkxL?= =?utf-8?B?ODM3YVYwcWhISjRINis0OGlSREM4OFVVMWdOT1djUjMraWhPVmpFeXF0Z2VO?= =?utf-8?B?Nzk5MWx4dk5RanJRa0JuS3dQUmVSbFdWY05NRzAvRUhTOE42OS9jWUZPNlRq?= =?utf-8?B?K0lYdHZzZnowRjNuazJ3UFZ6MllqUHRZOXk0cXdwUGFDUXBFTEpRQUVCVG5F?= =?utf-8?B?WW01YUJjbWN6NzI5cWFGTmRUSk80OXE0M2ZQNkRicmpFREhscHBYaUdMczZh?= =?utf-8?B?SHpmeldSOU5DMlMyM1FOSk9IdDBlSm5YS0V1RDIxUWV3dkJCKzFMTTd1bGt1?= =?utf-8?B?ZXNiYmt2cXAvRkFaNWJCNkFQVkR0eW1MejJsRlFwa0p3R0NIVFRpODFxTDVt?= =?utf-8?B?ZjFuVG0yZEpHcXA0SXZ2UmE4UnVpZmdZY0ZSQXFIL0orYjlRTFZsajVXNjRq?= =?utf-8?B?UnY2M2FKc2NzVDB0MlZmOERnckFlWTJoalY4S09JcUI0dGFGZmUwMGhOYnBM?= =?utf-8?B?VHFUc1R0dzV4YUtyR3RxQTFsQ3haZE5vQjhiQ0hVd2FML2JrS1RGdHdLNGlj?= =?utf-8?B?aExLL3VtWWJsR0l4bGlHdlh0UDRTSStlaGpzVHdaVDFjbWo4S0x0dWpOUk9E?= =?utf-8?B?UnJmRmtDL2ZWdWcxVVc0Y1lDbXFDcTBVTmRJNnBqeHVMaVVGYWtNMldZcFRp?= =?utf-8?B?WU9waGl1eDNmMnNlUk0ydVdISys5WXk1S1JDYUxSajdkSThUU0Rud3kxc29s?= =?utf-8?B?WmlwS3J6S2E5bFYzVStrTmZOYXhhMG80dVd3emlKZnpnbnlWLzJBdGlmd1dG?= =?utf-8?B?eU5rRHFRUmR3WjdtM0IrRURmN1Y2aVVCcTJRc1ZSRTZKUk9raC8xQmRmcWNC?= =?utf-8?B?QzJEc0doTkppamxsLzh4WG9zeGI3WmRPQjRFRnNMQXRmZ0M4aGFTc25HNU1W?= =?utf-8?B?VXo0MGc2Y2RQU3YxMkM1ZEtBNVg5ZERERDJFRTU2QUZmdDB2UFo1TERyb2Qr?= =?utf-8?B?amVMMk1oaGU4Z2hFRVZpemJ3ZFV5NS9GY0NrMmFVd3BNT0lueTRHNzlzNFA5?= =?utf-8?B?aVYzQjh1clY3VjZIN2VyeUVVanEzVDgvc0M0ZnRvNE1UTERXai9HaTlxTnh4?= =?utf-8?B?ZDE4U1orRzRjV3I4YVh4RmcvMEdpUVZaWm4vcmd0dnRUUkRrSElvNHhSMUtX?= =?utf-8?B?UE5JeWhRMk9iQkdHZnRCZEZxVzdUY2R0bkVld3RWUFBrbDNUd0FYNExOTTRx?= =?utf-8?B?WGFpem1JbG9SMGVmYmF1aXhIVDhBcXZiRlBkdnUwc1VxM1ZzNk00UTVpT29P?= =?utf-8?B?OTRsRlRqMThWdStnV2phVVV4QnZSWkxYUy9nT0g5Nk1JUUw0Rk11K01rQjBI?= =?utf-8?B?eW1Db2pLZHNrb2tTRFdIVjZhMFJlR0o5RjVoc1lFNGY4L2YrVW5rUEZwclVl?= =?utf-8?B?RUYwTUVXa29icHpwY1F3RnV2eUozOFNaWDRyVlBaUVRaRXk4dGtka2lzZWQz?= =?utf-8?B?dDUxYTlHMXlRckpJN0hWejdCWjF3Mlp1NEV5R24xWkxsWUVGN3hwdnlYRTNP?= =?utf-8?B?cVU0ZlhJWmtsWkxwT1lyQ2wzUFVNZVZxVElzQitnektVdyt0S1IyQXRWdllp?= =?utf-8?B?ZW1zUnJNVG1TOGJJZ0R4bDBxVWRVaDNYK2N5NnRzM2FZZDlINkJJOUdsNE9a?= =?utf-8?B?SStNVHFnNWwwdkZBdk02NVlCRXVQcXo0cG0ya2hseUZJa1JZNTQzRGpsZCtN?= =?utf-8?B?aUVlR3dHQmNxTjhWZEtXK01QS1VFeU9jNE84T245cnRKTFY0WEdCcGlCK2RN?= =?utf-8?B?SFcxSmg0WkRTUUZGdm5KbTI0bUh2aXYzbHZNek1qTjNFZTBCaUNCVGNQUWhE?= =?utf-8?B?RlFRcmw4ajVLTmI0U1pKMmprQXpadHZyNzBVM2oxVldrcEErbmVBSXVjejZK?= =?utf-8?Q?pvzQ7dhlovlTABLKuB0oz4D/ZmuQJiv/sqUixqrQK1Rh?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: adbb5d51-1739-4957-3e37-08ddea2d8b1e X-MS-Exchange-CrossTenant-AuthSource: CH2PR12MB3990.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 02 Sep 2025 14:32:28.6420 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: t70W+5YZrlBrzKSQHlTN9FQXyCAg22nPvl6kK4OyzISwDV9DA8fzYmdRFW5whO7nt7H5LcGTONIHEeL8y08IiQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB8955 The GSP firmware is a binary blob that is verified, loaded, and run by the GSP bootloader. Its presentation is a bit peculiar as the GSP bootloader expects to be given a DMA address to a 3-levels page table mapping the GSP firmware at address 0 of its own address space. Prepare such a structure containing the DMA-mapped firmware as well as the DMA-mapped page tables, and a way to obtain the DMA handle of the level 0 page table. Then, move the GSP firmware instance from the `Firmware` struct to the `start_gsp` method since it doesn't need to be kept after the GSP is booted. As we are performing the required ELF section parsing and radix3 page table building, remove these items from the TODO file. Signed-off-by: Alexandre Courbot --- Documentation/gpu/nova/core/todo.rst | 17 --- drivers/gpu/nova-core/firmware.rs | 3 +- drivers/gpu/nova-core/firmware/gsp.rs | 237 ++++++++++++++++++++++++++++++= ++++ drivers/gpu/nova-core/gpu.rs | 6 + drivers/gpu/nova-core/gsp.rs | 4 + drivers/gpu/nova-core/nova_core.rs | 1 + 6 files changed, 249 insertions(+), 19 deletions(-) diff --git a/Documentation/gpu/nova/core/todo.rst b/Documentation/gpu/nova/= core/todo.rst index 89431fec9041b1f35cc55799c91f48dc6bc918eb..0972cb905f7ae64dfbaef480827= 6757319009e9c 100644 --- a/Documentation/gpu/nova/core/todo.rst +++ b/Documentation/gpu/nova/core/todo.rst @@ -229,23 +229,6 @@ Rust abstraction for debugfs APIs. GPU (general) =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 -Parse firmware headers ----------------------- - -Parse ELF headers from the firmware files loaded from the filesystem. - -| Reference: ELF utils -| Complexity: Beginner -| Contact: Abdiel Janulgue - -Build radix3 page table ------------------------ - -Build the radix3 page table to map the firmware. - -| Complexity: Intermediate -| Contact: Abdiel Janulgue - Initial Devinit support ----------------------- =20 diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firm= ware.rs index d954b1e98fda82c44f87d2103e31fa717c392d79..cef910a7c2dc360139fafc2a01a= 050a9df40e45f 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -19,6 +19,7 @@ =20 pub(crate) mod booter; pub(crate) mod fwsec; +pub(crate) mod gsp; =20 pub(crate) const FIRMWARE_VERSION: &str =3D "535.113.01"; =20 @@ -39,7 +40,6 @@ fn request_nv_firmware( #[expect(dead_code)] pub(crate) struct Firmware { bootloader: firmware::Firmware, - gsp: firmware::Firmware, } =20 impl Firmware { @@ -48,7 +48,6 @@ pub(crate) fn new(dev: &device::Device, chipset: Chipset,= ver: &str) -> Result(elf: &'a [u8], name: &'b str) -> O= ption<&'a [u8]> { + let hdr =3D &elf + .get(0..size_of::()) + .and_then(Elf64Hdr::from_bytes)? + .0; + + // Get all the section headers. + let shdr =3D { + let shdr_num =3D usize::from(hdr.e_shnum); + let shdr_start =3D usize::try_from(hdr.e_shoff).ok()?; + let shdr_end =3D shdr_num + .checked_mul(size_of::()) + .and_then(|v| v.checked_add(shdr_start))?; + + elf.get(shdr_start..shdr_end) + .map(|slice| slice.as_ptr()) + .filter(|ptr| ptr.align_offset(align_of::()) =3D=3D 0) + // `FromBytes::from_bytes` does not support slices yet, so= build it manually. + // + // SAFETY: + // * `get` guarantees that the slice is within the bounds = of `elf` and of size + // `elf64_shdr * shdr_num`. + // * We checked that `ptr` had the correct alignment for `= elf64_shdr`. + .map(|ptr| unsafe { + core::slice::from_raw_parts(ptr.cast::(), shdr_num) + })? + }; + + // Get the strings table. + let strhdr =3D shdr.get(usize::from(hdr.e_shstrndx))?; + + // Find the section which name matches `name` and return it. + shdr.iter() + .find(|sh| { + let Some(name_idx) =3D strhdr + .sh_offset + .checked_add(u64::from(sh.sh_name)) + .and_then(|idx| usize::try_from(idx).ok()) + else { + return false; + }; + + // Get the start of the name. + elf.get(name_idx..) + // Stop at the first `0`. + .and_then(|nstr| nstr.get(0..=3Dnstr.iter().position(|= b| *b =3D=3D 0)?)) + // Convert into CStr. This should never fail because o= f the line above. + .and_then(|nstr| CStr::from_bytes_with_nul(nstr).ok()) + // Convert into str. + .and_then(|c_str| c_str.to_str().ok()) + // Check that the name matches. + .map(|str| str =3D=3D name) + .unwrap_or(false) + }) + // Return the slice containing the section. + .and_then(|sh| { + let start =3D usize::try_from(sh.sh_offset).ok()?; + let end =3D usize::try_from(sh.sh_size) + .ok() + .and_then(|sh_size| start.checked_add(sh_size))?; + + elf.get(start..end) + }) + } +} + +/// GSP firmware with 3-level radix page tables for the GSP bootloader. +/// +/// The bootloader expects firmware to be mapped starting at address 0 in = GSP's virtual address +/// space: +/// +/// ```text +/// Level 0: 1 page, 1 entry -> points to first level 1 page +/// Level 1: Multiple pages/entries -> each entry points to a level 2 pa= ge +/// Level 2: Multiple pages/entries -> each entry points to a firmware p= age +/// ``` +/// +/// Each page is 4KB, each entry is 8 bytes (64-bit DMA address). +/// Also known as "Radix3" firmware. +#[pin_data] +pub(crate) struct GspFirmware { + /// The GSP firmware inside a [`VVec`], device-mapped via a SG table. + #[pin] + fw: SGTable>>, + /// Level 2 page table whose entries contain DMA addresses of firmware= pages. + #[pin] + level2: SGTable>>, + /// Level 1 page table whose entries contain DMA addresses of level 2 = pages. + #[pin] + level1: SGTable>>, + /// Level 0 page table (single 4KB page) with one entry: DMA address o= f first level 1 page. + level0: DmaObject, + /// Size in bytes of the firmware contained in [`Self::fw`]. + pub size: usize, + /// Device-mapped GSP signatures matching the GPU's [`Chipset`]. + signatures: DmaObject, +} + +impl GspFirmware { + /// Loads the GSP firmware binaries, map them into `dev`'s address-spa= ce, and creates the page + /// tables expected by the GSP bootloader to load it. + pub(crate) fn new<'a, 'b>( + dev: &'a device::Device, + chipset: Chipset, + ver: &'b str, + ) -> Result + 'a> { + let fw =3D super::request_nv_firmware(dev, chipset, "gsp", ver)?; + + let fw_section =3D elf::elf64_section(fw.data(), ".fwimage").ok_or= (EINVAL)?; + + let sigs_section =3D match chipset.arch() { + Architecture::Ampere =3D> ".fwsignature_ga10x", + _ =3D> return Err(ENOTSUPP), + }; + let signatures =3D elf::elf64_section(fw.data(), sigs_section) + .ok_or(EINVAL) + .and_then(|data| DmaObject::from_data(dev, data))?; + + let size =3D fw_section.len(); + + // Move the firmware into a vmalloc'd vector and map it into the d= evice address + // space. + let fw_vvec =3D VVec::with_capacity(fw_section.len(), GFP_KERNEL) + .and_then(|mut v| { + v.extend_from_slice(fw_section, GFP_KERNEL)?; + Ok(v) + }) + .map_err(|_| ENOMEM)?; + + Ok(try_pin_init!(&this in Self { + fw <- SGTable::new(dev, fw_vvec, DataDirection::ToDevice, GFP_= KERNEL), + level2 <- { + // Allocate the level 2 page table, map the firmware onto = it, and map it into the + // device address space. + // SAFETY: `this` is a valid pointer, and `fw` has been in= itialized. + let fw_sg_table =3D unsafe { &(*this.as_ptr()).fw }; + VVec::::with_capacity( + fw_sg_table.iter().count() * core::mem::size_of::= (), + GFP_KERNEL, + ) + .map_err(|_| ENOMEM) + .and_then(|level2| map_into_lvl(fw_sg_table, level2)) + .map(|level2| SGTable::new(dev, level2, DataDirection::ToD= evice, GFP_KERNEL))? + }, + level1 <- { + // Allocate the level 1 page table, map the level 2 page t= able onto it, and map it + // into the device address space. + // SAFETY: `this` is a valid pointer, and `level2` has bee= n initialized. + let level2_sg_table =3D unsafe { &(*this.as_ptr()).level2 = }; + VVec::::with_capacity( + level2_sg_table.iter().count() * core::mem::size_of::<= u64>(), + GFP_KERNEL, + ) + .map_err(|_| ENOMEM) + .and_then(|level1| map_into_lvl(level2_sg_table, level1)) + .map(|level1| SGTable::new(dev, level1, DataDirection::ToD= evice, GFP_KERNEL))? + }, + level0: { + // Allocate the level 0 page table as a device-visible DMA= object, and map the + // level 1 page table onto it. + // SAFETY: `this` is a valid pointer, and `level1` has bee= n initialized. + let level1_sg_table =3D unsafe { &(*this.as_ptr()).level1 = }; + let mut level0 =3D DmaObject::new(dev, GSP_PAGE_SIZE)?; + // SAFETY: we are the only owner of this newly-created obj= ect, making races + // impossible. + let level0_slice =3D unsafe { level0.as_slice_mut(0, GSP_P= AGE_SIZE) }?; + level0_slice[0..core::mem::size_of::()].copy_from_sli= ce( + #[allow(clippy::useless_conversion)] + &(u64::from(level1_sg_table.iter().next().unwrap().dma= _address())) + .to_le_bytes(), + ); + + level0 + }, + size, + signatures, + })) + } + + #[expect(unused)] + /// Returns the DMA handle of the radix3 level 0 page table. + pub(crate) fn radix3_dma_handle(&self) -> DmaAddress { + self.level0.dma_handle() + } +} + +/// Build a page table from a scatter-gather list. +/// +/// Takes each DMA-mapped region from `sg_table` and writes page table ent= ries +/// for all 4KB pages within that region. For example, a 16KB SG entry bec= omes +/// 4 consecutive page table entries. +fn map_into_lvl(sg_table: &SGTable>>, mut dst: VVec) ->= Result> { + for sg_entry in sg_table.iter() { + // Number of pages we need to map. + let num_pages =3D (sg_entry.dma_len() as usize).div_ceil(GSP_PAGE_= SIZE); + + for i in 0..num_pages { + let entry =3D sg_entry.dma_address() + (i as u64 * GSP_PAGE_SI= ZE as u64); + dst.extend_from_slice(&entry.to_le_bytes(), GFP_KERNEL)?; + } + } + + Ok(dst) +} diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 2f5ae89ab80b237eba5d55351229be78cd471a72..547e5dd31aeb9650b226c267de5= f0412173b3fe0 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -8,6 +8,7 @@ use crate::fb::SysmemFlush; use crate::firmware::booter::{BooterFirmware, BooterKind}; use crate::firmware::fwsec::{FwsecCommand, FwsecFirmware}; +use crate::firmware::gsp::GspFirmware; use crate::firmware::{Firmware, FIRMWARE_VERSION}; use crate::gfw; use crate::regs; @@ -289,6 +290,11 @@ pub(crate) fn start_gsp(&self, pdev: &pci::Device) -> Result<()> =20 let bios =3D Vbios::new(dev, bar)?; =20 + let _gsp_fw =3D KBox::pin_init( + GspFirmware::new(dev, self.spec.chipset, FIRMWARE_VERSION)?, + GFP_KERNEL, + )?; + let fb_layout =3D FbLayout::new(self.spec.chipset, bar)?; dev_dbg!(dev, "{:#x?}\n", fb_layout); =20 diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs new file mode 100644 index 0000000000000000000000000000000000000000..a0e7ec5f6c9c959d57540b3ebf4= b782f2e002b08 --- /dev/null +++ b/drivers/gpu/nova-core/gsp.rs @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 + +pub(crate) const GSP_PAGE_SHIFT: usize =3D 12; +pub(crate) const GSP_PAGE_SIZE: usize =3D 1 << GSP_PAGE_SHIFT; diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index cb2bbb30cba142265b354c9acf70349a6e40759e..fffcaee2249fe6cd7f55a7291c1= e44be42e791d9 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -9,6 +9,7 @@ mod firmware; mod gfw; mod gpu; +mod gsp; mod regs; mod util; mod vbios; --=20 2.51.0