1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1993-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "gpu/gpu.h"
25 #include "gpu/gpu_device_mapping.h"
26 #include "core/thread_state.h"
27 #include "nv_ref.h"
28 
29 /**
30  * @brief Finds the device mapping matching the specified address and device index
31  *
32  * @param[in] pGpu
33  * @param[in] deviceIndex device specific device enum (DEVICE_INDEX_*)
34  * @param[in] addr        device register address
35  *
36  * @returns matching mapping, or NULL if not found.
37  */
38 static DEVICE_MAPPING *
_gpuFindDeviceMapping(OBJGPU * pGpu,DEVICE_INDEX deviceIndex,NvU32 instance)39 _gpuFindDeviceMapping
40 (
41     OBJGPU *pGpu,
42     DEVICE_INDEX deviceIndex,
43     NvU32   instance
44 )
45 {
46     NvU32 i;
47     NvU32 devId = 0;
48     DEVICE_ID_MAPPING *deviceIdMapping;
49     NvU32 numDeviceIDs;
50 
51     numDeviceIDs = gpuGetDeviceIDList_HAL(pGpu, &deviceIdMapping);
52 
53     // Find the devID that matches the requested device index
54     for (i = 0; i < numDeviceIDs; i++)
55     {
56         if (deviceIdMapping[i].deviceIndex == deviceIndex)
57         {
58             devId = deviceIdMapping[i].devId;
59             break;
60         }
61     }
62 
63     if (devId == 0)
64     {
65         // For discrete GPU, just return BAR0 mapping
66         if (deviceIndex == DEVICE_INDEX_GPU)
67         {
68             return &pGpu->deviceMappings[0];
69         }
70         else
71         {
72             NV_PRINTF(LEVEL_ERROR,
73                       "Could not find mapping for deviceIndex=%d\n",
74                       deviceIndex);
75             return NULL;
76         }
77     }
78     return gpuGetDeviceMappingFromDeviceID(pGpu, devId, instance);
79 }
80 
81 DEVICE_MAPPING *
gpuGetDeviceMapping_IMPL(OBJGPU * pGpu,DEVICE_INDEX deviceIndex,NvU32 instance)82 gpuGetDeviceMapping_IMPL
83 (
84     OBJGPU *pGpu,
85     DEVICE_INDEX deviceIndex,
86     NvU32   instance
87 )
88 {
89     // Fast lookup path for first instance of a device
90     if ((deviceIndex < DEVICE_INDEX_MAX) && (instance == 0))
91     {
92         if (!pGpu->pDeviceMappingsByDeviceInstance[deviceIndex])
93         {
94             pGpu->pDeviceMappingsByDeviceInstance[deviceIndex] = _gpuFindDeviceMapping(pGpu, deviceIndex, instance);
95         }
96         return pGpu->pDeviceMappingsByDeviceInstance[deviceIndex];
97     }
98 
99     return _gpuFindDeviceMapping(pGpu, deviceIndex, instance);
100 }
101 
102 /**
103  * @brief Returns the device mapping matching the specified device ID from
104  * project relocation table
105  *
106  * @param[in] pGpu        OBJGPU pointer
107  * @param[in] deviceId    device ID from project relocation table
108  * @param[in] instance    instance of the particular device ID
109  *
110  * @returns matching mapping, or NULL if not found.
111  */
112 
113 DEVICE_MAPPING *
gpuGetDeviceMappingFromDeviceID_IMPL(OBJGPU * pGpu,NvU32 deviceId,NvU32 instance)114 gpuGetDeviceMappingFromDeviceID_IMPL
115 (
116     OBJGPU *pGpu,
117     NvU32 deviceId,
118     NvU32 instance
119 )
120 {
121     NvU32 i;
122 
123     //
124     // For SOC, walk the list of devices to find the device/instance requested.
125     // For GPU (legacy), only NV_DEVID_GPU(0) is expected & allowed
126     //
127     if (pGpu->bIsSOC)
128     {
129         for (i = 0; i < pGpu->gpuDeviceMapCount; i++)
130         {
131             if (pGpu->deviceMappings[i].gpuDeviceEnum == deviceId)
132             {
133                 // Find the Nth instance of the requested device
134                 if (instance)
135                     instance--;
136                 else
137                     return &pGpu->deviceMappings[i];
138             }
139         }
140 
141         NV_PRINTF(LEVEL_ERROR, "Could not find mapping for deviceId=%d\n",
142                   deviceId);
143     }
144     else
145     {
146         // For GPU, always assume NV_DEVID_GPU instance 0.
147         NV_ASSERT(instance == 0);
148         NV_ASSERT(pGpu->gpuDeviceMapCount == 1);
149 
150         return &pGpu->deviceMappings[0];
151     }
152 
153     return NULL;
154 }
155 
_gpuCheckIsBar0OffByN(OBJGPU * pGpu)156 static NvBool _gpuCheckIsBar0OffByN(OBJGPU *pGpu)
157 {
158     NvU32 i, pmcBoot0;
159 
160     // Check to see if we can find PMC_BOOT_0
161     for (i = 0; i < 20; i++)
162     {
163         pmcBoot0 = GPU_REG_RD32(pGpu, NV_PMC_BOOT_0 + (i * 4));
164         if (pmcBoot0 == pGpu->chipId0)
165         {
166             break;
167         }
168     }
169 
170     if ((i != 0) && (i != 20))
171     {
172         // We are off by N
173         return NV_TRUE;
174     }
175 
176     // Everything looks ok
177     return NV_FALSE;
178 }
179 
_gpuCheckDoesPciSpaceMatch(OBJGPU * pGpu)180 static NvBool _gpuCheckDoesPciSpaceMatch(OBJGPU *pGpu)
181 {
182     NvU16 VendorId;
183     NvU16 DeviceId;
184     NvU8  bus = gpuGetBus(pGpu);
185     NvU8  device = gpuGetDevice(pGpu);
186     NvU32 domain = gpuGetDomain(pGpu);
187 
188     osPciInitHandle(domain, bus, device, 0, &VendorId, &DeviceId);
189     if ((DeviceId == 0xFFFF) ||
190         (VendorId != 0x10DE))
191     {
192         return NV_FALSE;
193     }
194 
195     return NV_TRUE;
196 }
197 
_gpuCheckIsPciMemSpaceEnabled(OBJGPU * pGpu)198 static NvBool _gpuCheckIsPciMemSpaceEnabled(OBJGPU *pGpu)
199 {
200     NvU16 VendorId;
201     NvU16 DeviceId;
202     NvU8  bus = gpuGetBus(pGpu);
203     NvU8  device = gpuGetDevice(pGpu);
204     NvU32 domain = gpuGetDomain(pGpu);
205     void *Handle = osPciInitHandle(domain, bus, device, 0, &VendorId, &DeviceId);
206     NvU32 Enabled = osPciReadDword(Handle, NV_CONFIG_PCI_NV_1);
207 
208     // Is Memory Spaced Enabled
209     if (DRF_VAL(_CONFIG, _PCI_NV_1, _MEMORY_SPACE, Enabled) != NV_CONFIG_PCI_NV_1_MEMORY_SPACE_ENABLED)
210     {
211         return NV_FALSE;
212     }
213 
214     return NV_TRUE;
215 }
216 
gpuSanityCheck_IMPL(OBJGPU * pGpu,NvU32 flags,NvU32 * pFlagsFailed)217 NV_STATUS gpuSanityCheck_IMPL
218 (
219     OBJGPU *pGpu,
220     NvU32 flags,
221     NvU32 *pFlagsFailed
222 )
223 {
224     NV_STATUS rmStatus = NV_OK;
225     NvU32 flagsFailed = GPU_SANITY_CHECK_FLAGS_NONE;
226     THREAD_STATE_NODE *pThreadNode = NULL;
227 
228     if (pFlagsFailed != NULL)
229     {
230         *pFlagsFailed = GPU_SANITY_CHECK_FLAGS_NONE;
231     }
232 
233     if (pGpu->bIsSOC)
234     {
235         flags &= ~(
236                   GPU_SANITY_CHECK_FLAGS_BOOT_0                  |
237                   GPU_SANITY_CHECK_FLAGS_OFF_BY_N                |
238                   GPU_SANITY_CHECK_FLAGS_PCI_SPACE_MATCH         |
239                   GPU_SANITY_CHECK_FLAGS_PCI_MEM_SPACE_ENABLED   |
240                   GPU_SANITY_CHECK_FLAGS_FB);
241 
242     }
243 
244     //
245     // Check to make sure the lock is held for this thread as the underlying
246     // functions can touch state and lists that expect exclusive access.
247     //
248     rmStatus = threadStateGetCurrent(&pThreadNode, pGpu);
249     if (rmStatus != NV_OK)
250     {
251         return rmStatus;
252     }
253     if (pThreadNode->flags & THREAD_STATE_FLAGS_IS_ISR_LOCKLESS)
254     {
255         return NV_ERR_NOT_SUPPORTED;
256     }
257 
258     // Check to make sure we are powered on first
259     if (gpuIsGpuFullPower(pGpu) == NV_FALSE)
260     {
261         NV_ASSERT(0);
262         return NV_ERR_GPU_NOT_FULL_POWER;
263     }
264 
265     if (flags & GPU_SANITY_CHECK_FLAGS_BOOT_0)
266     {
267         //
268         // When GPU is in reset reg reads will return 0xFFFFFFFF.
269         // Without this check RM would keep hitting assert during TDR recovery.
270         //
271         if (!API_GPU_IN_RESET_SANITY_CHECK(pGpu))
272         {
273             NvU32 pmcBoot0 = GPU_REG_RD32(pGpu, NV_PMC_BOOT_0);
274             if (pmcBoot0 != pGpu->chipId0)
275             {
276                 flagsFailed |= GPU_SANITY_CHECK_FLAGS_BOOT_0;
277                 NV_ASSERT(0);
278             }
279         }
280     }
281 
282     if (flags & GPU_SANITY_CHECK_FLAGS_OFF_BY_N)
283     {
284         if (_gpuCheckIsBar0OffByN(pGpu))
285         {
286             flagsFailed |= GPU_SANITY_CHECK_FLAGS_OFF_BY_N;
287             NV_ASSERT(0);
288         }
289     }
290 
291     if (flags & GPU_SANITY_CHECK_FLAGS_PCI_SPACE_MATCH)
292     {
293         if (!_gpuCheckDoesPciSpaceMatch(pGpu))
294         {
295             flagsFailed |= GPU_SANITY_CHECK_FLAGS_PCI_SPACE_MATCH;
296             NV_ASSERT(0);
297         }
298     }
299 
300     if (flags & GPU_SANITY_CHECK_FLAGS_PCI_MEM_SPACE_ENABLED)
301     {
302         if (!_gpuCheckIsPciMemSpaceEnabled(pGpu))
303         {
304             flagsFailed |= GPU_SANITY_CHECK_FLAGS_PCI_MEM_SPACE_ENABLED;
305             NV_ASSERT(0);
306         }
307     }
308 
309     if (flags & GPU_SANITY_CHECK_FLAGS_FB)
310     {
311         if (!gpuIsGpuFullPower(pGpu))
312         {
313             NV_ASSERT(0);
314         }
315     }
316 
317     if (flagsFailed != GPU_SANITY_CHECK_FLAGS_NONE)
318     {
319         rmStatus = NV_ERR_GENERIC;
320         NV_PRINTF(LEVEL_ERROR, "Failed test flags: 0x%x\n", flagsFailed);
321     }
322 
323     if (pFlagsFailed != NULL)
324     {
325         *pFlagsFailed = flagsFailed;
326     }
327 
328     return rmStatus;
329 }
330