drm/xe/nvm: add on-die non-volatile memory device

Enable access to internal non-volatile memory on DGFX
with GSC/CSC devices via a child device.
The nvm child device is exposed via auxiliary bus.

Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Link: https://lore.kernel.org/r/20250617145159.3803852-7-alexander.usyskin@intel.com
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
This commit is contained in:
Alexander Usyskin 2025-06-17 17:51:56 +03:00 committed by Rodrigo Vivi
parent 4b93f5fc3b
commit c28bfb107d
No known key found for this signature in database
GPG key ID: FA625F640EEB13CA
6 changed files with 140 additions and 0 deletions

View file

@ -80,6 +80,7 @@ xe-y += xe_bb.o \
xe_mmio.o \
xe_mocs.o \
xe_module.o \
xe_nvm.o \
xe_oa.o \
xe_observation.o \
xe_pat.o \

View file

@ -46,6 +46,7 @@
#include "xe_memirq.h"
#include "xe_mmio.h"
#include "xe_module.h"
#include "xe_nvm.h"
#include "xe_oa.h"
#include "xe_observation.h"
#include "xe_pat.h"
@ -881,6 +882,8 @@ int xe_device_probe(struct xe_device *xe)
return err;
}
xe_nvm_init(xe);
err = xe_heci_gsc_init(xe);
if (err)
return err;
@ -938,6 +941,8 @@ void xe_device_remove(struct xe_device *xe)
{
xe_display_unregister(xe);
xe_nvm_fini(xe);
drm_dev_unplug(&xe->drm);
xe_bo_pci_dev_remove_all(xe);

View file

@ -32,6 +32,7 @@
struct dram_info;
struct intel_display;
struct intel_dg_nvm_dev;
struct xe_ggtt;
struct xe_pat_ops;
struct xe_pxp;
@ -316,6 +317,8 @@ struct xe_device {
u8 has_fan_control:1;
/** @info.has_flat_ccs: Whether flat CCS metadata is used */
u8 has_flat_ccs:1;
/** @info.has_gsc_nvm: Device has gsc non-volatile memory */
u8 has_gsc_nvm:1;
/** @info.has_heci_cscfi: device has heci cscfi */
u8 has_heci_cscfi:1;
/** @info.has_heci_gscfi: device has heci gscfi */
@ -549,6 +552,9 @@ struct xe_device {
/** @heci_gsc: graphics security controller */
struct xe_heci_gsc heci_gsc;
/** @nvm: discrete graphics non-volatile memory */
struct intel_dg_nvm_dev *nvm;
/** @oa: oa observation subsystem */
struct xe_oa oa;

107
drivers/gpu/drm/xe/xe_nvm.c Normal file
View file

@ -0,0 +1,107 @@
// SPDX-License-Identifier: MIT
/*
* Copyright(c) 2019-2025, Intel Corporation. All rights reserved.
*/
#include <linux/intel_dg_nvm_aux.h>
#include <linux/pci.h>
#include "xe_device_types.h"
#include "xe_nvm.h"
#include "xe_sriov.h"
#define GEN12_GUNIT_NVM_BASE 0x00102040
#define GEN12_GUNIT_NVM_SIZE 0x80
#define HECI_FW_STATUS_2_NVM_ACCESS_MODE BIT(3)
static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = {
[0] = { .name = "DESCRIPTOR", },
[2] = { .name = "GSC", },
[9] = { .name = "PADDING", },
[11] = { .name = "OptionROM", },
[12] = { .name = "DAM", },
};
static void xe_nvm_release_dev(struct device *dev)
{
}
int xe_nvm_init(struct xe_device *xe)
{
struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
struct auxiliary_device *aux_dev;
struct intel_dg_nvm_dev *nvm;
int ret;
if (!xe->info.has_gsc_nvm)
return 0;
/* No access to internal NVM from VFs */
if (IS_SRIOV_VF(xe))
return 0;
/* Nvm pointer should be NULL here */
if (WARN_ON(xe->nvm))
return -EFAULT;
xe->nvm = kzalloc(sizeof(*nvm), GFP_KERNEL);
if (!xe->nvm)
return -ENOMEM;
nvm = xe->nvm;
nvm->writable_override = false;
nvm->bar.parent = &pdev->resource[0];
nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start;
nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1;
nvm->bar.flags = IORESOURCE_MEM;
nvm->bar.desc = IORES_DESC_NONE;
nvm->regions = regions;
aux_dev = &nvm->aux_dev;
aux_dev->name = "nvm";
aux_dev->id = (pci_domain_nr(pdev->bus) << 16) | pci_dev_id(pdev);
aux_dev->dev.parent = &pdev->dev;
aux_dev->dev.release = xe_nvm_release_dev;
ret = auxiliary_device_init(aux_dev);
if (ret) {
drm_err(&xe->drm, "xe-nvm aux init failed %d\n", ret);
goto err;
}
ret = auxiliary_device_add(aux_dev);
if (ret) {
drm_err(&xe->drm, "xe-nvm aux add failed %d\n", ret);
auxiliary_device_uninit(aux_dev);
goto err;
}
return 0;
err:
kfree(nvm);
xe->nvm = NULL;
return ret;
}
void xe_nvm_fini(struct xe_device *xe)
{
struct intel_dg_nvm_dev *nvm = xe->nvm;
if (!xe->info.has_gsc_nvm)
return;
/* No access to internal NVM from VFs */
if (IS_SRIOV_VF(xe))
return;
/* Nvm pointer should not be NULL here */
if (WARN_ON(!nvm))
return;
auxiliary_device_delete(&nvm->aux_dev);
auxiliary_device_uninit(&nvm->aux_dev);
kfree(nvm);
xe->nvm = NULL;
}

View file

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright(c) 2019-2025 Intel Corporation. All rights reserved.
*/
#ifndef __XE_NVM_H__
#define __XE_NVM_H__
struct xe_device;
int xe_nvm_init(struct xe_device *xe);
void xe_nvm_fini(struct xe_device *xe);
#endif

View file

@ -63,6 +63,7 @@ struct xe_device_desc {
u8 has_display:1;
u8 has_fan_control:1;
u8 has_gsc_nvm:1;
u8 has_heci_gscfi:1;
u8 has_heci_cscfi:1;
u8 has_llc:1;
@ -272,6 +273,7 @@ static const struct xe_device_desc dg1_desc = {
PLATFORM(DG1),
.dma_mask_size = 39,
.has_display = true,
.has_gsc_nvm = 1,
.has_heci_gscfi = 1,
.require_force_probe = true,
};
@ -283,6 +285,7 @@ static const u16 dg2_g12_ids[] = { INTEL_DG2_G12_IDS(NOP), 0 };
#define DG2_FEATURES \
DGFX_FEATURES, \
PLATFORM(DG2), \
.has_gsc_nvm = 1, \
.has_heci_gscfi = 1, \
.subplatforms = (const struct xe_subplatform_desc[]) { \
{ XE_SUBPLATFORM_DG2_G10, "G10", dg2_g10_ids }, \
@ -319,6 +322,7 @@ static const __maybe_unused struct xe_device_desc pvc_desc = {
PLATFORM(PVC),
.dma_mask_size = 52,
.has_display = false,
.has_gsc_nvm = 1,
.has_heci_gscfi = 1,
.max_remote_tiles = 1,
.require_force_probe = true,
@ -349,6 +353,7 @@ static const struct xe_device_desc bmg_desc = {
.has_display = true,
.has_fan_control = true,
.has_mbx_power_limits = true,
.has_gsc_nvm = 1,
.has_heci_cscfi = 1,
.needs_scratch = true,
};
@ -592,6 +597,7 @@ static int xe_info_init_early(struct xe_device *xe,
xe->info.is_dgfx = desc->is_dgfx;
xe->info.has_fan_control = desc->has_fan_control;
xe->info.has_mbx_power_limits = desc->has_mbx_power_limits;
xe->info.has_gsc_nvm = desc->has_gsc_nvm;
xe->info.has_heci_gscfi = desc->has_heci_gscfi;
xe->info.has_heci_cscfi = desc->has_heci_cscfi;
xe->info.has_llc = desc->has_llc;