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