1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2018-2019 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 "flcn/flcnable_nvswitch.h"
25 #include "flcn/flcn_nvswitch.h"
26 #include "rmflcncmdif_nvswitch.h"
27
28 #include "common_nvswitch.h"
29 #include "nvstatus.h"
30
31 /*!
32 * @brief Read the falcon core revision and subversion.
33 *
34 * @param[in] device nvswitch device pointer
35 * @param[in] pFlcnable FLCNABLE object pointer
36 *
37 * @return @ref NV_FLCN_CORE_REV_X_Y.
38 */
39 static NvU8
_flcnableReadCoreRev_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable)40 _flcnableReadCoreRev_IMPL
41 (
42 nvswitch_device *device,
43 PFLCNABLE pFlcnable
44 )
45 {
46 return flcnReadCoreRev_HAL(device, pFlcnable->pFlcn);
47 }
48
49 /*!
50 * @brief Get external config
51 */
52 static void
_flcnableGetExternalConfig_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable,PFALCON_EXTERNAL_CONFIG pConfig)53 _flcnableGetExternalConfig_IMPL
54 (
55 nvswitch_device *device,
56 PFLCNABLE pFlcnable,
57 PFALCON_EXTERNAL_CONFIG pConfig
58 )
59 {
60 pConfig->bResetInPmc = NV_FALSE;
61 pConfig->blkcgBase = 0xffffffff;
62 pConfig->fbifBase = 0xffffffff;
63 }
64
65 /*!
66 * @brief Retrieve content from falcon's EMEM.
67 */
68 static void
_flcnableEmemCopyFrom_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable,NvU32 src,NvU8 * pDst,NvU32 sizeBytes,NvU8 port)69 _flcnableEmemCopyFrom_IMPL
70 (
71 nvswitch_device *device,
72 PFLCNABLE pFlcnable,
73 NvU32 src,
74 NvU8 *pDst,
75 NvU32 sizeBytes,
76 NvU8 port
77 )
78 {
79 NVSWITCH_PRINT(device, ERROR,
80 "%s: FLCNABLE interface not implemented on this falcon!\n",
81 __FUNCTION__);
82 NVSWITCH_ASSERT(0);
83 }
84
85 /*!
86 * @brief Write content to falcon's EMEM.
87 */
88 static void
_flcnableEmemCopyTo_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable,NvU32 dst,NvU8 * pSrc,NvU32 sizeBytes,NvU8 port)89 _flcnableEmemCopyTo_IMPL
90 (
91 nvswitch_device *device,
92 PFLCNABLE pFlcnable,
93 NvU32 dst,
94 NvU8 *pSrc,
95 NvU32 sizeBytes,
96 NvU8 port
97 )
98 {
99 NVSWITCH_PRINT(device, ERROR,
100 "%s: FLCNABLE interface not implemented on this falcon!\n",
101 __FUNCTION__);
102 NVSWITCH_ASSERT(0);
103 }
104
105 /*
106 * @brief Handle INIT Event
107 */
108 static NV_STATUS
_flcnableHandleInitEvent_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable,RM_FLCN_MSG * pGenMsg)109 _flcnableHandleInitEvent_IMPL
110 (
111 nvswitch_device *device,
112 PFLCNABLE pFlcnable,
113 RM_FLCN_MSG *pGenMsg
114 )
115 {
116 return NV_OK;
117 }
118
119 /*!
120 * @brief Retrieves a pointer to the engine specific SEQ_INFO structure.
121 *
122 * @param[in] device nvswitch device pointer
123 * @param[in] pFlcnable FLCNABLE object pointer
124 * @param[in] seqIndex Index of the structure to retrieve
125 *
126 * @return Pointer to the SEQ_INFO structure or NULL on invalid index.
127 */
128 static PFLCN_QMGR_SEQ_INFO
_flcnableQueueSeqInfoGet_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable,NvU32 seqIndex)129 _flcnableQueueSeqInfoGet_IMPL
130 (
131 nvswitch_device *device,
132 PFLCNABLE pFlcnable,
133 NvU32 seqIndex
134 )
135 {
136 NVSWITCH_PRINT(device, ERROR,
137 "%s: FLCNABLE interface not implemented on this falcon!\n",
138 __FUNCTION__);
139 NVSWITCH_ASSERT(0);
140 return NULL;
141 }
142
143 /*!
144 * @brief Clear out the engine specific portion of the SEQ_INFO structure.
145 *
146 * @param[in] device nvswitch device pointer
147 * @param[in] pFlcnable FLCNABLE object pointer
148 * @param[in] pSeqInfo SEQ_INFO structure pointer
149 */
150 static void
_flcnableQueueSeqInfoClear_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable,PFLCN_QMGR_SEQ_INFO pSeqInfo)151 _flcnableQueueSeqInfoClear_IMPL
152 (
153 nvswitch_device *device,
154 PFLCNABLE pFlcnable,
155 PFLCN_QMGR_SEQ_INFO pSeqInfo
156 )
157 {
158 }
159
160 /*!
161 * @brief Free up all the engine specific sequence allocations.
162 *
163 * @param[in] device nvswitch device pointer
164 * @param[in] pFlcnable FLCNABLE object pointer
165 * @param[in] pSeqInfo SEQ_INFO structure pointer
166 */
167 static void
_flcnableQueueSeqInfoFree_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable,PFLCN_QMGR_SEQ_INFO pSeqInfo)168 _flcnableQueueSeqInfoFree_IMPL
169 (
170 nvswitch_device *device,
171 PFLCNABLE pFlcnable,
172 PFLCN_QMGR_SEQ_INFO pSeqInfo
173 )
174 {
175 }
176
177 /*!
178 * @brief Validate that the given CMD and related params are properly formed.
179 *
180 * @copydoc flcnQueueCmdPostNonBlocking_IMPL
181 *
182 * @return Boolean if command was properly formed.
183 */
184 static NvBool
_flcnableQueueCmdValidate_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable,PRM_FLCN_CMD pCmd,PRM_FLCN_MSG pMsg,void * pPayload,NvU32 queueIdLogical)185 _flcnableQueueCmdValidate_IMPL
186 (
187 nvswitch_device *device,
188 PFLCNABLE pFlcnable,
189 PRM_FLCN_CMD pCmd,
190 PRM_FLCN_MSG pMsg,
191 void *pPayload,
192 NvU32 queueIdLogical
193 )
194 {
195 NVSWITCH_PRINT(device, ERROR,
196 "%s: FLCNABLE interface not implemented on this falcon!\n",
197 __FUNCTION__);
198 NVSWITCH_ASSERT(0);
199 return NV_FALSE;
200 }
201
202 /*!
203 * @brief Engine specific command post actions.
204 *
205 * @copydoc flcnQueueCmdPostNonBlocking_IMPL
206 *
207 * @return NV_OK on success
208 * Failure specific error codes
209 */
210 static NV_STATUS
_flcnableQueueCmdPostExtension_IMPL(nvswitch_device * device,PFLCNABLE pFlcnable,PRM_FLCN_CMD pCmd,PRM_FLCN_MSG pMsg,void * pPayload,NVSWITCH_TIMEOUT * pTimeout,PFLCN_QMGR_SEQ_INFO pSeqInfo)211 _flcnableQueueCmdPostExtension_IMPL
212 (
213 nvswitch_device *device,
214 PFLCNABLE pFlcnable,
215 PRM_FLCN_CMD pCmd,
216 PRM_FLCN_MSG pMsg,
217 void *pPayload,
218 NVSWITCH_TIMEOUT *pTimeout,
219 PFLCN_QMGR_SEQ_INFO pSeqInfo
220 )
221 {
222 return NV_OK;
223 }
224
225 static void
_flcnablePostDiscoveryInit_IMPL(nvswitch_device * device,FLCNABLE * pSoe)226 _flcnablePostDiscoveryInit_IMPL
227 (
228 nvswitch_device *device,
229 FLCNABLE *pSoe
230 )
231 {
232 flcnPostDiscoveryInit(device, pSoe->pFlcn);
233 }
234
235 /**
236 * @brief sets pEngDescUc and pEngDescBc to the discovered
237 * engine that matches this flcnable instance
238 *
239 * @param[in] device nvswitch_device pointer
240 * @param[in] pSoe SOE pointer
241 * @param[out] pEngDescUc pointer to the UniCast Engine
242 * Descriptor Pointer
243 * @param[out] pEngDescBc pointer to the BroadCast Engine
244 * Descriptor Pointer
245 */
246 static void
_flcnableFetchEngines_IMPL(nvswitch_device * device,FLCNABLE * pSoe,ENGINE_DESCRIPTOR_TYPE * pEngDescUc,ENGINE_DESCRIPTOR_TYPE * pEngDescBc)247 _flcnableFetchEngines_IMPL
248 (
249 nvswitch_device *device,
250 FLCNABLE *pSoe,
251 ENGINE_DESCRIPTOR_TYPE *pEngDescUc,
252 ENGINE_DESCRIPTOR_TYPE *pEngDescBc
253 )
254 {
255 // Every falcon REALLY needs to implement this. If they don't flcnRegRead and flcnRegWrite won't work
256 NVSWITCH_PRINT(device, ERROR,
257 "%s: FLCNABLE interface not implemented on this falcon!\n",
258 __FUNCTION__);
259 NVSWITCH_ASSERT(0);
260 }
261
262
263 /* -------------------- Object construction/initialization ------------------- */
264 static void
flcnableSetupHal(FLCNABLE * pFlcnable,NvU32 pci_device_id)265 flcnableSetupHal
266 (
267 FLCNABLE *pFlcnable,
268 NvU32 pci_device_id
269 )
270 {
271 flcnable_hal *pHal = pFlcnable->pHal;
272
273 //init hal Interfaces
274 pHal->readCoreRev = _flcnableReadCoreRev_IMPL;
275 pHal->getExternalConfig = _flcnableGetExternalConfig_IMPL;
276 pHal->ememCopyFrom = _flcnableEmemCopyFrom_IMPL;
277 pHal->ememCopyTo = _flcnableEmemCopyTo_IMPL;
278 pHal->handleInitEvent = _flcnableHandleInitEvent_IMPL;
279 pHal->queueSeqInfoGet = _flcnableQueueSeqInfoGet_IMPL;
280 pHal->queueSeqInfoClear = _flcnableQueueSeqInfoClear_IMPL;
281 pHal->queueSeqInfoFree = _flcnableQueueSeqInfoFree_IMPL;
282 pHal->queueCmdValidate = _flcnableQueueCmdValidate_IMPL;
283 pHal->queueCmdPostExtension = _flcnableQueueCmdPostExtension_IMPL;
284 pHal->postDiscoveryInit = _flcnablePostDiscoveryInit_IMPL;
285 pHal->fetchEngines = _flcnableFetchEngines_IMPL;
286 }
287
288 NvlStatus
flcnableInit(nvswitch_device * device,FLCNABLE * pFlcnable,NvU32 pci_device_id)289 flcnableInit
290 (
291 nvswitch_device *device,
292 FLCNABLE *pFlcnable,
293 NvU32 pci_device_id
294 )
295 {
296 NvlStatus retval;
297 FLCN *pFlcn = NULL;
298
299 // allocate hal if a child class hasn't already
300 if (pFlcnable->pHal == NULL)
301 {
302 flcnable_hal *pHal = pFlcnable->pHal = nvswitch_os_malloc(sizeof(*pHal));
303 if (pHal == NULL)
304 {
305 NVSWITCH_PRINT(device, ERROR, "Flcn allocation failed!\n");
306 retval = -NVL_NO_MEM;
307 goto flcnable_init_fail;
308 }
309 nvswitch_os_memset(pHal, 0, sizeof(*pHal));
310 }
311
312 // init flcn - a little out of place here, since we're really only
313 // supposed to be initializing hals. However, we need pci_device_id
314 // to initialize flcn's hals and flcn is _very_ closely tied to
315 // flcnable so it kind of makes some sense to allocate it here
316 pFlcn = pFlcnable->pFlcn = flcnAllocNew();
317 if (pFlcn == NULL)
318 {
319 NVSWITCH_PRINT(device, ERROR, "Flcn allocation failed!\n");
320 retval = -NVL_NO_MEM;
321 goto flcnable_init_fail;
322 }
323 retval = flcnInit(device, pFlcn, pci_device_id);
324 if (retval != NVL_SUCCESS)
325 {
326 goto flcnable_init_fail;
327 }
328
329 //don't have a parent class to init, go straight to setupHal
330 flcnableSetupHal(pFlcnable, pci_device_id);
331
332 return retval;
333
334 flcnable_init_fail:
335 flcnableDestroy(device, pFlcnable);
336 return retval;
337 }
338
339 // reverse of flcnableInit()
340 void
flcnableDestroy(nvswitch_device * device,FLCNABLE * pFlcnable)341 flcnableDestroy
342 (
343 nvswitch_device *device,
344 FLCNABLE *pFlcnable
345 )
346 {
347 if (pFlcnable->pFlcn != NULL)
348 {
349 flcnDestroy(device, pFlcnable->pFlcn);
350 nvswitch_os_free(pFlcnable->pFlcn);
351 pFlcnable->pFlcn = NULL;
352 }
353
354 if (pFlcnable->pHal != NULL)
355 {
356 nvswitch_os_free(pFlcnable->pHal);
357 pFlcnable->pHal = NULL;
358 }
359 }
360