Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright(c) 2019-2025, Intel Corporation. All rights reserved.
4 */
5
6#include <linux/intel_dg_nvm_aux.h>
7#include <linux/pci.h>
8
9#include "xe_device.h"
10#include "xe_device_types.h"
11#include "xe_mmio.h"
12#include "xe_nvm.h"
13#include "regs/xe_gsc_regs.h"
14#include "xe_sriov.h"
15
16#define GEN12_GUNIT_NVM_BASE 0x00102040
17#define GEN12_DEBUG_NVM_BASE 0x00101018
18
19#define GEN12_CNTL_PROTECTED_NVM_REG 0x0010100C
20
21#define GEN12_GUNIT_NVM_SIZE 0x80
22#define GEN12_DEBUG_NVM_SIZE 0x4
23
24#define NVM_NON_POSTED_ERASE_CHICKEN_BIT BIT(13)
25
26#define HECI_FW_STATUS_2_NVM_ACCESS_MODE BIT(3)
27
28static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = {
29 [0] = { .name = "DESCRIPTOR", },
30 [2] = { .name = "GSC", },
31 [9] = { .name = "PADDING", },
32 [11] = { .name = "OptionROM", },
33 [12] = { .name = "DAM", },
34};
35
36static void xe_nvm_release_dev(struct device *dev)
37{
38 struct auxiliary_device *aux = container_of(dev, struct auxiliary_device, dev);
39 struct intel_dg_nvm_dev *nvm = container_of(aux, struct intel_dg_nvm_dev, aux_dev);
40
41 kfree(nvm);
42}
43
44static bool xe_nvm_non_posted_erase(struct xe_device *xe)
45{
46 struct xe_mmio *mmio = xe_root_tile_mmio(xe);
47
48 if (xe->info.platform != XE_BATTLEMAGE)
49 return false;
50 return !(xe_mmio_read32(mmio, XE_REG(GEN12_CNTL_PROTECTED_NVM_REG)) &
51 NVM_NON_POSTED_ERASE_CHICKEN_BIT);
52}
53
54static bool xe_nvm_writable_override(struct xe_device *xe)
55{
56 struct xe_mmio *mmio = xe_root_tile_mmio(xe);
57 bool writable_override;
58 resource_size_t base;
59
60 switch (xe->info.platform) {
61 case XE_BATTLEMAGE:
62 base = DG2_GSC_HECI2_BASE;
63 break;
64 case XE_PVC:
65 base = PVC_GSC_HECI2_BASE;
66 break;
67 case XE_DG2:
68 base = DG2_GSC_HECI2_BASE;
69 break;
70 case XE_DG1:
71 base = DG1_GSC_HECI2_BASE;
72 break;
73 default:
74 drm_err(&xe->drm, "Unknown platform\n");
75 return true;
76 }
77
78 writable_override =
79 !(xe_mmio_read32(mmio, HECI_FWSTS2(base)) &
80 HECI_FW_STATUS_2_NVM_ACCESS_MODE);
81 if (writable_override)
82 drm_info(&xe->drm, "NVM access overridden by jumper\n");
83 return writable_override;
84}
85
86static void xe_nvm_fini(void *arg)
87{
88 struct xe_device *xe = arg;
89 struct intel_dg_nvm_dev *nvm = xe->nvm;
90
91 if (!xe->info.has_gsc_nvm)
92 return;
93
94 /* No access to internal NVM from VFs */
95 if (IS_SRIOV_VF(xe))
96 return;
97
98 /* Nvm pointer should not be NULL here */
99 if (WARN_ON(!nvm))
100 return;
101
102 auxiliary_device_delete(&nvm->aux_dev);
103 auxiliary_device_uninit(&nvm->aux_dev);
104 xe->nvm = NULL;
105}
106
107int xe_nvm_init(struct xe_device *xe)
108{
109 struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
110 struct auxiliary_device *aux_dev;
111 struct intel_dg_nvm_dev *nvm;
112 int ret;
113
114 if (!xe->info.has_gsc_nvm)
115 return 0;
116
117 /* No access to internal NVM from VFs */
118 if (IS_SRIOV_VF(xe))
119 return 0;
120
121 /* Nvm pointer should be NULL here */
122 if (WARN_ON(xe->nvm))
123 return -EFAULT;
124
125 xe->nvm = kzalloc(sizeof(*nvm), GFP_KERNEL);
126 if (!xe->nvm)
127 return -ENOMEM;
128
129 nvm = xe->nvm;
130
131 nvm->writable_override = xe_nvm_writable_override(xe);
132 nvm->non_posted_erase = xe_nvm_non_posted_erase(xe);
133 nvm->bar.parent = &pdev->resource[0];
134 nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start;
135 nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1;
136 nvm->bar.flags = IORESOURCE_MEM;
137 nvm->bar.desc = IORES_DESC_NONE;
138 nvm->regions = regions;
139
140 nvm->bar2.parent = &pdev->resource[0];
141 nvm->bar2.start = GEN12_DEBUG_NVM_BASE + pdev->resource[0].start;
142 nvm->bar2.end = nvm->bar2.start + GEN12_DEBUG_NVM_SIZE - 1;
143 nvm->bar2.flags = IORESOURCE_MEM;
144 nvm->bar2.desc = IORES_DESC_NONE;
145
146 aux_dev = &nvm->aux_dev;
147
148 aux_dev->name = "nvm";
149 aux_dev->id = (pci_domain_nr(pdev->bus) << 16) | pci_dev_id(pdev);
150 aux_dev->dev.parent = &pdev->dev;
151 aux_dev->dev.release = xe_nvm_release_dev;
152
153 ret = auxiliary_device_init(aux_dev);
154 if (ret) {
155 drm_err(&xe->drm, "xe-nvm aux init failed %d\n", ret);
156 kfree(nvm);
157 xe->nvm = NULL;
158 return ret;
159 }
160
161 ret = auxiliary_device_add(aux_dev);
162 if (ret) {
163 drm_err(&xe->drm, "xe-nvm aux add failed %d\n", ret);
164 auxiliary_device_uninit(aux_dev);
165 xe->nvm = NULL;
166 return ret;
167 }
168 return devm_add_action_or_reset(xe->drm.dev, xe_nvm_fini, xe);
169}