1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2018-2020 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 "common_nvswitch.h"
25 #include "lr10/lr10.h"
26 #include "flcn/flcn_nvswitch.h"
27
28 #include "nvswitch/lr10/dev_falcon_v4.h"
29
30 static NvU32
_flcnRegRead_LR10(nvswitch_device * device,PFLCN pFlcn,NvU32 offset)31 _flcnRegRead_LR10
32 (
33 nvswitch_device *device,
34 PFLCN pFlcn,
35 NvU32 offset
36 )
37 {
38 // Probably should perform some checks on the offset, the device, and the engine descriptor
39 return nvswitch_reg_read_32(device, pFlcn->engDescUc.base + offset);
40 }
41
42 static void
_flcnRegWrite_LR10(nvswitch_device * device,PFLCN pFlcn,NvU32 offset,NvU32 data)43 _flcnRegWrite_LR10
44 (
45 nvswitch_device *device,
46 PFLCN pFlcn,
47 NvU32 offset,
48 NvU32 data
49 )
50 {
51 // Probably should perform some checks on the offset, the device, and the engine descriptor
52 nvswitch_reg_write_32(device, pFlcn->engDescUc.base + offset, data);
53 }
54
55 /*
56 * @brief Retrigger an interrupt message from the engine to the NV_CTRL tree
57 *
58 * @param[in] device nvswitch_device pointer
59 * @param[in] pFlcn FLCN pointer
60 */
61 static void
_flcnIntrRetrigger_LR10(nvswitch_device * device,FLCN * pFlcn)62 _flcnIntrRetrigger_LR10
63 (
64 nvswitch_device *device,
65 FLCN *pFlcn
66 )
67 {
68 NvU32 val = DRF_DEF(_PFALCON, _FALCON_INTR_RETRIGGER, _TRIGGER, _TRUE);
69 flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_INTR_RETRIGGER(0), val);
70 }
71
72 static NvBool
_flcnAreEngDescsInitialized_LR10(nvswitch_device * device,FLCN * pFlcn)73 _flcnAreEngDescsInitialized_LR10
74 (
75 nvswitch_device *device,
76 FLCN *pFlcn
77 )
78 {
79 // if pFlcn->engDescUc is 0, we haven't finished discovery, return false
80 // if pFlcn->engDescUc is NOT 0, and pFlcn->engDescBc is NULL, this is a unicast only engine
81 return pFlcn->engDescUc.base != 0 && pFlcn->engDescUc.initialized &&
82 (pFlcn->engDescBc.base == 0 || pFlcn->engDescBc.initialized);
83 }
84
85 /*
86 * @brief Waits for falcon to finish scrubbing IMEM/DMEM.
87 *
88 * @param[in] device switch device
89 * @param[in] pFlcn FLCN pointer
90 *
91 * @returns nothing
92 */
93 static NV_STATUS
_flcnWaitForResetToFinish_LR10(nvswitch_device * device,PFLCN pFlcn)94 _flcnWaitForResetToFinish_LR10
95 (
96 nvswitch_device *device,
97 PFLCN pFlcn
98 )
99 {
100 NVSWITCH_TIMEOUT timeout;
101 NvU32 dmaCtrl;
102
103 // Add a dummy write (of anything) to trigger scrubbing
104 flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_MAILBOX0, 0);
105
106 // TODO: Adapt timeout to our model, this should be centralized.
107 if (IS_EMULATION(device))
108 {
109 nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
110 }
111 else
112 {
113 nvswitch_timeout_create(NVSWITCH_INTERVAL_5MSEC_IN_NS, &timeout);
114 }
115
116 while (1)
117 {
118 dmaCtrl = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_DMACTL);
119
120 if (FLD_TEST_DRF(_PFALCON, _FALCON_DMACTL, _DMEM_SCRUBBING, _DONE, dmaCtrl) &&
121 FLD_TEST_DRF(_PFALCON, _FALCON_DMACTL, _IMEM_SCRUBBING, _DONE, dmaCtrl))
122 {
123 // Operation successful, IMEM and DMEM scrubbing has finished.
124 return NV_OK;
125 }
126
127 if (nvswitch_timeout_check(&timeout))
128 {
129 NVSWITCH_PRINT(device, ERROR,
130 "%s: Timeout waiting for scrubbing to finish!!!\n",
131 __FUNCTION__);
132 NVSWITCH_ASSERT(0);
133 return NV_ERR_TIMEOUT;
134 }
135 }
136 }
137
138 /*!
139 * @brief Capture and dump the falconPC trace.
140 *
141 * @param[in] device nvswitch device pointer
142 * @param[in] pFlcn FLCN object pointer
143 *
144 * @returns nothing
145 */
146 void
_flcnDbgInfoCapturePcTrace_LR10(nvswitch_device * device,PFLCN pFlcn)147 _flcnDbgInfoCapturePcTrace_LR10
148 (
149 nvswitch_device *device,
150 PFLCN pFlcn
151 )
152 {
153 NvU32 regTraceIdx;
154 NvU32 idx;
155 NvU32 maxIdx;
156
157 // Dump entire PC trace buffer
158 regTraceIdx = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_TRACEIDX);
159 maxIdx = DRF_VAL(_PFALCON_FALCON, _TRACEIDX, _MAXIDX, regTraceIdx);
160
161 NVSWITCH_PRINT(device, ERROR,
162 "PC TRACE (TOTAL %d ENTRIES. Entry 0 is the most recent branch):\n",
163 maxIdx);
164
165 for (idx = 0; idx < maxIdx; idx++)
166 {
167 regTraceIdx =
168 FLD_SET_DRF_NUM(_PFALCON, _FALCON_TRACEIDX, _IDX, idx, regTraceIdx);
169
170 flcnRegWrite_HAL(device, pFlcn, NV_PFALCON_FALCON_TRACEIDX, regTraceIdx);
171
172 NVSWITCH_PRINT(device, ERROR, "FALCON_TRACEPC(%d) : 0x%08x\n", idx,
173 DRF_VAL(_PFALCON, _FALCON_TRACEPC, _PC,
174 flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_TRACEPC)));
175 }
176 }
177
178 /*!
179 * @brief Read falcon core revision
180 *
181 * @param[in] device nvswitch_device pointer
182 * @param[in] pFlcn FLCN pointer
183 *
184 * @return @ref NV_FLCN_CORE_REV_X_Y.
185 */
186 NvU8
_flcnReadCoreRev_LR10(nvswitch_device * device,PFLCN pFlcn)187 _flcnReadCoreRev_LR10
188 (
189 nvswitch_device *device,
190 PFLCN pFlcn
191 )
192 {
193 NvU32 hwcfg1 = flcnRegRead_HAL(device, pFlcn, NV_PFALCON_FALCON_HWCFG1);
194
195 return ((DRF_VAL(_PFALCON, _FALCON_HWCFG1, _CORE_REV, hwcfg1) << 4) |
196 DRF_VAL(_PFALCON, _FALCON_HWCFG1, _CORE_REV_SUBVERSION, hwcfg1));
197 }
198
199 //
200 // Store pointers to ucode header and data.
201 // Preload ucode from registry if available.
202 //
203 NV_STATUS
_flcnConstruct_LR10(nvswitch_device * device,PFLCN pFlcn)204 _flcnConstruct_LR10
205 (
206 nvswitch_device *device,
207 PFLCN pFlcn
208 )
209 {
210 NV_STATUS status;
211 PFLCNABLE pFlcnable = pFlcn->pFlcnable;
212 PFALCON_QUEUE_INFO pQueueInfo;
213 pFlcn->bConstructed = NV_TRUE;
214
215 // Set the arch to Falcon
216 pFlcn->engArch = NV_UPROC_ENGINE_ARCH_FALCON;
217
218 // Allocate the memory for Queue Data Structure if needed.
219 if (pFlcn->bQueuesEnabled)
220 {
221 pQueueInfo = pFlcn->pQueueInfo = nvswitch_os_malloc(sizeof(*pQueueInfo));
222 if (pQueueInfo == NULL)
223 {
224 status = NV_ERR_NO_MEMORY;
225 NVSWITCH_ASSERT(0);
226 goto _flcnConstruct_LR10_fail;
227 }
228 nvswitch_os_memset(pQueueInfo, 0, sizeof(FALCON_QUEUE_INFO));
229 // Assert if Number of Queues are zero
230 NVSWITCH_ASSERT(pFlcn->numQueues != 0);
231 pQueueInfo->pQueues = nvswitch_os_malloc(sizeof(FLCNQUEUE) * pFlcn->numQueues);
232 if (pQueueInfo->pQueues == NULL)
233 {
234 status = NV_ERR_NO_MEMORY;
235 NVSWITCH_ASSERT(0);
236 goto _flcnConstruct_LR10_fail;
237 }
238 nvswitch_os_memset(pQueueInfo->pQueues, 0, sizeof(FLCNQUEUE) * pFlcn->numQueues);
239 // Sequences can be optional
240 if (pFlcn->numSequences != 0)
241 {
242 if ((pFlcn->numSequences - 1) > ((NvU32)NV_U8_MAX))
243 {
244 status = NV_ERR_OUT_OF_RANGE;
245 NVSWITCH_PRINT(device, ERROR,
246 "Max numSequences index = %d cannot fit into byte\n",
247 (pFlcn->numSequences - 1));
248 NVSWITCH_ASSERT(0);
249 goto _flcnConstruct_LR10_fail;
250 }
251 flcnQueueSeqInfoStateInit(device, pFlcn);
252 }
253 }
254 // DEBUG
255 NVSWITCH_PRINT(device, INFO, "Falcon: %s\n", flcnGetName_HAL(device, pFlcn));
256 NVSWITCH_ASSERT(pFlcnable != NULL);
257 flcnableGetExternalConfig(device, pFlcnable, &pFlcn->extConfig);
258 return NV_OK;
259 _flcnConstruct_LR10_fail:
260 // call flcnDestruct to free the memory allocated in this construct function
261 flcnDestruct_HAL(device, pFlcn);
262 return status;
263 }
264
265 void
_flcnDestruct_LR10(nvswitch_device * device,PFLCN pFlcn)266 _flcnDestruct_LR10
267 (
268 nvswitch_device *device,
269 PFLCN pFlcn
270 )
271 {
272 PFALCON_QUEUE_INFO pQueueInfo;
273 PFLCNABLE pFlcnable = pFlcn->pFlcnable;
274 if (!pFlcn->bConstructed)
275 {
276 return;
277 }
278 pFlcn->bConstructed = NV_FALSE;
279 if (pFlcnable == NULL) {
280 NVSWITCH_ASSERT(pFlcnable != NULL);
281 return;
282 }
283 if (pFlcn->bQueuesEnabled && (pFlcn->pQueueInfo != NULL))
284 {
285 pQueueInfo = pFlcn->pQueueInfo;
286 if (NULL != pQueueInfo->pQueues)
287 {
288 nvswitch_os_free(pQueueInfo->pQueues);
289 pQueueInfo->pQueues = NULL;
290 }
291 nvswitch_os_free(pFlcn->pQueueInfo);
292 pFlcn->pQueueInfo = NULL;
293 }
294 }
295 const char *
_flcnGetName_LR10(nvswitch_device * device,PFLCN pFlcn)296 _flcnGetName_LR10
297 (
298 nvswitch_device *device,
299 PFLCN pFlcn
300 )
301 {
302 if (pFlcn->name == NULL)
303 {
304 return "UNKNOWN";
305 }
306 return pFlcn->name;
307 }
308
309 /**
310 * @brief set hal function pointers for functions defined in LR10 (i.e. this file)
311 *
312 * this function has to be at the end of the file so that all the
313 * other functions are already defined.
314 *
315 * @param[in] pFlcn The flcn for which to set hals
316 */
317 void
flcnSetupHal_LR10(PFLCN pFlcn)318 flcnSetupHal_LR10
319 (
320 PFLCN pFlcn
321 )
322 {
323 flcn_hal *pHal = pFlcn->pHal;
324
325 pHal->readCoreRev = _flcnReadCoreRev_LR10;
326 pHal->regRead = _flcnRegRead_LR10;
327 pHal->regWrite = _flcnRegWrite_LR10;
328 pHal->construct = _flcnConstruct_LR10;
329 pHal->destruct = _flcnDestruct_LR10;
330 pHal->getName = _flcnGetName_LR10;
331 pHal->intrRetrigger = _flcnIntrRetrigger_LR10;
332 pHal->areEngDescsInitialized = _flcnAreEngDescsInitialized_LR10;
333 pHal->waitForResetToFinish = _flcnWaitForResetToFinish_LR10;
334 pHal->dbgInfoCapturePcTrace = _flcnDbgInfoCapturePcTrace_LR10;
335 }
336