ef80816d4ff3a48ca79519d3962c76c65e9638c3
[mirror/winof/.git] / hw / mt23108 / vapi / Hca / hcahal / tavor / thh_hob / thh_hob.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 2004-2005 Mellanox Technologies Ltd.  All rights reserved.\r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32  \r
33 #include <mtl_common.h>\r
34 #include <cr_types.h>\r
35 #include <MT23108_PRM.h>\r
36 #include <vapi.h>\r
37 #include <vapi_common.h>\r
38 #include <hh.h>\r
39 #include <thh_hob_priv.h>\r
40 #include <sm_mad.h>\r
41 #include <tlog2.h>\r
42 #include <thh_default_profile.h>\r
43 #include <thhul_pdm.h>\r
44 #include <thh_srqm.h>\r
45 \r
46 #define TEST_RETURN_FATAL(hob)  if ((hob->thh_state & THH_STATE_HAVE_ANY_FATAL) != 0) {          \\r
47                            MTL_ERROR1(MT_FLFMT("%s: Device in FATAL state"), __func__);  \\r
48                            return HH_EFATAL;                               \\r
49                            }\r
50 #define TEST_CMD_FATAL(ret)  if (ret == THH_CMD_STAT_EFATAL) {                          \\r
51                            MTL_ERROR1(MT_FLFMT("%s: cmdif returned FATAL"), __func__);  \\r
52                            return HH_EFATAL;                                            \\r
53                            }\r
54 #define FREE_RSRC_RET(hob)    rc = ((have_fatal == TRUE) ? HH_OK : rc) ; return rc\r
55 #define DECLARE_FATAL_VARS    MT_bool  have_fatal=FALSE\r
56 #define WAIT_IF_FATAL(hob)    THH_hob_wait_if_fatal(hob,&have_fatal);\r
57 #define IB_MAX_MESSAGE_SIZE          (1 << 31)\r
58 #define CMD_EQ_SIZE 250 /* to be smaller then 8K - so it's EQ can get into physical memory */\r
59 \r
60 #if 4 <= MAX_DEBUG\r
61 #define THH_PRINT_PROFILE(a)      THH_print_profile(a)\r
62 #define THH_PRINT_USR_PROFILE(a)  THH_print_usr_profile(a)\r
63 #else\r
64 #define THH_PRINT_PROFILE(a)      \r
65 #define THH_PRINT_USR_PROFILE(a)\r
66 #endif\r
67 \r
68 /* global reference here for cmdif when putting Outbox in DDR memory*/\r
69 #ifdef DEBUG_MEM_OV\r
70 #define CMDIF_SIZE_IN_DDR   0x100000    /* allocate 1M in DDR memory*/ \r
71 MT_phys_addr_t cmdif_dbg_ddr; /* address in ddr used for out params in debug mode */\r
72 #endif\r
73 \r
74 \r
75 #define THH_WATERMARK 1024 /* 1K*/\r
76 \r
77 #define GET_DDR_ADDR(phys_addr,hide_ddr,ddr_base)   ((u_int64_t) ((((hide_ddr) == TRUE)&&(sizeof(MT_phys_addr_t)<=4)) ? \\r
78                                   (((u_int64_t)(phys_addr)) | ((ddr_base) & MAKE_ULONGLONG(0xFFFFFFFF00000000))) : phys_addr))\r
79                                                       \r
80 static HH_ret_t THH_hob_query_struct_init(THH_hob_t  hob, MT_bool have_usr_profile, VAPI_hca_cap_t *hca_cap_p);\r
81 static HH_ret_t   THH_hob_halt_hca(/*IN*/ THH_hob_t hob);\r
82 \r
83 \r
84 static void THH_dummy_async_event(HH_hca_hndl_t hca_hndl, HH_event_record_t  *event_rec_p, void* ptr)\r
85 {\r
86   /* TBD : This should be an error */\r
87   MTL_TRACE1("THH_dummy_async_event: called for devices %s with event type 0x%x",\r
88              hca_hndl->dev_desc, event_rec_p->etype);\r
89   return;\r
90 }\r
91 \r
92 static void THH_dummy_comp_event(HH_hca_hndl_t hca_hndl, HH_cq_hndl_t cq_num, void* ptr)\r
93 {\r
94   /* TBD : This should be an error */\r
95   MTL_TRACE1("THH_dummy_comp_event: called for device %s and  cq num 0x%x",\r
96                           hca_hndl->dev_desc, cq_num);\r
97   return;\r
98 }\r
99 \r
100 int THH_hob_fatal_err_thread(void  *arg);\r
101 \r
102 /******************************************************************************\r
103 ******************************************************************************\r
104 ************************  INTERNAL FUNCTIONS *********************************\r
105 ******************************************************************************\r
106 ******************************************************************************/\r
107 #if 4 <= MAX_DEBUG\r
108 static void THH_print_profile(THH_profile_t *profile) \r
109 {\r
110     MTL_DEBUG1("Profile printout\n");\r
111 \r
112     MTL_DEBUG1("        ddr_alloc_vec_size = "SIZE_T_DFMT"\n",profile->ddr_alloc_vec_size);\r
113     MTL_DEBUG1("        ddr_size = "SIZE_T_XFMT" ("SIZE_T_DFMT")\n", \r
114                profile->ddr_size,profile->ddr_size );\r
115 \r
116     MTL_DEBUG1("        ddr_size_code = %d\n", profile->ddr_size_code);\r
117     \r
118     MTL_DEBUG1("        num_external_mem_regions = "SIZE_T_XFMT" ("SIZE_T_DFMT")\n", \r
119                profile->num_external_mem_regions,profile->num_external_mem_regions );\r
120     MTL_DEBUG1("        num_mem_windows = "SIZE_T_XFMT" ("SIZE_T_DFMT")\n", \r
121                profile->num_mem_windows,profile->num_mem_windows);\r
122 \r
123     MTL_DEBUG1("        log2_max_qps = "SIZE_T_DFMT"\n", profile->log2_max_qps);\r
124     MTL_DEBUG1("        max_num_qps = "SIZE_T_XFMT" ("SIZE_T_DFMT")\n", \r
125                profile->max_num_qps,profile->max_num_qps);\r
126     MTL_DEBUG1("        log2_max_cqs = "SIZE_T_DFMT"\n", profile->log2_max_cqs);\r
127     MTL_DEBUG1("        max_num_cqs = "SIZE_T_XFMT" ("SIZE_T_DFMT")\n", \r
128                profile->max_num_cqs,profile->max_num_cqs);\r
129     MTL_DEBUG1("        max_num_pds = "SIZE_T_XFMT" ("SIZE_T_DFMT")\n", \r
130                profile->max_num_pds,profile->max_num_pds);\r
131 \r
132     MTL_DEBUG1("        log2_max_mpt_entries = "SIZE_T_DFMT"\n", profile->log2_max_mpt_entries);\r
133     MTL_DEBUG1("        log2_max_mtt_entries = "SIZE_T_DFMT"\n", profile->log2_max_mtt_entries);\r
134     MTL_DEBUG1("        log2_mtt_segs_per_region = "SIZE_T_DFMT"\n", profile->log2_mtt_segs_per_region);\r
135     MTL_DEBUG1("        log2_mtt_entries_per_seg = "SIZE_T_DFMT"\n", profile->log2_mtt_entries_per_seg);\r
136 \r
137     \r
138     MTL_DEBUG1("        log2_max_uar = "SIZE_T_DFMT"\n", profile->log2_max_uar);\r
139     MTL_DEBUG1("        log2_uar_pg_size = %d\n", profile->log2_uar_pg_size);\r
140     \r
141     MTL_DEBUG1("        log2_wqe_ddr_space_per_qp = "SIZE_T_DFMT"\n",profile->log2_wqe_ddr_space_per_qp);\r
142 \r
143     MTL_DEBUG1("        use_priv_udav  = %s\n", (profile->use_priv_udav ? "TRUE" : "FALSE"));\r
144     MTL_DEBUG1("        max_priv_udavs = "SIZE_T_XFMT" ("SIZE_T_DFMT")\n", \r
145                profile->max_priv_udavs,profile->max_priv_udavs);\r
146     \r
147     MTL_DEBUG1("        log2_max_mcgs = "SIZE_T_DFMT"\n", profile->log2_max_mcgs);\r
148     MTL_DEBUG1("        qps_per_mcg = "SIZE_T_DFMT"\n", profile->qps_per_mcg);\r
149     MTL_DEBUG1("        log2_mcg_entry_size = "SIZE_T_DFMT"\n", profile->log2_mcg_entry_size);\r
150     MTL_DEBUG1("        log2_mcg_hash_size = "SIZE_T_DFMT"\n",profile->log2_mcg_hash_size);\r
151 \r
152 \r
153     MTL_DEBUG1("        log2_max_eecs = "SIZE_T_DFMT"\n",profile->log2_max_eecs);\r
154 \r
155     MTL_DEBUG1("        log2_max_eqs = %d\n", profile->log2_max_eqs);\r
156         return;\r
157 }\r
158 \r
159 static void THH_print_usr_profile(EVAPI_hca_profile_t *profile) \r
160 {\r
161     MTL_DEBUG1("User Profile printout\n");\r
162 \r
163     MTL_DEBUG1("        num_qp = %d\n",profile->num_qp);\r
164     MTL_DEBUG1("        num_cq = %d\n",profile->num_cq);\r
165     MTL_DEBUG1("        num_pd = %d\n",profile->num_pd);\r
166     MTL_DEBUG1("        num_mr = %d\n",profile->num_mr);\r
167     MTL_DEBUG1("        num_mw = %d\n",profile->num_mw);\r
168     MTL_DEBUG1("        max_qp_ous_rd_atom = %d\n",profile->max_qp_ous_rd_atom);\r
169     MTL_DEBUG1("        max_mcg = %d\n",profile->max_mcg);\r
170     MTL_DEBUG1("        qp_per_mcg = %d\n",profile->qp_per_mcg);\r
171     MTL_DEBUG1("        require = %s\n",(profile->require == 0) ? "FALSE" : "TRUE");\r
172         return;\r
173 }\r
174 #endif\r
175 \r
176 static const char* THH_get_ddr_allocation_string (u_int32_t index)\r
177 {\r
178     switch(index) {\r
179         case 0: return "mtt sz";\r
180         case 1: return "mpt sz";\r
181         case 2: return "qpc sz";\r
182         case 3: return "eqpc sz";\r
183         case 4: return "srqc sz";\r
184         case 5: return "cqc sz";\r
185         case 6: return "rdb sz";\r
186         case 7: return "uar scratch sz";\r
187         case 8: return "eqc sz";\r
188         case 9: return "mcg sz";\r
189         case 10: return "eec sz";\r
190         case 11: return "eeec sz";\r
191     #if 0\r
192         case 12: return "wqe pool sz";\r
193         case 13: return "uplink qp sz";\r
194         case 14: return "uplink mem sz";\r
195     #endif\r
196         default: return "UNKNOWN";\r
197 \r
198     }\r
199 }\r
200 \r
201 \r
202 /*\r
203  * THH_get_ddr_size_code\r
204  *\r
205  */\r
206 static void THH_print_hw_props(THH_hw_props_t   *hw_props_p) \r
207 {\r
208     MTL_DEBUG4("%s:        cr_base = " PHYS_ADDR_FMT "\n", __func__, hw_props_p->cr_base);\r
209 //    MTL_DEBUG4("%s:        ddr_base = " PHYS_ADDR_FMT "\n", __func__hw_props_p->ddr_base);\r
210     MTL_DEBUG4("%s:        uar_base = " PHYS_ADDR_FMT "\n", __func__, hw_props_p->uar_base);\r
211     MTL_DEBUG4("%s:        device_id = 0x%x\n", __func__, hw_props_p->device_id);\r
212     MTL_DEBUG4("%s:        pci_vendor_id = 0x%x\n", __func__, hw_props_p->pci_vendor_id);\r
213     MTL_DEBUG4("%s:        intr_pin = 0x%x\n", __func__, hw_props_p->interrupt_props.intr_pin);\r
214 #ifndef __DARWIN__\r
215     //MOSAL_IRQ_ID_t does not have to be integer\r
216     MTL_DEBUG4("%s:        irq = 0x%x\n", __func__, hw_props_p->interrupt_props.irq);\r
217 #endif  /* not defined __DARWIN__ */\r
218     MTL_DEBUG4("%s:        bus = %d\n", __func__, hw_props_p->bus);\r
219     MTL_DEBUG4("%s:        dev_func = 0x%x\n", __func__, hw_props_p->dev_func);\r
220 }\r
221 \r
222 /*\r
223  * THH_get_ddr_size_code\r
224  *\r
225  */\r
226 static THH_ddr_size_enum_t THH_get_ddr_size_code(MT_size_t    ddr_size) \r
227 {\r
228     MTL_DEBUG4("THH_get_ddr_size_code: ddr size = "SIZE_T_FMT"\n", ddr_size);\r
229     if (ddr_size < (1UL<<25)) {\r
230         return THH_DDR_SIZE_32M;\r
231     } else if (ddr_size < (1UL<<26)) {\r
232         return THH_DDR_SIZE_64M;\r
233     } else if (ddr_size < (1UL<<27)) {\r
234         return THH_DDR_SIZE_128M;\r
235     } else if (ddr_size < (1UL<<28)) {\r
236         return THH_DDR_SIZE_256M;\r
237     } else if (ddr_size < (1UL<<29)) {\r
238         return THH_DDR_SIZE_512M;\r
239     } else if (ddr_size < (1UL<<30)) {\r
240         return THH_DDR_SIZE_1024M;\r
241     } else if (ddr_size < (1UL<<31)) {\r
242         return THH_DDR_SIZE_2048M;\r
243     } else if (ddr_size < 0xFFFFFFFF) {\r
244         return THH_DDR_SIZE_4096M;\r
245     } else {\r
246         return THH_DDR_SIZE_BIG;\r
247     }\r
248 }\r
249 #ifndef __DARWIN__\r
250 //TODO: all this code is OS dependent!\r
251 //Must work with the pointer to PCI device\r
252 \r
253 /*  \r
254  *  read_pci_config -- reads all configuration registers for given device\r
255  *  except for skipping regs 22 and 23\r
256  */\r
257 static HH_ret_t read_pci_config(u_int8_t bus, u_int8_t devfun, u_int32_t *config) \r
258 {\r
259     u_int8_t offset = 0;\r
260     HH_ret_t  rc = HH_OK;\r
261 \r
262     for (offset = 0; offset < 64; offset += 4) {\r
263       if (offset == 22 || offset == 23) {\r
264           continue;\r
265       }\r
266       rc = MOSAL_PCI_read_config_dword(bus,devfun,offset,config);\r
267       if (rc != MT_OK) {\r
268           return HH_ERR;\r
269       }\r
270       config++;\r
271     }\r
272     return HH_OK;\r
273 }\r
274 static HH_ret_t write_pci_config(u_int8_t bus, u_int8_t devfun, u_int32_t *config) \r
275 {\r
276     u_int8_t offset = 0;\r
277     HH_ret_t  rc = HH_OK;\r
278 \r
279     for (offset = 0; offset < 64; offset += 4) {\r
280       if (offset == 22 || offset == 23) {\r
281           continue;\r
282       }\r
283       rc = MOSAL_PCI_write_config_dword(bus,devfun,offset,*config);\r
284       if (rc != MT_OK) {\r
285           return HH_ERR;\r
286       }\r
287       config++;\r
288     }\r
289     return HH_OK;\r
290 }\r
291 /******************************************************************************\r
292  *  Function:     THH_hob_get_pci_br_config\r
293  *\r
294  *  Description:  Gets p2p bridge configuration for this hca's bridge  \r
295  *\r
296  *  input:\r
297  *                hob\r
298  *  output: \r
299  *                ack_timeout_p \r
300  *  returns:\r
301  *                HH_OK\r
302  *                HH_EINVAL\r
303  *                HH_EINVAL_HCA_HNDL\r
304  *                HH_ERR\r
305  *\r
306  *  Comments:     Does MAD query to get the data in real time. This function is used\r
307  *                in pre-calculation of VAPI_query_hca values (at open_hca time).\r
308  *\r
309  *****************************************************************************/\r
310 static HH_ret_t  THH_hob_get_pci_br_config(THH_hob_t  hob)\r
311 {\r
312     call_result_t  rc;\r
313     u_int16_t      index=0;\r
314     u_int8_t       bus;\r
315     u_int8_t       dev_func;\r
316     MOSAL_PCI_cfg_hdr_t cfg_hdr;\r
317 \r
318     MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
319     /* scan all bridges to find mellanox pci bridge which belongs to this hca */\r
320     while (TRUE) {\r
321       /*1. find device */\r
322       rc = MOSAL_PCI_find_device(hob->hw_props.pci_vendor_id,\r
323                                  (hob->hw_props.device_id)+2,\r
324                                  index, &bus, &dev_func);\r
325       index++;\r
326       if (rc != MT_OK) {\r
327         MTL_DEBUG4(MT_FLFMT("%s: No more InfiniBridges."), __func__); \r
328         break;\r
329       }\r
330       MTL_DEBUG4(MT_FLFMT("%s: InfiniBridge %d: pci_find_device returned: bus=%d, dev_func=%d"), \r
331                  __func__, index, bus, dev_func);\r
332       \r
333       /*2. get pci header */\r
334       rc = MOSAL_PCI_get_cfg_hdr(bus, dev_func, &cfg_hdr);\r
335       if (rc != MT_OK) {\r
336         MTL_ERROR4(MT_FLFMT("%s: Could not get header for device bus %d, dev_func 0x%x"),\r
337                    __func__, bus, dev_func); \r
338         continue;\r
339       }\r
340 \r
341       if ((cfg_hdr.type1.header_type & 0x7F) != MOSAL_PCI_HEADER_TYPE1) {\r
342         MTL_DEBUG1(MT_FLFMT("%s: Wrong PCI header type (0x%02X). Should be type 1. Device ignored."),\r
343                    __func__, cfg_hdr.type0.header_type);\r
344         continue; \r
345       }\r
346 \r
347       /*3. check if this is our bridge */\r
348       if (cfg_hdr.type1.sec_bus != hob->hw_props.bus) {\r
349         MTL_DEBUG1(MT_FLFMT("%s: Not our bridge. bus = %d, dev_num=%d"),\r
350                    __func__, bus, dev_func );\r
351         continue; \r
352       }\r
353 \r
354       /* found our bridge.  Read and save its configuration */\r
355       MTL_DEBUG1(MT_FLFMT("%s: found bridge. bus = %d, dev_num=%d"),\r
356                  __func__, bus, dev_func );\r
357       if (read_pci_config(bus,dev_func,hob->pci_bridge_info.config) != MT_OK) {\r
358           return (HH_ERR);\r
359       } else {\r
360           hob->pci_bridge_info.bus = bus;\r
361           hob->pci_bridge_info.dev_func = dev_func;\r
362           hob->pci_bridge_info.is_valid = TRUE;\r
363           return HH_OK;\r
364       }\r
365     }\r
366 \r
367     return HH_ERR; // did not find bridge\r
368 }\r
369 #endif /* not defined __DARWIN__ */\r
370 \r
371 /******************************************************************************\r
372  *  Function:     THH_hob_get_node_guid\r
373  *\r
374  *  Description:  Gets node GUID for this HCA.  \r
375  *\r
376  *  input:\r
377  *                hob\r
378  *                port_num - 1 or 2\r
379  *  output: \r
380  *                node_guid - pointer to a GUID structure\r
381  *  returns:\r
382  *                HH_OK\r
383  *                HH_EINVAL\r
384  *                HH_EINVAL_HCA_HNDL\r
385  *                HH_ERR\r
386  *\r
387  *  Comments:     Does MAD query to get the data in real time. This function is used\r
388  *                in pre-calculation of VAPI_query_hca values (at open_hca time).\r
389  *\r
390  *****************************************************************************/\r
391 static HH_ret_t THH_hob_get_node_guid(THH_hob_t  hob,\r
392                                      IB_guid_t   *node_guid)\r
393 {\r
394   SM_MAD_NodeInfo_t  node_info;\r
395   u_int8_t       *mad_frame_in;\r
396   u_int8_t       *mad_frame_out;\r
397   THH_cmd_status_t  cmd_ret;\r
398 \r
399   MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
400   MTL_DEBUG4("==> THH_hob_get_node_guid\n");\r
401   TEST_RETURN_FATAL(hob);\r
402 \r
403   mad_frame_in = TNMALLOC(u_int8_t, IB_MAD_SIZE);\r
404   if ( !mad_frame_in ) {\r
405     return HH_EAGAIN;\r
406   }\r
407   mad_frame_out = TNMALLOC(u_int8_t, IB_MAD_SIZE);\r
408   if ( !mad_frame_out ) {\r
409     FREE(mad_frame_in);\r
410     return HH_EAGAIN;\r
411   }\r
412   memset(mad_frame_in, 0, sizeof(mad_frame_in));\r
413   memset(mad_frame_out, 0, sizeof(mad_frame_out));\r
414 \r
415   /* get PKey table using MAD commands in THH_cmd object */\r
416   /* First, build the MAD header */\r
417   MADHeaderBuild(IB_CLASS_SMP, \r
418                     0,\r
419                     IB_METHOD_GET,\r
420                     IB_SMP_ATTRIB_NODEINFO,\r
421                     (u_int32_t)   0,\r
422                     &(mad_frame_in[0]));\r
423 \r
424   /* issue the query */\r
425   cmd_ret = THH_cmd_MAD_IFC(hob->cmd, 0, 0, 1, &(mad_frame_in[0]), &(mad_frame_out[0]));\r
426   if (cmd_ret != THH_CMD_STAT_OK) {\r
427       TEST_CMD_FATAL(cmd_ret);\r
428       MTL_ERROR2( "THH_hob_get_pkey_tbl: ERROR : Get Node Info command failed (%d) for port 1\n", cmd_ret);\r
429       MTL_DEBUG4("<== THH_hob_get_node_guid. ERROR\n");\r
430       FREE(mad_frame_out);\r
431       FREE(mad_frame_in);\r
432       return HH_EINVAL;\r
433   }\r
434   MadBufPrint(&(mad_frame_out[0]));\r
435   NodeInfoMADToSt(&node_info, &(mad_frame_out[0]));\r
436   NodeInfoPrint(&node_info);\r
437   \r
438 //  guid = node_info.qwNodeGUID;\r
439 //  MTL_DEBUG4("THH_hob_get_node_guid: Node GUID = 0x%Lx\n", guid);\r
440 //  for (i = 7; i >= 0 ; --i) {\r
441 //     (*node_guid)[i] = (u_int8_t) (guid & 0x0FF);\r
442 //     guid >>= 8;\r
443 //  }\r
444   memcpy((*node_guid), node_info.qwNodeGUID, sizeof(IB_guid_t));\r
445   MTL_DEBUG4("<== THH_hob_get_node_guid\n");\r
446   FREE(mad_frame_out);\r
447   FREE(mad_frame_in);\r
448   return HH_OK;\r
449 }\r
450 \r
451 /* now obtained from DEV_LIMS */\r
452 #if 0\r
453 /******************************************************************************\r
454  *  Function:     THH_hob_get_ack_timeout\r
455  *\r
456  *  Description:  Gets ack timeout for this HCA.  \r
457  *\r
458  *  input:\r
459  *                hob\r
460  *  output: \r
461  *                ack_timeout_p \r
462  *  returns:\r
463  *                HH_OK\r
464  *                HH_EINVAL\r
465  *                HH_EINVAL_HCA_HNDL\r
466  *                HH_ERR\r
467  *\r
468  *  Comments:     Does MAD query to get the data in real time. This function is used\r
469  *                in pre-calculation of VAPI_query_hca values (at open_hca time).\r
470  *\r
471  *****************************************************************************/\r
472 static HH_ret_t  THH_hob_get_ack_timeout(\r
473   THH_hob_t  hob,\r
474   u_int8_t*  ack_timeout_p)\r
475 {\r
476   SM_MAD_PortInfo_t  port_info;\r
477   u_int8_t       *mad_frame_in;\r
478   u_int8_t       *mad_frame_out;\r
479   THH_cmd_status_t  cmd_ret;\r
480 \r
481   MTL_DEBUG4("ENTERING THH_hob_get_ack_timeout\n");\r
482 \r
483   mad_frame_in = TNMALLOC(u_int8_t, IB_MAD_SIZE);\r
484   if ( !mad_frame_in ) {\r
485     return HH_EAGAIN;\r
486   }\r
487   mad_frame_out = TNMALLOC(u_int8_t, IB_MAD_SIZE);\r
488   if ( !mad_frame_out ) {\r
489     FREE(mad_frame_in);\r
490     return HH_EAGAIN;\r
491   }\r
492   memset(mad_frame_in, 0, sizeof(mad_frame_in));\r
493   memset(mad_frame_out, 0, sizeof(mad_frame_out));\r
494 \r
495   /* get PortInfo for port 12 (first port) */\r
496   /* First, build the MAD header */\r
497 \r
498   MADHeaderBuild(IB_CLASS_SMP, \r
499                     0,\r
500                     IB_METHOD_GET,\r
501                     IB_SMP_ATTRIB_PORTINFO,\r
502                     (u_int32_t)   1,\r
503                     &(mad_frame_in[0]));\r
504 \r
505   /* issue the query */\r
506   cmd_ret = THH_cmd_MAD_IFC(hob->cmd, 0, 0, 1, &(mad_frame_in[0]), &(mad_frame_out[0]));\r
507   if (cmd_ret != THH_CMD_STAT_OK) {\r
508       TEST_CMD_FATAL(cmd_ret);\r
509       MTL_ERROR2( "THH_hob_get_ack_timeout: ERROR : Get Port Info command failed (%d) for port 1\n", cmd_ret);\r
510       FREE(mad_frame_out);\r
511       FREE(mad_frame_in);\r
512       return HH_ERR;\r
513   }\r
514   PortInfoMADToSt(&port_info, &(mad_frame_out[0]));\r
515   PortInfoPrint(&port_info);\r
516 \r
517   *ack_timeout_p = port_info.cRespTimeValue;\r
518   FREE(mad_frame_out);\r
519   FREE(mad_frame_in);\r
520   return HH_OK;\r
521 }\r
522 #endif\r
523 \r
524 /******************************************************************************\r
525  *  Function:     calculate_ddr_alloc_vec\r
526  *\r
527  *  Description:  Calculates sizes for DDR area allocation from profile\r
528  *\r
529  *  input:\r
530  *                hob\r
531  *                profile        -- pointer to data structure containing computation input\r
532  *  output: \r
533  *                alloc_size_vec -- pointer to vector of allocation sizes to compute\r
534  *                \r
535  *  returns:\r
536  *                HH_OK\r
537  *\r
538  *\r
539  *****************************************************************************/\r
540 static void calculate_ddr_alloc_vec(/*IN*/ THH_hob_t     hob,\r
541                                             /*IN*/ THH_profile_t *profile,  \r
542                                             /*OUT*/THH_ddr_allocation_vector_t *alloc_size_vec)\r
543 {\r
544 \r
545     alloc_size_vec->log2_mtt_size = profile->log2_max_mtt_entries + THH_DDR_LOG2_MTT_ENTRY_SIZE; \r
546     alloc_size_vec->log2_mpt_size = profile->log2_max_mpt_entries + THH_DDR_LOG2_MPT_ENTRY_SIZE;   \r
547     alloc_size_vec->log2_qpc_size = profile->log2_max_qps + THH_DDR_LOG2_QPC_ENTRY_SIZE;\r
548     alloc_size_vec->log2_eqpc_size = profile->log2_max_qps + THH_DDR_LOG2_EQPC_ENTRY_SIZE; \r
549     alloc_size_vec->log2_srqc_size = hob->dev_lims.srq ? \r
550       profile->log2_max_srqs + THH_DDR_LOG2_SRQC_ENTRY_SIZE : THH_DDRMM_INVALID_SZ;\r
551     alloc_size_vec->log2_cqc_size = profile->log2_max_cqs + THH_DDR_LOG2_CQC_ENTRY_SIZE;\r
552     alloc_size_vec->log2_rdb_size = profile->log2_max_qps + profile->log2_inflight_rdma_per_qp + \r
553                                                         THH_DDR_LOG2_RDB_ENTRY_SIZE;\r
554     alloc_size_vec->log2_uar_scratch_size = profile->log2_max_uar + THH_DDR_LOG2_UAR_SCR_ENTRY_SIZE;  \r
555     alloc_size_vec->log2_eqc_size = profile->log2_max_eqs + THH_DDR_LOG2_EQC_ENTRY_SIZE; \r
556     if (THH_DEV_LIM_MCG_ENABLED(hob)) {\r
557          alloc_size_vec->log2_mcg_size = profile->log2_max_mcgs + profile->log2_mcg_entry_size;\r
558     } else {\r
559         alloc_size_vec->log2_mcg_size = 0;\r
560     }\r
561     alloc_size_vec->log2_eec_size = profile->log2_max_eecs + THH_DDR_LOG2_EEC_ENTRY_SIZE; \r
562     alloc_size_vec->log2_eeec_size = profile->log2_max_eecs + THH_DDR_LOG2_EEEC_ENTRY_SIZE;    /* in-flight rdma */\r
563 \r
564     return;\r
565 }\r
566 \r
567 \r
568 /******************************************************************************\r
569  *  Function:     THH_check_profile\r
570  *\r
571  *  Description:  Validates profile values against tavor max values, as obtained\r
572  *                from GET_DEV_LIM query\r
573  *\r
574  *  Details:\r
575  *\r
576  *****************************************************************************/\r
577 static HH_ret_t THH_check_profile(THH_hob_t   hob)\r
578 {\r
579     \r
580   MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
581     if (hob->profile.log2_uar_pg_size < hob->dev_lims.log_pg_sz) {\r
582         MTL_ERROR1("THH_calculate_default_profile:  log2 UAR page size(%u) is less than the Tavor minimum (%u)\n", \r
583                    hob->profile.log2_uar_pg_size, hob->dev_lims.log_pg_sz);\r
584         return HH_EAGAIN;\r
585     }\r
586     hob->profile.log2_max_qps             = (hob->profile.log2_max_qps > hob->dev_lims.log_max_qp) ? \r
587                                                          hob->dev_lims.log_max_qp : hob->profile.log2_max_qps; \r
588     hob->profile.log2_max_mcgs            = (hob->profile.log2_max_mcgs > hob->dev_lims.log_max_mcg) ? \r
589                                                          hob->dev_lims.log_max_mcg : hob->profile.log2_max_mcgs;\r
590     hob->profile.log2_max_eecs            = (hob->profile.log2_max_eecs > hob->dev_lims.log_max_ee) ? \r
591                                                          hob->dev_lims.log_max_ee : hob->profile.log2_max_eecs;\r
592     hob->profile.log2_max_cqs             = (hob->profile.log2_max_cqs > hob->dev_lims.log_max_cq) ? \r
593                                                          hob->dev_lims.log_max_cq : hob->profile.log2_max_cqs;\r
594     hob->profile.log2_max_uar             = (hob->profile.log2_max_uar > hob->dev_lims.uar_sz + 20UL - hob->profile.log2_uar_pg_size) ? \r
595                                                          hob->dev_lims.uar_sz + 20UL - hob->profile.log2_uar_pg_size : hob->profile.log2_max_uar;\r
596 \r
597     hob->profile.log2_max_eqs             = (hob->profile.log2_max_eqs > hob->dev_lims.log_max_eq) ? \r
598                                                          hob->dev_lims.log_max_eq : hob->profile.log2_max_eqs; \r
599     hob->profile.max_num_pds              = (hob->profile.max_num_pds > (1UL<<hob->dev_lims.log_max_pd)) ? \r
600                                                          (1UL<<hob->dev_lims.log_max_pd) : hob->profile.max_num_pds;  \r
601 \r
602     if (THH_DEV_LIM_MCG_ENABLED(hob)) {\r
603         hob->profile.qps_per_mcg         = (hob->profile.qps_per_mcg > (MT_size_t) (1U<<hob->dev_lims.log_max_qp_mcg)) ? \r
604                                                    (MT_size_t) (1U<<hob->dev_lims.log_max_qp_mcg) : hob->profile.qps_per_mcg;\r
605     }\r
606 \r
607     return HH_OK;\r
608 }\r
609 \r
610 \r
611 #define THH_PROFILE_CALC_QP_AT_MINIMUM     (1)\r
612 #define THH_PROFILE_CALC_CQ_AT_MINIMUM     (1 << 1)\r
613 #define THH_PROFILE_CALC_PD_AT_MINIMUM     (1 << 2)\r
614 #define THH_PROFILE_CALC_REG_AT_MINIMUM    (1 << 3)\r
615 #define THH_PROFILE_CALC_WIN_AT_MINIMUM    (1 << 4)\r
616 #define THH_PROFILE_CALC_ALL_AT_MINIMUM    (THH_PROFILE_CALC_QP_AT_MINIMUM | THH_PROFILE_CALC_CQ_AT_MINIMUM | \\r
617                                             THH_PROFILE_CALC_PD_AT_MINIMUM | THH_PROFILE_CALC_REG_AT_MINIMUM | \\r
618                                             THH_PROFILE_CALC_WIN_AT_MINIMUM )\r
619                                             \r
620 static int check_profile_sanity(THH_hob_t   hob, EVAPI_hca_profile_t *user_profile, THH_profile_input_t *thh_profile)\r
621 {\r
622     u_int64_t  tmp_calc;\r
623         /* check for bad minimum values */\r
624         if ((user_profile->num_qp == 0) || (user_profile->num_cq == 0) || (user_profile->num_pd == 0) ||\r
625             (user_profile->num_mr == 0) || (user_profile->max_qp_ous_rd_atom == 0) ) {\r
626             MTL_ERROR1(MT_FLFMT("profile: QPs or CQs or PDs or MRs or max_qp_ous_rd_atom equal to 0"));\r
627             return 0;\r
628         }\r
629         if (user_profile->num_qp > (1U<<hob->dev_lims.log_max_qp)) {\r
630             MTL_ERROR1(MT_FLFMT("profile: num QPs more than device limit(%d)"),\r
631                        (1U<<hob->dev_lims.log_max_qp));\r
632             return 0;\r
633         } else if (user_profile->num_qp < 1) {\r
634             MTL_ERROR1(MT_FLFMT("profile: num QPs must be at least 1"));\r
635             return 0;\r
636         }\r
637 \r
638         if (user_profile->num_cq > (1U<<hob->dev_lims.log_max_cq)) {\r
639             MTL_ERROR1(MT_FLFMT("profile: num CQs more than device limit(%d)"),\r
640                        (1U<<hob->dev_lims.log_max_cq));\r
641             return 0;\r
642         } else if (user_profile->num_cq < 1) {\r
643             MTL_ERROR1(MT_FLFMT("profile: num CQs must be at least 1"));\r
644             return 0;\r
645         }\r
646 \r
647         if (user_profile->num_pd > (1U<<hob->dev_lims.log_max_pd)) {\r
648             MTL_ERROR1(MT_FLFMT("profile: num PDs more than device limit(%d)"),\r
649                        (1U<<hob->dev_lims.log_max_pd));\r
650             return 0;\r
651         } else if (user_profile->num_pd < 1) {\r
652             MTL_ERROR1(MT_FLFMT("profile: num PDs must be at least 1"));\r
653             return 0;\r
654         }\r
655         if (user_profile->num_mr < 1) {\r
656             MTL_ERROR1(MT_FLFMT("profile: num MRs must be at least 1"));\r
657             return 0;\r
658         }\r
659         if (user_profile->max_qp_ous_rd_atom > (1U<<hob->dev_lims.log_max_ra_res_qp)) {\r
660             MTL_ERROR1(MT_FLFMT("profile: max_qp_ous_rd_atom more than device limit (%d)"),\r
661                        (1U<<hob->dev_lims.log_max_ra_res_qp));\r
662             return 0;\r
663         }\r
664 \r
665         if (ceil_log2((u_int64_t)user_profile->max_mcg) > hob->dev_lims.log_max_mcg) {\r
666             MTL_ERROR1(MT_FLFMT("profile: num MCGs more than device limit(%d)"),\r
667                        (1U<<hob->dev_lims.log_max_mcg));\r
668             return 0;\r
669         }\r
670 \r
671         if (ceil_log2((u_int64_t)user_profile->qp_per_mcg) > hob->dev_lims.log_max_qp_mcg) {\r
672             MTL_ERROR1(MT_FLFMT("profile: QPs per multicast group greater than device limit (%d)"),\r
673                        (1U<<hob->dev_lims.log_max_qp_mcg));\r
674             return 0;\r
675         }\r
676         if (user_profile->num_cq > (user_profile->num_qp * 2)) {\r
677             MTL_ERROR1(MT_FLFMT("profile: CQs more than twice QPs in hca profile"));\r
678             return 0;\r
679         }\r
680         if ((user_profile->max_mcg > 0) && (user_profile->qp_per_mcg < 8)) {\r
681             MTL_ERROR1(MT_FLFMT("profile: if MCGs not zero, QP_PER_MCG must be >= 8"));\r
682             return 0;\r
683         }\r
684         if (ceil_log2(user_profile->num_mr) > hob->dev_lims.log_max_mpts) {\r
685             MTL_ERROR1("profile:  Requested MRs use more MTTs than HCA provides\n");\r
686             return 0;\r
687         }\r
688         \r
689         tmp_calc = (u_int64_t)((u_int64_t) user_profile->num_qp +\r
690                                (u_int64_t) (unsigned long)THH_NUM_RSVD_QP +\r
691                                (u_int64_t) user_profile->num_cq + \r
692                                (u_int64_t) user_profile->num_mr);\r
693         if ( hob->dev_lims.log_max_mtt_seg < ceil_log2( tmp_calc * (u_int64_t)(1U<<thh_profile->log2_mtt_segs_per_region) )) {\r
694             MTL_ERROR1("profile:  Requested parameters (CQs + QPs + MRs) use more MTTs than HCA provides\n");\r
695             return 0;\r
696         }\r
697 \r
698 \r
699         if (ceil_log2(user_profile->num_mr) > hob->dev_lims.log_max_mpts) {\r
700             MTL_ERROR1("profile:  Requested MRs use more MPTs than HCA provides\n");\r
701             return 0;\r
702         }\r
703 \r
704         if (ceil_log2(user_profile->num_mw) > hob->dev_lims.log_max_mpts) {\r
705             MTL_ERROR1("profile:  Requested MWs use more MPTs than HCA provides\n");\r
706             return 0;\r
707         }\r
708 \r
709         tmp_calc = (u_int64_t)((u_int64_t) user_profile->num_qp +\r
710                                (u_int64_t) (unsigned long)THH_NUM_RSVD_QP +\r
711                                (u_int64_t) user_profile->num_cq + \r
712                                (u_int64_t) user_profile->num_mr + \r
713                                (u_int64_t) user_profile->num_mw);\r
714 \r
715         if ( hob->dev_lims.log_max_mpts < ceil_log2( tmp_calc)) {\r
716             MTL_ERROR1("profile:  Requested parameters (CQs + QPs + MRs + MWs) use more MPTs than HCA provides\n");\r
717             return 0;\r
718         }\r
719         return 1;\r
720 }\r
721 /******************************************************************************\r
722  *  Function:     THH_calculate_profile\r
723  *\r
724  *  Description:  Calculates and installs profile values\r
725  *\r
726  *  input\r
727  *                hob\r
728  *                profile_user_data - pointer to a user override for the data used\r
729  *                                    in calculating the THH profile.\r
730  *\r
731  *  Details:\r
732  *\r
733  *        All calculations are derived from the following data:\r
734  *\r
735  *        - max QPs = 64k per 128M DDR size (= 2^16)\r
736  *        - max MPT entries per HCA:       1M (= 2^20)\r
737  *        - avg Regions/windows per QP     8  (= 2^3)\r
738  *        - avg Segments per Region        8  (= 2^3)\r
739  *        - avg inflight RDMA per QP       4  (= 2^2)\r
740  *\r
741  *        Calculations are as follows:\r
742  *        Max UARs = 1 per QP\r
743  *        Max CQs  = 1 per QP\r
744  *        Max PDs  = 1 per QP\r
745  *        Max Regions/Wins per QP = 8, divided as follows:\r
746  *             internal regions = 2 per QP  (1 for QP, one for CQ)\r
747  *             external regions = 2 per QP\r
748  *             windows          = 4 per QP\r
749  *\r
750  *        MPT:\r
751  *           Tavor has a max of 1M regions/windows per HCA, and the MPT size must\r
752  *           be a power of 2.  It is pointless to have fewer than 8 regions/windows per QP\r
753  *           (as divided up above).  This means that the maximum number of QPs allowable,\r
754  *           regardless of DDR size, is 128K.  Therefore, the presence of the "min" function\r
755  *           in calculating the max number of MPT entries.  In effect, the 1M table size limitation\r
756  *           means that a DDR larger than 256M will only add to the user-available DDR memory, and\r
757  *           not to the driver's internal tables.\r
758  *\r
759  *        MTT:\r
760  *           The default MTT size allocated has 2 segments per Region, with a segment size of 8 entries.\r
761  *\r
762  *        MCG:  for 128M: 4096 Groups per HCA, with 16 QPs per group (so that entry size is 64 bytes).\r
763  *              for 256M: 8192 Groups per HCA, with 16 QPs per group (so that entry size is 64 bytes).\r
764  *\r
765  *        NOTES:\r
766  *           If the profile_user_data is NULL, default values are used.  After the profile calculation,\r
767  *           a check is done to see that all values are within HCA_DEV_LIM values, and that the result\r
768  *           does not exceed the DDR memory size.  If any violations are encountered, the number of QPs\r
769  *           is reduced by half, and the calculation is redone.\r
770  *           \r
771  *****************************************************************************/\r
772 static HH_ret_t THH_calculate_profile(THH_hob_t   hob, \r
773                                       EVAPI_hca_profile_t *profile_user_data,\r
774                                       EVAPI_hca_profile_t  *sugg_profile_p)\r
775 {\r
776     u_int8_t            log2_host_pg_size;\r
777     EVAPI_hca_profile_t local_user_profile;\r
778     THH_profile_input_t profile_input_data;\r
779     u_int64_t           tot_ddr_allocs;\r
780     THH_ddr_allocation_vector_t ddr_alloc_vec;\r
781     MT_size_t           *ddr_alloc_iterator, temp_size;\r
782     u_int32_t           i;\r
783     MT_bool             ddr_calc_loop = TRUE, need_to_loop = FALSE;\r
784     u_int32_t           calc_at_minimum = 0;\r
785 //    EVAPI_hca_profile_t hca_profile;\r
786 \r
787 \r
788     if (profile_user_data != NULL) {\r
789        \r
790         memcpy(&local_user_profile,  profile_user_data, sizeof(EVAPI_hca_profile_t));\r
791 \r
792         /* default value substitutions */\r
793         local_user_profile.num_qp = (local_user_profile.num_qp == 0xFFFFFFFF) ? \r
794                        THH_PROF_MAX_QPS : local_user_profile.num_qp; \r
795         local_user_profile.num_cq = (local_user_profile.num_cq == 0xFFFFFFFF) ? \r
796                                THH_PROF_MAX_CQS  : local_user_profile.num_cq; \r
797         local_user_profile.num_pd = (local_user_profile.num_pd == 0xFFFFFFFF) ? \r
798                                THH_PROF_MAX_PDS : local_user_profile.num_pd; \r
799         local_user_profile.num_mr = (local_user_profile.num_mr == 0xFFFFFFFF) ? \r
800                                THH_PROF_MAX_REGIONS : local_user_profile.num_mr; \r
801         local_user_profile.num_mw = (local_user_profile.num_mw == 0xFFFFFFFF) ? \r
802                                THH_PROF_MAX_WINDOWS : local_user_profile.num_mw;\r
803         \r
804         local_user_profile.max_qp_ous_rd_atom = (local_user_profile.max_qp_ous_rd_atom == 0xFFFFFFFF) ? \r
805                                (1 << THH_DDR_LOG2_INFLIGHT_RDMA_PER_QP):\r
806                                local_user_profile.max_qp_ous_rd_atom; \r
807 \r
808         local_user_profile.max_mcg = (local_user_profile.max_mcg == 0xFFFFFFFF) ? \r
809                                (1 << THH_DDR_LOG2_MAX_MCG):local_user_profile.max_mcg; \r
810         \r
811         local_user_profile.qp_per_mcg = (local_user_profile.qp_per_mcg == 0xFFFFFFFF) ? \r
812                                (1 << THH_DDR_LOG2_MIN_QP_PER_MCG):local_user_profile.qp_per_mcg; \r
813         \r
814         if (sugg_profile_p != NULL) {\r
815             memcpy(sugg_profile_p, &local_user_profile, sizeof(EVAPI_hca_profile_t));\r
816         }\r
817 \r
818         profile_input_data.max_qps        = local_user_profile.num_qp ;\r
819         profile_input_data.max_cqs        = local_user_profile.num_cq ;\r
820         profile_input_data.max_pds        = local_user_profile.num_pd ;\r
821         profile_input_data.max_regions    = local_user_profile.num_mr ;\r
822         profile_input_data.max_windows    = local_user_profile.num_mw ;\r
823 \r
824         profile_input_data.min_qps        = (1U<<hob->dev_lims.log2_rsvd_qps) + THH_NUM_RSVD_QP + 1;\r
825         profile_input_data.min_cqs        = (1U<<hob->dev_lims.log2_rsvd_cqs) + 1;\r
826         profile_input_data.min_pds        = hob->dev_lims.num_rsvd_pds + THH_NUM_RSVD_PD + 1;\r
827         profile_input_data.min_regions    = (1 << hob->dev_lims.log2_rsvd_mtts) + 1;\r
828         profile_input_data.min_windows    = (1 << hob->dev_lims.log2_rsvd_mrws);\r
829     \r
830         profile_input_data.reduction_pct_qps     = 10;\r
831         profile_input_data.reduction_pct_cqs     = 10;\r
832         profile_input_data.reduction_pct_pds     = 10;\r
833         profile_input_data.reduction_pct_regions = 10;\r
834         profile_input_data.reduction_pct_windows = 10;\r
835         \r
836         profile_input_data.log2_inflight_rdma_per_qp = ceil_log2(local_user_profile.max_qp_ous_rd_atom);\r
837         profile_input_data.log2_max_mcg              = ceil_log2(local_user_profile.max_mcg);\r
838         profile_input_data.log2_min_qp_per_mcg       = ceil_log2(local_user_profile.qp_per_mcg);\r
839         \r
840         profile_input_data.log2_max_eq               = THH_DDR_LOG2_MAX_EQ;\r
841         profile_input_data.log2_mcg_hash_proportion  = THH_DDR_LOG2_MCG_HASH_PROPORTION;\r
842         profile_input_data.log2_mtt_entries_per_seg  = THH_DDR_LOG2_MTT_ENTRIES_PER_SEG;\r
843         profile_input_data.log2_mtt_segs_per_region  = THH_DDR_LOG2_MTT_SEGS_PER_REGION;\r
844         profile_input_data.use_priv_udav             = THH_USE_PRIV_UDAV;\r
845         profile_input_data.log2_wqe_ddr_space_per_qp = THH_LOG2_WQE_DDR_SPACE_PER_QP;\r
846         /*sanity checks */\r
847         if (check_profile_sanity(hob,&local_user_profile, &profile_input_data) == 0) {\r
848             MTL_ERROR1(MT_FLFMT("THH_calculate_profile: user profile not valid"));\r
849             return HH_EINVAL_PARAM;\r
850         }\r
851     } else {\r
852         /* use internally defined default values */\r
853         profile_input_data.max_qps        = THH_PROF_MAX_QPS;\r
854         profile_input_data.max_cqs        = THH_PROF_MAX_CQS;\r
855         profile_input_data.max_pds        = THH_PROF_MAX_PDS;\r
856         profile_input_data.max_regions    = THH_PROF_MAX_REGIONS;\r
857         profile_input_data.max_windows    = THH_PROF_MAX_WINDOWS;\r
858         profile_input_data.max_priv_udavs = THH_DDR_MAX_PRIV_UDAVS;\r
859         \r
860         profile_input_data.min_qps        = THH_PROF_MIN_QPS;\r
861         profile_input_data.min_cqs        = THH_PROF_MIN_CQS;\r
862         profile_input_data.min_pds        = THH_PROF_MIN_PDS;\r
863         profile_input_data.min_regions    = THH_PROF_MIN_REGIONS;\r
864         profile_input_data.min_windows    = THH_PROF_MIN_WINDOWS;\r
865 \r
866         profile_input_data.reduction_pct_qps     = THH_PROF_PCNT_REDUCTION_QPS;\r
867         profile_input_data.reduction_pct_cqs     = THH_PROF_PCNT_REDUCTION_CQS;\r
868         profile_input_data.reduction_pct_pds     = THH_PROF_PCNT_REDUCTION_PDS;\r
869         profile_input_data.reduction_pct_regions = THH_PROF_PCNT_REDUCTION_REGIONS;\r
870         profile_input_data.reduction_pct_windows = THH_PROF_PCNT_REDUCTION_WINDOWS;\r
871         \r
872         profile_input_data.log2_inflight_rdma_per_qp = THH_DDR_LOG2_INFLIGHT_RDMA_PER_QP;\r
873         profile_input_data.log2_max_eq               = THH_DDR_LOG2_MAX_EQ;\r
874         profile_input_data.log2_max_mcg              = THH_DDR_LOG2_MAX_MCG;\r
875         profile_input_data.log2_min_qp_per_mcg       = THH_DDR_LOG2_MIN_QP_PER_MCG;\r
876         profile_input_data.log2_mcg_hash_proportion  = THH_DDR_LOG2_MCG_HASH_PROPORTION;\r
877         profile_input_data.log2_mtt_entries_per_seg  = THH_DDR_LOG2_MTT_ENTRIES_PER_SEG;\r
878         profile_input_data.log2_mtt_segs_per_region  = THH_DDR_LOG2_MTT_SEGS_PER_REGION;\r
879         profile_input_data.use_priv_udav             = THH_USE_PRIV_UDAV;\r
880         profile_input_data.log2_wqe_ddr_space_per_qp = THH_LOG2_WQE_DDR_SPACE_PER_QP;\r
881     }\r
882 \r
883     hob->profile.use_priv_udav = profile_input_data.use_priv_udav;\r
884     hob->profile.max_priv_udavs = profile_input_data.max_priv_udavs;\r
885     \r
886     /* need inflight rdma per QP for rdb size in DDR, and for THH_qpm_create */\r
887     hob->profile.log2_inflight_rdma_per_qp = (u_int8_t) profile_input_data.log2_inflight_rdma_per_qp;\r
888 \r
889     /* manipulate MCG max if not inputting a profile, or if inputting profile which allows reduction */\r
890     /* Reduce the number of MCGs for smaller DDR memories */\r
891     hob->profile.log2_max_mcgs            = profile_input_data.log2_max_mcg;\r
892     if ((hob->profile.ddr_size_code < THH_DDR_SIZE_128M)\r
893         && ((profile_user_data == NULL)|| (local_user_profile.require == FALSE))) {\r
894             hob->profile.log2_max_mcgs--;\r
895     }\r
896 \r
897     log2_host_pg_size = MOSAL_SYS_PAGE_SHIFT;\r
898     if (log2_host_pg_size < hob->dev_lims.log_pg_sz) {\r
899         MTL_ERROR1("THH_calculate_default_profile:  Host min page size(%lu) is too small\n", \r
900                    (unsigned long ) MOSAL_SYS_PAGE_SIZE);\r
901         return HH_EAGAIN;\r
902     }\r
903 \r
904     /* do not allocate DDR memory for MCGs if MCG is not enabled in dev_limits  */\r
905     hob->profile.ddr_alloc_vec_size = (THH_DEV_LIM_MCG_ENABLED(hob) ? \r
906                                        THH_DDR_ALLOCATION_VEC_SIZE : THH_DDR_ALLOCATION_VEC_SIZE - 1) ;  /* no eec as yet */\r
907     hob->profile.log2_wqe_ddr_space_per_qp = profile_input_data.log2_wqe_ddr_space_per_qp;\r
908     \r
909     /* MCG calculations - not in recalculation loop, since the amount of memory involved is very small*/\r
910     /* each MCG entry must be a power-of-2 size. To guarantee a power-of-2, we take a "ceiling" log of the */\r
911     /* MCG entry size(in bytes), and then compute the actual number of QPs per mcg backwards from the mcg_size variable. */\r
912     /* We also require (as a sanity check) that the log2_mcg_hash_size be greater than zero */\r
913     if ((THH_DEV_LIM_MCG_ENABLED(hob)) &&\r
914         ((int)(hob->profile.log2_max_mcgs + profile_input_data.log2_mcg_hash_proportion) > 0)) {\r
915         hob->profile.log2_mcg_entry_size = ceil_log2(((1U<<profile_input_data.log2_min_qp_per_mcg) * THH_DDR_MCG_BYTES_PER_QP) + \r
916                                                      THH_DDR_MCG_ENTRY_HEADER_SIZE);\r
917         hob->profile.qps_per_mcg    = ( (1U<<(hob->profile.log2_mcg_entry_size)) - THH_DDR_MCG_ENTRY_HEADER_SIZE) / \r
918                                                              THH_DDR_MCG_BYTES_PER_QP;\r
919     \r
920         /* the hash proportion is the log of the power-of-2 fraction of the total MCG entries used for the hash table. */\r
921         /* Thus, for example, a proportion of (1/2) gets a log2_mcg_hash_proportion = -1 */\r
922         hob->profile.log2_mcg_hash_size  = hob->profile.log2_max_mcgs + profile_input_data.log2_mcg_hash_proportion;\r
923     } else {\r
924         /*UD MCGs not available on this HCA*/\r
925         hob->profile.log2_mcg_entry_size = 0;\r
926         hob->profile.qps_per_mcg    = 0;\r
927         hob->profile.log2_mcg_hash_size  = 0;\r
928         hob->profile.log2_max_mcgs = 0;\r
929         }\r
930     \r
931     hob->profile.log2_mtt_entries_per_seg = profile_input_data.log2_mtt_entries_per_seg;\r
932     hob->profile.log2_mtt_segs_per_region = profile_input_data.log2_mtt_segs_per_region;\r
933     \r
934     hob->profile.log2_uar_pg_size         = log2_host_pg_size;\r
935     hob->profile.log2_max_uar             = hob->dev_lims.uar_sz + 20 - hob->profile.log2_uar_pg_size;\r
936 /*** warning C4242: '=' : conversion from 'u_int32_t' to 'u_int8_t', possible loss of data ***/\r
937     hob->profile.log2_max_eqs             = (u_int8_t)profile_input_data.log2_max_eq;      /* 64 EQs */\r
938     hob->profile.max_num_pds              = profile_input_data.max_pds;\r
939 \r
940     hob->profile.max_num_qps              = profile_input_data.max_qps;\r
941 \r
942     hob->profile.log2_max_qps             = ceil_log2(profile_input_data.max_qps+ \r
943                                                (1U<<hob->dev_lims.log2_rsvd_qps) + THH_NUM_RSVD_QP); \r
944     \r
945     /* adjust max QPs downward (if using internal profile, or if user profile permits)\r
946      * if the few reserved QPs cause max qps to go beyond a power-of-2.\r
947      */\r
948 \r
949     if (hob->profile.log2_max_qps > ceil_log2(profile_input_data.max_qps)) {\r
950         MTL_DEBUG1(MT_FLFMT("%s:  reserved qps cause profile qps to jump a power-of-2"),__func__);\r
951         if ((profile_user_data==NULL) || (local_user_profile.require == FALSE)) {\r
952             hob->profile.log2_max_qps--;\r
953             hob->profile.max_num_qps = (1U<<hob->profile.log2_max_qps) - (1U<<hob->dev_lims.log2_rsvd_qps)\r
954                                                                            - THH_NUM_RSVD_QP;\r
955             MTL_DEBUG1(MT_FLFMT("%s: Adjusting max qps to "SIZE_T_DFMT),__func__, hob->profile.max_num_qps);\r
956         }\r
957     }\r
958 \r
959     /* TBD: Expose max_srqs to profile given by user and use MOD_STAT_CFG */\r
960     if (hob->dev_lims.srq) {\r
961       hob->profile.log2_max_srqs            = hob->dev_lims.log_max_srqs;\r
962       hob->profile.max_num_srqs             = \r
963         (1U << hob->dev_lims.log_max_srqs) - (1 << hob->dev_lims.log2_rsvd_srqs);\r
964     } else {\r
965       hob->profile.log2_max_srqs            = 0;\r
966       hob->profile.max_num_srqs             = 0;\r
967     }\r
968     \r
969     hob->profile.max_num_cqs              = profile_input_data.max_cqs;\r
970     hob->profile.log2_max_cqs             = ceil_log2(profile_input_data.max_cqs + \r
971                                                       (1U<<hob->dev_lims.log2_rsvd_cqs)); \r
972     /* adjust max CQs downward (if using internal profile, or if user profile permits) \r
973      * if the few reserved CQs cause max cqs to go beyond a power-of-2.\r
974      */\r
975 \r
976     if (hob->profile.log2_max_cqs > ceil_log2(profile_input_data.max_cqs)) {\r
977         MTL_DEBUG1(MT_FLFMT("%s:  reserved cqs cause profile cqs to jump a power-of-2"),__func__);\r
978         if ((profile_user_data == NULL) || (local_user_profile.require == FALSE)) {\r
979             hob->profile.log2_max_cqs--;\r
980             hob->profile.max_num_cqs = (1U<<hob->profile.log2_max_cqs) - (1U<<hob->dev_lims.log2_rsvd_cqs);\r
981             MTL_DEBUG1(MT_FLFMT("%s: Adjusting max cqs to "SIZE_T_DFMT),__func__, hob->profile.max_num_cqs);\r
982         }\r
983     }\r
984     hob->profile.num_external_mem_regions = profile_input_data.max_regions;  /* 2 per QP */\r
985     hob->profile.num_mem_windows          = profile_input_data.max_windows;\r
986     hob->profile.log2_max_eecs            = 0;\r
987 \r
988     while (ddr_calc_loop) {\r
989         MT_bool continue_calc_loop;\r
990 \r
991         continue_calc_loop = FALSE;\r
992     \r
993         MTL_DEBUG4("THH_calculate_profile: max_qps = "SIZE_T_FMT", max_cqs = "SIZE_T_FMT", max_priv_udav="SIZE_T_FMT\r
994                    ",\nmax_pds="SIZE_T_FMT",max_reg="SIZE_T_FMT", max_win="SIZE_T_FMT"\n",\r
995                         hob->profile.max_num_qps, hob->profile.max_num_cqs, hob->profile.max_priv_udavs,\r
996                         hob->profile.max_num_pds, hob->profile.num_external_mem_regions, \r
997                         hob->profile.num_mem_windows); \r
998 \r
999         /* add all raw resources without Tavor-reserved quantities */\r
1000         temp_size = hob->profile.max_num_qps + THH_NUM_RSVD_QP + \r
1001                     hob->profile.max_num_cqs + hob->profile.num_external_mem_regions;\r
1002         \r
1003         hob->profile.log2_max_mtt_entries     = ceil_log2(\r
1004                                                    ( temp_size * (1U<<profile_input_data.log2_mtt_segs_per_region)\r
1005                                                       * (1U<<profile_input_data.log2_mtt_entries_per_seg))\r
1006                                                    + (1 << hob->dev_lims.log2_rsvd_mtts)\r
1007                                                 );\r
1008     \r
1009         /* add all raw resources without Tavor-reserved quantities */\r
1010         temp_size = hob->profile.max_num_qps + THH_NUM_RSVD_QP + hob->profile.max_num_cqs \r
1011             + hob->profile.num_external_mem_regions + hob->profile.num_mem_windows;\r
1012         \r
1013         hob->profile.log2_max_mpt_entries       = ceil_log2(temp_size + (1 << hob->dev_lims.log2_rsvd_mrws));\r
1014     \r
1015     \r
1016         if (hob->profile.log2_max_mtt_entries - profile_input_data.log2_mtt_entries_per_seg \r
1017              > hob->dev_lims.log_max_mtt_seg) {\r
1018             continue_calc_loop = TRUE;\r
1019             need_to_loop = TRUE;\r
1020         }\r
1021         \r
1022         if (!continue_calc_loop) {\r
1023             /* Now, compute the total DDR size, and verify that we have not over-allocated it.  If yes, reduce QPs by half, and */\r
1024             /* recompute all above parameters starting with log2_max_regions */\r
1025             calculate_ddr_alloc_vec(hob, &(hob->profile),&ddr_alloc_vec);\r
1026         \r
1027             /* Add up all the sizes in the ddr allocation vector */\r
1028             tot_ddr_allocs = 0;\r
1029             ddr_alloc_iterator = (MT_size_t *)&(ddr_alloc_vec);\r
1030             for (i = 0; i < hob->profile.ddr_alloc_vec_size; i++, ddr_alloc_iterator++) {\r
1031                 if ((*ddr_alloc_iterator) == THH_DDRMM_INVALID_SZ) {\r
1032                     temp_size = 0;  /* no allocation */\r
1033                 } else if ((*ddr_alloc_iterator) >= ceil_log2(hob->profile.ddr_size)) {\r
1034                     temp_size = hob->profile.ddr_size;\r
1035                 } else  {\r
1036                     temp_size =  (((MT_size_t) 1ul) << (*ddr_alloc_iterator));\r
1037                 }\r
1038                 MTL_DEBUG4("THH_calculate_profile:DDR: %s = "SIZE_T_XFMT"("SIZE_T_DFMT")\n", \r
1039                            THH_get_ddr_allocation_string(i), temp_size, temp_size); \r
1040                 tot_ddr_allocs += temp_size;\r
1041             }\r
1042             \r
1043             /* see if need to reserve space for WQEs in DDR */\r
1044             if (hob->profile.log2_wqe_ddr_space_per_qp != 0) {\r
1045                 temp_size =  (((MT_size_t) 1ul) << (hob->profile.log2_max_qps + hob->profile.log2_wqe_ddr_space_per_qp));\r
1046                 MTL_DEBUG4("THH_calculate_profile:  WQEs ddr area = "SIZE_T_XFMT" ("SIZE_T_DFMT")\n", \r
1047                            temp_size, temp_size); \r
1048                 tot_ddr_allocs += temp_size;\r
1049             }\r
1050         \r
1051             /* see if need to reserve space for privileged UDAVs in DDR */\r
1052             if (hob->profile.use_priv_udav) {\r
1053                 temp_size =  hob->profile.max_priv_udavs * (sizeof(struct tavorprm_ud_address_vector_st) / 8);\r
1054                 MTL_DEBUG4("THH_calculate_profile:  privileged UDAVs ddr area = "SIZE_T_XFMT" ("SIZE_T_DFMT")\n",\r
1055                             temp_size, temp_size); \r
1056                 tot_ddr_allocs += temp_size;\r
1057             }\r
1058         \r
1059             /* test against DDR size */\r
1060             MTL_DEBUG4("THH_calculate_profile:  total DDR allocs = %d MB (incl reserved areas)\n",(int)(tot_ddr_allocs>>20)); \r
1061             if ((hob->profile.ddr_size < tot_ddr_allocs) || \r
1062                           ((profile_user_data == NULL) && (hob->profile.max_num_qps>(1U<<16)))){ \r
1063                           /*do not want more than 64K QPs if using internal defaults*/\r
1064                 continue_calc_loop = TRUE;\r
1065                 need_to_loop = TRUE;\r
1066             }\r
1067 \r
1068         }\r
1069         if (continue_calc_loop) {\r
1070             u_int64_t  temp;\r
1071             u_int32_t  u32_temp, change_flag;\r
1072             /* Reduce flagged profile input params by factor of 10 percent */\r
1073             change_flag = 0;\r
1074             if ((calc_at_minimum & THH_PROFILE_CALC_QP_AT_MINIMUM) == 0) {\r
1075                 change_flag++;\r
1076                 temp = (u_int64_t)(hob->profile.max_num_qps) * (100 - profile_input_data.reduction_pct_qps);\r
1077                 /*check for overflow. If have overflow, use approximate percentages (divide by 1024) */\r
1078                 if (temp & MAKE_ULONGLONG(0xFFFFFFFF00000000)) {\r
1079                     temp = (u_int64_t)(hob->profile.max_num_qps) * (1024 - (profile_input_data.reduction_pct_qps*10));\r
1080                     temp >>= 10;\r
1081                     u32_temp = (u_int32_t)(temp & 0xFFFFFFFF);\r
1082                 } else {\r
1083                     /* use more exact percentages -- but still not floating point */\r
1084                     u32_temp = (u_int32_t)temp;\r
1085                     u32_temp /= 100;\r
1086                 }\r
1087                 if (u32_temp <= (u_int32_t)profile_input_data.min_qps) {\r
1088                     calc_at_minimum |= THH_PROFILE_CALC_QP_AT_MINIMUM;\r
1089                     u32_temp = profile_input_data.min_qps;\r
1090                 }\r
1091                 hob->profile.max_num_qps = u32_temp;\r
1092                 hob->profile.log2_max_qps = ceil_log2(u32_temp + (1U<<hob->dev_lims.log2_rsvd_qps) \r
1093                                                       + THH_NUM_RSVD_QP);\r
1094             }\r
1095             \r
1096             \r
1097             if ((calc_at_minimum & THH_PROFILE_CALC_CQ_AT_MINIMUM) == 0) {\r
1098                 change_flag++;\r
1099                 temp = (u_int64_t)(hob->profile.max_num_cqs) * (100 - profile_input_data.reduction_pct_cqs);\r
1100                 if (temp & MAKE_ULONGLONG(0xFFFFFFFF00000000)) {\r
1101                     temp = (u_int64_t)(hob->profile.max_num_cqs) * (1024 - (profile_input_data.reduction_pct_cqs*10));\r
1102                     temp >>= 10;\r
1103                     u32_temp = (u_int32_t)(temp & 0xFFFFFFFF);\r
1104                 } else {\r
1105                     /* use more exact percentages -- but still not floating point */\r
1106                     u32_temp = (u_int32_t)temp;\r
1107                     u32_temp /= 100;\r
1108                 }\r
1109                 if (u32_temp <= (u_int32_t)profile_input_data.min_cqs) {\r
1110                     calc_at_minimum |= THH_PROFILE_CALC_CQ_AT_MINIMUM;\r
1111                     u32_temp = profile_input_data.min_cqs;\r
1112                 }\r
1113                 hob->profile.max_num_cqs = u32_temp;\r
1114                 hob->profile.log2_max_cqs = ceil_log2(u32_temp + (1U<<hob->dev_lims.log2_rsvd_cqs));\r
1115             }\r
1116 \r
1117             if ((calc_at_minimum & THH_PROFILE_CALC_PD_AT_MINIMUM) == 0) {\r
1118                 change_flag++;\r
1119                 temp = (u_int64_t)(hob->profile.max_num_pds) * (100 - profile_input_data.reduction_pct_pds);\r
1120                 if (temp & MAKE_ULONGLONG(0xFFFFFFFF00000000)) {\r
1121                     temp = (u_int64_t)(hob->profile.max_num_pds) * (1024 - (profile_input_data.reduction_pct_pds*10));\r
1122                     temp >>= 10;\r
1123                     u32_temp = (u_int32_t)(temp & 0xFFFFFFFF);\r
1124                 } else {\r
1125                     /* use more exact percentages -- but still not floating point */\r
1126                     u32_temp = (u_int32_t)temp;\r
1127                     u32_temp /= 100;\r
1128                 }\r
1129                 if (u32_temp <= (u_int32_t)profile_input_data.min_pds) {\r
1130                     calc_at_minimum |= THH_PROFILE_CALC_PD_AT_MINIMUM;\r
1131                     u32_temp = profile_input_data.min_pds;\r
1132                 }\r
1133                 hob->profile.max_num_pds = u32_temp;\r
1134             }\r
1135 \r
1136             if ((calc_at_minimum & THH_PROFILE_CALC_REG_AT_MINIMUM) == 0) {\r
1137                 change_flag++;\r
1138                 temp = (u_int64_t)(hob->profile.num_external_mem_regions) * (100 - profile_input_data.reduction_pct_regions);\r
1139                 if (temp & MAKE_ULONGLONG(0xFFFFFFFF00000000)) {\r
1140                     temp = (u_int64_t)(hob->profile.num_external_mem_regions) * (1024 - (profile_input_data.reduction_pct_regions*10));\r
1141                     temp >>= 10;\r
1142                     u32_temp = (u_int32_t)(temp & 0xFFFFFFFF);\r
1143                 } else {\r
1144                     /* use more exact percentages -- but still not floating point */\r
1145                     u32_temp = (u_int32_t)temp;\r
1146                     u32_temp /= 100;\r
1147                 }\r
1148                 if (u32_temp <= (u_int32_t)profile_input_data.min_regions) {\r
1149                     calc_at_minimum |= THH_PROFILE_CALC_REG_AT_MINIMUM;\r
1150                     u32_temp = profile_input_data.min_regions;\r
1151                 }\r
1152                 hob->profile.num_external_mem_regions = u32_temp;\r
1153             }\r
1154 \r
1155             if ((calc_at_minimum & THH_PROFILE_CALC_WIN_AT_MINIMUM) == 0) {\r
1156                 change_flag++;\r
1157                 temp = (u_int64_t)(hob->profile.num_mem_windows) * (100 - profile_input_data.reduction_pct_windows);\r
1158                 if (temp & MAKE_ULONGLONG(0xFFFFFFFF00000000)) {\r
1159                     temp = (u_int64_t)(hob->profile.num_mem_windows) * (1024 - (profile_input_data.reduction_pct_windows*10));\r
1160                     temp >>= 10;\r
1161                     u32_temp = (u_int32_t)(temp & 0xFFFFFFFF);\r
1162                 } else {\r
1163                     /* use more exact percentages -- but still not floating point */\r
1164                     u32_temp = (u_int32_t)temp;\r
1165                     u32_temp /= 100;\r
1166                 }\r
1167                 if (u32_temp <= (u_int32_t)profile_input_data.min_windows) {\r
1168                     calc_at_minimum |= THH_PROFILE_CALC_WIN_AT_MINIMUM;\r
1169                     u32_temp = profile_input_data.min_windows;\r
1170                 }\r
1171                 hob->profile.num_mem_windows = u32_temp;\r
1172             }\r
1173             if (hob->profile.log2_inflight_rdma_per_qp > THH_DDR_LOG2_INFLIGHT_RDMA_PER_QP) {\r
1174                  hob->profile.log2_inflight_rdma_per_qp--;\r
1175                  change_flag++;\r
1176             }\r
1177 \r
1178             /* check if we were able to perform any reductions */\r
1179             if (change_flag == 0) {\r
1180                 MTL_ERROR1("THH_calculate_default_profile:  DDR memory to small for MIN profile\n");\r
1181                 ddr_alloc_iterator = (MT_size_t *)&(ddr_alloc_vec);\r
1182                 for (i = 0; i < hob->profile.ddr_alloc_vec_size; i++, ddr_alloc_iterator++) {\r
1183                     if ((*ddr_alloc_iterator) == THH_DDRMM_INVALID_SZ) {\r
1184                         temp_size = 0;  /* no allocation */\r
1185                     } else if ((*ddr_alloc_iterator) >= ceil_log2(hob->profile.ddr_size)) {\r
1186                         temp_size = hob->profile.ddr_size;\r
1187                         MTL_ERROR1(MT_FLFMT("THH_calculate_profile: %s uses ALL available DDR memory"), \r
1188                                THH_get_ddr_allocation_string(i)); \r
1189                     } else  {\r
1190                         temp_size =  (((MT_size_t) 1ul) << (*ddr_alloc_iterator));\r
1191                     }\r
1192                     MTL_ERROR1(MT_FLFMT("THH_calculate_profile:DDR: %s = "SIZE_T_XFMT"("SIZE_T_DFMT")"), \r
1193                                THH_get_ddr_allocation_string(i), temp_size, temp_size); \r
1194                 }\r
1195                 return HH_EAGAIN;\r
1196             }\r
1197         } else {\r
1198             ddr_calc_loop = FALSE;\r
1199         }\r
1200     }\r
1201     \r
1202     THH_check_profile(hob);  /* final adjustment to catch dev-lim overruns*/\r
1203 \r
1204     /* adjust mcg hash table after final adjustment of mcg size */\r
1205     if (THH_DEV_LIM_MCG_ENABLED(hob)) {\r
1206         hob->profile.log2_mcg_hash_size  =  (hob->profile.log2_max_mcgs) + profile_input_data.log2_mcg_hash_proportion;\r
1207 /*** error C4296: '<' : expression is always false ***/\r
1208         //if (hob->profile.log2_mcg_hash_size < 0) {\r
1209         //    hob->profile.log2_mcg_hash_size = 0;\r
1210         //}\r
1211     }\r
1212 \r
1213     THH_PRINT_PROFILE(&(hob->profile));\r
1214     MTL_DEBUG4("Leaving THH_calculate_profile\n");\r
1215 \r
1216     if (sugg_profile_p != NULL) { \r
1217             sugg_profile_p->num_mw = (u_int32_t)hob->profile.num_mem_windows;\r
1218             sugg_profile_p->num_qp = (u_int32_t)hob->profile.max_num_qps;\r
1219             sugg_profile_p->num_cq = (u_int32_t)hob->profile.max_num_cqs;\r
1220             sugg_profile_p->num_pd = (u_int32_t)hob->profile.max_num_pds;\r
1221             sugg_profile_p->num_mr = (u_int32_t)hob->profile.num_external_mem_regions;\r
1222             sugg_profile_p->max_qp_ous_rd_atom = (1U<<hob->profile.log2_inflight_rdma_per_qp);\r
1223     }\r
1224     if ((profile_user_data != NULL) && (profile_user_data->require != 0) && (need_to_loop == TRUE)) {\r
1225             MTL_ERROR1("THH_calculate_default_profile:  Provided profile requires too many resources\n");\r
1226         return HH_ENOMEM;\r
1227     }\r
1228     return HH_OK;\r
1229 }\r
1230 \r
1231 /*****************************************************************************\r
1232 ******************************************************************************\r
1233 ************************  HOB Interface FUNCTIONS ****************************\r
1234 ******************************************************************************\r
1235 ******************************************************************************/\r
1236 \r
1237 /******************************************************************************\r
1238  *  Function:     THH_hob_close_hca\r
1239  *\r
1240  *  Description:  This function stops HCA hardware activity and frees all associated resources.\r
1241  *\r
1242  *  input:\r
1243  *                hca_hndl\r
1244  *  output: \r
1245  *                none\r
1246  *  returns:\r
1247  *                HH_OK\r
1248  *                HH_EINVAL_HCA_HNDL\r
1249  *                HH_ERR\r
1250  *\r
1251  *  Comments:     If any errors occur, continue process of de-allocating resources.  However, log the errors,\r
1252  *                and return HH_ERR instead of HH_OK\r
1253  *\r
1254  *****************************************************************************/\r
1255 HH_ret_t THH_hob_close_hca_internal(HH_hca_hndl_t  hca_hndl, MT_bool invoked_from_destroy)\r
1256 {\r
1257   /* TBD - Complete function */\r
1258     THH_cmd_status_t    cmd_ret;\r
1259     MT_bool             have_error = FALSE;\r
1260     HH_ret_t            ret = HH_OK;\r
1261     MT_phys_addr_t         *ddr_alloc_area;\r
1262     MT_size_t           *ddr_alloc_size;\r
1263     u_int32_t           i;\r
1264     u_int16_t           num_ports;\r
1265     call_result_t       res;\r
1266     THH_hob_t  thh_hob_p;\r
1267     DECLARE_FATAL_VARS;\r
1268 \r
1269     MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
1270     if (MOSAL_get_exec_ctx() != MOSAL_IN_TASK) {\r
1271         MTL_ERROR1("THH_hob_close_hca: NOT IN TASK CONTEXT)\n");\r
1272         return HH_ERR;\r
1273     }\r
1274 \r
1275     if (hca_hndl == NULL) {\r
1276         MTL_ERROR1("THH_hob_close_hca : ERROR : Invalid HCA handle\n");\r
1277         return HH_EINVAL_HCA_HNDL;\r
1278     }\r
1279     thh_hob_p = THHOBP(hca_hndl);\r
1280         if (thh_hob_p == NULL) {\r
1281                 MTL_ERROR1("THH_hob_close_hca : ERROR : HOB is already destroyed\n");\r
1282                 return HH_ERR;\r
1283         }\r
1284     \r
1285     /* uninterruptible acquire.  Want to be sure to clean up */\r
1286     MOSAL_mutex_acq_ui(&(thh_hob_p->mtx));\r
1287     if (hca_hndl->status == HH_HCA_STATUS_CLOSED) {\r
1288         MOSAL_mutex_rel(&(thh_hob_p->mtx));\r
1289         MTL_ERROR1("THH_hob_close_hca: Device already closed\n");\r
1290         return HH_EINVAL_HCA_HNDL;\r
1291     }\r
1292     \r
1293     /* move the HCA to CLOSING state, preserving fatal indicators */\r
1294     MOSAL_spinlock_dpc_lock(&thh_hob_p->fatal_spl);\r
1295     if ((thh_hob_p->thh_state & THH_STATE_RUNNING) == 0) {\r
1296         MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
1297         MOSAL_mutex_rel(&(thh_hob_p->mtx));\r
1298         MTL_ERROR1(MT_FLFMT("THH_hob_close_hca:  already invoked"));\r
1299         return HH_EBUSY;\r
1300     }\r
1301     thh_hob_p->thh_state &= THH_STATE_HAVE_ANY_FATAL;\r
1302     thh_hob_p->thh_state |= THH_STATE_CLOSING;\r
1303     MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
1304 \r
1305     /* transfer to closing state */    \r
1306     WAIT_IF_FATAL(thh_hob_p);\r
1307     if (have_fatal == FALSE) {\r
1308         num_ports = thh_hob_p->dev_lims.num_ports;\r
1309         for (i = 1; i <= num_ports; i++) {\r
1310             cmd_ret = THH_cmd_CLOSE_IB(thh_hob_p->cmd, (IB_port_t) i);\r
1311             if (cmd_ret != THH_CMD_STAT_OK) {\r
1312                 MTL_ERROR1("THH_hob_close_hca: THH_cmd_CLOSE_IB error (%d)\n", cmd_ret);\r
1313                 have_error = TRUE;\r
1314             }\r
1315         }\r
1316     }\r
1317     /* test if a fatal error occurred during CLOSE_IB. */\r
1318     if (have_fatal == FALSE) {\r
1319         WAIT_IF_FATAL(thh_hob_p);\r
1320     }\r
1321     thh_hob_p->compl_eq = THH_INVALID_EQN;\r
1322     thh_hob_p->ib_eq = THH_INVALID_EQN;\r
1323     \r
1324     /* destroy eventq mgr.  Event manager must destroy all EQs */\r
1325     ret = THH_eventp_destroy( thh_hob_p->eventp );\r
1326     if (ret != HH_OK) {\r
1327         MTL_ERROR1("THH_hob_close_hca: THH_eventp_destroy error (%d)\n", ret);\r
1328         have_error = TRUE;\r
1329     }\r
1330     thh_hob_p->eventp = (THH_eventp_t)THH_INVALID_HNDL;\r
1331 \r
1332     if (thh_hob_p->mcgm != (THH_mcgm_t)THH_INVALID_HNDL) {\r
1333         ret = THH_mcgm_destroy(thh_hob_p->mcgm );\r
1334         if (ret != HH_OK) {\r
1335             MTL_ERROR1("THH_hob_close_hca: THH_mcgm_destroy error (%d)\n", ret);\r
1336             have_error = TRUE;\r
1337         }\r
1338         thh_hob_p->mcgm = (THH_mcgm_t)THH_INVALID_HNDL;\r
1339     }\r
1340 \r
1341     MTL_DEBUG4("%s: calling MOSAL_unmap_phys_addr FOR KAR = " VIRT_ADDR_FMT "\n", __func__,\r
1342                (MT_virt_addr_t) thh_hob_p->kar_addr);\r
1343     if ((res = (MOSAL_unmap_phys_addr(MOSAL_get_kernel_prot_ctx(), (MT_virt_addr_t) thh_hob_p->kar_addr, \r
1344                                ((MT_size_t)1 << thh_hob_p->profile.log2_uar_pg_size)))) != MT_OK) {\r
1345         MTL_ERROR1("THH_hob_close_hca: MOSAL_unmap_phys_addr error for kar: %d\n", res);\r
1346         have_error = TRUE;\r
1347     }\r
1348     thh_hob_p->kar_addr = (MT_virt_addr_t) 0;\r
1349     \r
1350     ret = THH_uar_destroy(thh_hob_p->kar);\r
1351     if (ret != HH_OK) {\r
1352         MTL_ERROR1("THH_hob_close_hca: THH_uar_destroy error (%d)\n", ret);\r
1353         have_error = TRUE;\r
1354     }\r
1355     thh_hob_p->kar = (THH_uar_t)THH_INVALID_HNDL;\r
1356 \r
1357 \r
1358     if (thh_hob_p->udavm_use_priv) {\r
1359         ret = THH_udavm_destroy(thh_hob_p->udavm);\r
1360         if (ret != HH_OK) {\r
1361             MTL_ERROR1("THH_hob_close_hca: THH_udavm_destroy error (%d)\n", ret);\r
1362             have_error = TRUE;\r
1363         }\r
1364         thh_hob_p->udavm = (THH_udavm_t)THH_INVALID_HNDL;\r
1365 \r
1366         ret = THH_mrwm_deregister_mr(thh_hob_p->mrwm, thh_hob_p->udavm_lkey);\r
1367         if (ret != HH_OK) {\r
1368             MTL_ERROR1("THH_hob_close_hca: THH_mrwm_deregister_mr error (%d)\n", ret);\r
1369             have_error = TRUE;\r
1370         }\r
1371 \r
1372         if ((res = MOSAL_unmap_phys_addr( MOSAL_get_kernel_prot_ctx(), \r
1373                                     (MT_virt_addr_t)  thh_hob_p->udavm_table , \r
1374                                     thh_hob_p->udavm_table_size )) != MT_OK) {\r
1375             MTL_ERROR1("THH_hob_close_hca: MOSAL_unmap_phys_addr error for udavm: %d\n", res);\r
1376             have_error = TRUE;\r
1377         }\r
1378         thh_hob_p->udavm_table = (MT_virt_addr_t) NULL;\r
1379 \r
1380         ret = THH_ddrmm_free(thh_hob_p->ddrmm, thh_hob_p->udavm_table_ddr, thh_hob_p->udavm_table_size);\r
1381         if (ret != HH_OK) {\r
1382             MTL_ERROR1("THH_hob_close_hca: THH_ddrmm_free error (%d)\n", ret);\r
1383             have_error = TRUE;\r
1384         }\r
1385  \r
1386     }\r
1387     thh_hob_p->udavm = (THH_udavm_t)THH_INVALID_HNDL;\r
1388     thh_hob_p->udavm_table = (MT_virt_addr_t) NULL;\r
1389     thh_hob_p->udavm_table_ddr  = (MT_phys_addr_t) 0;\r
1390     thh_hob_p->udavm_table_size = 0;\r
1391     thh_hob_p->udavm_lkey = 0;\r
1392 \r
1393     if (thh_hob_p->srqm != (THH_srqm_t)THH_INVALID_HNDL) { /* SRQs are supported - SRQM exists */\r
1394       ret = THH_srqm_destroy( thh_hob_p->srqm);\r
1395       if (ret != HH_OK) {\r
1396           MTL_ERROR1("THH_hob_close_hca: THH_srqm_destroy error %s(%d)\n", HH_strerror_sym(ret), ret);\r
1397           have_error = TRUE;\r
1398       }\r
1399       thh_hob_p->srqm = (THH_srqm_t)THH_INVALID_HNDL;\r
1400     }\r
1401     \r
1402     ret = THH_qpm_destroy( thh_hob_p->qpm, have_error);\r
1403     if (ret != HH_OK) {\r
1404         MTL_ERROR1("THH_hob_close_hca: THH_qpm_destroy error (%d)\n", ret);\r
1405         have_error = TRUE;\r
1406     }\r
1407     thh_hob_p->qpm = (THH_qpm_t)THH_INVALID_HNDL;\r
1408 \r
1409     FREE(thh_hob_p->init_ib_props);\r
1410     thh_hob_p->init_ib_props = ( THH_port_init_props_t *) NULL;\r
1411 \r
1412     ret = THH_cqm_destroy( thh_hob_p->cqm, have_error);\r
1413     if (ret != HH_OK) {\r
1414         MTL_ERROR1("THH_hob_close_hca: THH_cqm_destroy error (%d)\n", ret);\r
1415         have_error = TRUE;\r
1416     }\r
1417     thh_hob_p->cqm = (THH_cqm_t)THH_INVALID_HNDL;\r
1418 \r
1419     ret = THH_mrwm_destroy(thh_hob_p->mrwm, have_error);\r
1420     if (ret != HH_OK) {\r
1421         MTL_ERROR1("THH_hob_close_hca: THH_mrwm_destroy error (%d)\n", ret);\r
1422         have_error = TRUE;\r
1423     }\r
1424     thh_hob_p->mrwm = (THH_mrwm_t)THH_INVALID_HNDL;\r
1425 \r
1426     ret = THH_uldm_destroy(thh_hob_p->uldm );\r
1427     if (ret != HH_OK) {\r
1428         MTL_ERROR1("THH_hob_close_hca: THH_uldm_destroy error (%d)\n", ret);\r
1429         have_error = TRUE;\r
1430     }\r
1431     thh_hob_p->uldm = (THH_uldm_t)THH_INVALID_HNDL;\r
1432 \r
1433     ret = THH_cmd_revoke_ddrmm(thh_hob_p->cmd);\r
1434     if (ret != HH_OK) {\r
1435         MTL_ERROR1("THH_hob_close_hca: THH_cmd_revoke_ddrmm error (%d)\n", ret);\r
1436         have_error = TRUE;\r
1437     }\r
1438 \r
1439     ddr_alloc_area = (MT_phys_addr_t *) &(thh_hob_p->ddr_alloc_base_addrs_vec);\r
1440     ddr_alloc_size = (MT_size_t *)&(thh_hob_p->ddr_alloc_size_vec);\r
1441     for (i = 0; i < thh_hob_p->profile.ddr_alloc_vec_size; i++, ddr_alloc_area++, ddr_alloc_size++) {\r
1442         ret = *ddr_alloc_area != THH_DDRMM_INVALID_PHYS_ADDR ?\r
1443           THH_ddrmm_free(thh_hob_p->ddrmm,*ddr_alloc_area, ((MT_size_t)1<< (*ddr_alloc_size))) : HH_OK;\r
1444         if (ret != HH_OK) {\r
1445             MTL_ERROR1("THH_hob_close_hca: THH_ddrmm_free error (%d). i = %d\n", ret, i);\r
1446             have_error = TRUE;\r
1447         }\r
1448     }\r
1449 \r
1450     /* test for fatal again here */\r
1451     if (have_fatal == FALSE) {\r
1452         WAIT_IF_FATAL(thh_hob_p);\r
1453     }\r
1454     if (have_fatal == FALSE) {\r
1455         MTL_TRACE1("THH_hob_close_hca: Performing THH_cmd_CLOSE_HCA (no fatal)\n");\r
1456 #ifdef SIMULATE_HALT_HCA\r
1457         cmd_ret = THH_cmd_CLOSE_HCA(thh_hob_p->cmd);\r
1458 #else\r
1459         cmd_ret = THH_cmd_CLOSE_HCA(thh_hob_p->cmd, FALSE);\r
1460 #endif\r
1461         if (cmd_ret != THH_CMD_STAT_OK) {\r
1462             MTL_ERROR1("THH_hob_close_hca: THH_cmd_CLOSE_HCA error (%d)\n", cmd_ret);\r
1463             have_error = TRUE;\r
1464         }\r
1465     }\r
1466     hca_hndl->status = HH_HCA_STATUS_CLOSED;\r
1467 \r
1468     /* move state to "CLOSED"*/\r
1469     MOSAL_spinlock_dpc_lock(&thh_hob_p->fatal_spl);\r
1470     thh_hob_p->thh_state &= THH_STATE_HAVE_ANY_FATAL;\r
1471     thh_hob_p->thh_state |= THH_STATE_CLOSED;\r
1472     MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
1473     MOSAL_mutex_rel(&(thh_hob_p->mtx));\r
1474 \r
1475     MTL_TRACE2("THH_hob_close_hca: device name %s\n", hca_hndl->dev_desc);\r
1476 \r
1477     if (have_fatal == FALSE) {\r
1478         WAIT_IF_FATAL(thh_hob_p);\r
1479     }\r
1480     if ((have_fatal == TRUE) && (invoked_from_destroy == FALSE)) {\r
1481         // Leo: (WINDOWS) restart doen't work because the card reset doesn't work\r
1482         #ifndef __WIN__\r
1483         MTL_TRACE1("THH_hob_close_hca: HAVE FATAL, restarting\n");\r
1484         ret = THH_hob_restart(hca_hndl);\r
1485         if (ret != HH_OK) {\r
1486             MTL_ERROR1("THH_hob_close_hca: THH_hob_restart error (%d)\n", ret);\r
1487             have_error = TRUE;\r
1488         }\r
1489         #endif\r
1490     }\r
1491     if (have_error && (have_fatal == FALSE)) {\r
1492         return HH_ERR;\r
1493     } else {\r
1494         return(HH_OK);\r
1495     }\r
1496 } /* THH_hob_close_hca_internal */\r
1497 \r
1498 HH_ret_t THH_hob_close_hca(HH_hca_hndl_t  hca_hndl)\r
1499 {\r
1500     MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
1501     return (THH_hob_close_hca_internal(hca_hndl,FALSE));\r
1502 }\r
1503 \r
1504 \r
1505 /******************************************************************************\r
1506  *  Function:     THH_hob_destroy\r
1507  *\r
1508  *  Description:  Deregister given device from HH and free the HH object.\r
1509  *\r
1510  *  input:\r
1511  *                hca_hndl\r
1512  *  output: \r
1513  *                none\r
1514  *  returns:\r
1515  *                HH_OK\r
1516  *                HH_EINVAL_HCA_HNDL\r
1517  *\r
1518  *  Comments:     If HCA is still open,THH_hob_close_hca() is \r
1519  *                invoked before freeing the THH_hob.\r
1520  *\r
1521  *                Returns HH_EINVAL_HCA_HNDL if any function called internally fails  \r
1522  *\r
1523  *****************************************************************************/\r
1524 HH_ret_t    THH_hob_destroy(HH_hca_hndl_t hca_hndl)\r
1525 {\r
1526   HH_ret_t  ret, fn_ret = HH_OK;\r
1527   THH_cmd_status_t   cmd_ret;\r
1528   THH_hob_t          hob_p;\r
1529   int                int_ret = 0;\r
1530 #if !defined(__DARWIN__) && !defined(__WIN__)\r
1531   MT_virt_addr_t     va;\r
1532 #endif\r
1533   call_result_t      mosal_ret;\r
1534   MT_bool            have_fatal = FALSE;\r
1535 \r
1536   MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
1537   if (MOSAL_get_exec_ctx() != MOSAL_IN_TASK) {\r
1538       MTL_ERROR1("THH_hob_destroy: NOT IN TASK CONTEXT)\n");\r
1539       return HH_ERR;\r
1540   }\r
1541 \r
1542   if (hca_hndl == NULL) {\r
1543       MTL_ERROR1("THH_hob_destroy : ERROR : Invalid HCA handle\n");\r
1544       return HH_EINVAL_HCA_HNDL;\r
1545   }\r
1546   \r
1547   /* return ERROR if device is still open */\r
1548   if (hca_hndl->status != HH_HCA_STATUS_CLOSED) {\r
1549       MTL_ERROR1("THH_hob_destroy:  Unloading device %s: while it is still open.  Attempting to close it.\n", hca_hndl->dev_desc);\r
1550       ret = THH_hob_close_hca_internal(hca_hndl, TRUE);\r
1551       if (ret != HH_OK) {\r
1552         MTL_ERROR1("THH_hob_destroy: Could not close device %s: not opened or unknown (err=%d)\n", hca_hndl->dev_desc, ret);\r
1553         fn_ret = HH_EINVAL_HCA_HNDL;\r
1554       }\r
1555       hca_hndl->status = HH_HCA_STATUS_CLOSED;\r
1556   }\r
1557 \r
1558   MTL_TRACE2("THH_hob_destroy: removing the device %s\n",  hca_hndl->dev_desc);\r
1559   hob_p = THHOBP(hca_hndl);\r
1560   if (hob_p == NULL) {\r
1561       MTL_ERROR1("THH_hob_destroy : ERROR : HOB is already destroyed\n");\r
1562       return HH_ERR;\r
1563   }\r
1564   \r
1565 \r
1566   /* move the HCA to DESTROYING state, preserving fatal indicators */\r
1567   MOSAL_spinlock_dpc_lock(&hob_p->fatal_spl);\r
1568   if ((hob_p->thh_state & THH_STATE_DESTROYING) != 0) {\r
1569       MOSAL_spinlock_unlock(&hob_p->fatal_spl);\r
1570       MTL_ERROR1(MT_FLFMT("THH_hob_destroy:  already invoked"));\r
1571       return HH_EBUSY;\r
1572   }\r
1573   hob_p->thh_state &= THH_STATE_HAVE_ANY_FATAL;\r
1574   hob_p->thh_state |= THH_STATE_DESTROYING;\r
1575   MOSAL_spinlock_unlock(&hob_p->fatal_spl);\r
1576   \r
1577 #ifndef __DARWIN__ /* TODO: add support in darwin for fatal error handling */\r
1578 \r
1579   /* release the fatal signalling thread */\r
1580   hob_p->fatal_thread_obj.have_fatal = FALSE;\r
1581   MOSAL_syncobj_signal(&hob_p->fatal_thread_obj.fatal_err_sync);\r
1582   mosal_ret = MOSAL_syncobj_waiton(&(hob_p->fatal_thread_obj.stop_sync), 10000000);\r
1583   if (mosal_ret != MT_OK) {\r
1584       if (mosal_ret == MT_EINTR) {\r
1585           MTL_DEBUG1(MT_FLFMT("%s: Received OS interrupt while initializing fatal error thread (err = %d)"), \r
1586                      __func__,mosal_ret);\r
1587           fn_ret = HH_EINTR;\r
1588       } else {\r
1589           MTL_ERROR1(MT_FLFMT("%s: Timeout on destroying fatal error thread (err = %d)"), \r
1590                      __func__,mosal_ret);\r
1591           fn_ret = HH_ERR;\r
1592       }\r
1593   }\r
1594 \r
1595 #endif /* not defined __DARWIN__ */\r
1596 \r
1597   /* unregister the device from HH */\r
1598   ret = HH_rem_hca_dev(hca_hndl);\r
1599   if (ret != HH_OK) {\r
1600       MTL_ERROR1("THH_hob_destroy: Could not remove device 0x%p: unknown (%d)\n", hca_hndl, ret);\r
1601       fn_ret = HH_EINVAL_HCA_HNDL;\r
1602   }\r
1603 \r
1604   /* destroy objects created in hob_create, and issue SYS_DIS command to Tavor */\r
1605   ret = THH_ddrmm_destroy(hob_p->ddrmm);\r
1606   if (ret != HH_OK) {\r
1607       MTL_ERROR1("THH_hob_destroy: Could not destroy ddrmm object (err = %d)\n", ret);\r
1608       fn_ret = HH_ERR;\r
1609   }\r
1610   /* do SYS_DIS only if do not have a fatal error state */\r
1611   if ((hob_p->thh_state & THH_STATE_HAVE_ANY_FATAL) == 0) {\r
1612       have_fatal = FALSE;\r
1613       cmd_ret = THH_cmd_SYS_DIS(hob_p->cmd);\r
1614       if (cmd_ret != THH_CMD_STAT_OK) {\r
1615           MTL_ERROR1("THH_hob_destroy: SYS_DIS command failed (err = %d)\n", cmd_ret);\r
1616           if (cmd_ret == THH_CMD_STAT_EFATAL) {\r
1617               have_fatal = TRUE;\r
1618           }\r
1619           fn_ret = HH_ERR;\r
1620       }\r
1621    } else {\r
1622       /* halt the HCA if delayed-halt flag was set, in fatal case only, \r
1623        * to make sure that there is no PCI activity.  If fatal occurred during SYS_DIS above,\r
1624        * HCA was already closed, so don't need the "halt hca" operation\r
1625        */\r
1626       have_fatal = TRUE;\r
1627       if (hob_p->module_flags.fatal_delay_halt != 0) {\r
1628           MTL_DEBUG1(MT_FLFMT("%s: performing delayed halt-hca"), __func__);\r
1629           THH_hob_halt_hca(hob_p);\r
1630       }\r
1631    }\r
1632       \r
1633   ret = THH_cmd_destroy(hob_p->cmd);\r
1634   if (ret != HH_OK) {\r
1635       MTL_ERROR1("THH_hob_destroy: Could not destroy cmd object (err = %d)\n", ret);\r
1636       fn_ret = HH_ERR;\r
1637   }\r
1638 \r
1639   /* do PCI reset here if have a catastrophic error */\r
1640   if (have_fatal == TRUE) {\r
1641     /* perform sw reset */\r
1642       MTL_ERROR1(MT_FLFMT("%s: FATAL ERROR "), __func__);\r
1643 \r
1644 #if !defined(__DARWIN__) && !defined(__WIN__)\r
1645 #if 0 /*defined(__WIN__)*/\r
1646       if (hob_p->pci_hca_info.is_valid == TRUE) {\r
1647                 MOSAL_reset_card( hob_p->pci_hca_info.bus, hob_p->pci_hca_info.dev_func );\r
1648         }       \r
1649 #else   \r
1650       /* Do the Tavor RESET */\r
1651       va = MOSAL_io_remap(hob_p->hw_props.cr_base + 0xF0010, 4);\r
1652       if ( va ) {\r
1653           /* perform sw reset */\r
1654           MTL_ERROR1(MT_FLFMT("%s: PERFORMING SW RESET. pa="PHYS_ADDR_FMT" va="VIRT_ADDR_FMT),\r
1655                       __func__, hob_p->hw_props.cr_base + 0xF0010, va);\r
1656           MOSAL_MMAP_IO_WRITE_DWORD(((unsigned long)va),MOSAL_cpu_to_be32(0x00000001));\r
1657           /* sleep for one second, per PRM */\r
1658           MOSAL_delay_execution(1000000);\r
1659           MOSAL_io_unmap(va);\r
1660       }\r
1661 \r
1662       /* now, rewrite the PCI configuration */\r
1663       if (hob_p->pci_bridge_info.is_valid == TRUE) {\r
1664           write_pci_config(hob_p->pci_bridge_info.bus, hob_p->pci_bridge_info.dev_func,\r
1665                            hob_p->pci_bridge_info.config);\r
1666       }\r
1667       if (hob_p->pci_hca_info.is_valid == TRUE) {\r
1668           write_pci_config(hob_p->pci_hca_info.bus, hob_p->pci_hca_info.dev_func,\r
1669                            hob_p->pci_hca_info.config);\r
1670       }\r
1671 #endif /* defined __WIN__ */\r
1672 #endif /* not defined __DARWIN__ */\r
1673   }\r
1674 \r
1675   int_ret = VIP_delay_unlock_destroy(hob_p->delay_unlocks);\r
1676   if (int_ret != 0) {\r
1677       MTL_ERROR1("THH_hob_destroy: Could not destroy delay_unlocks (err = %d)\n", int_ret);\r
1678       fn_ret = HH_ERR;\r
1679   }\r
1680   \r
1681   if (hob_p->fw_error_buf_start_va != (MT_virt_addr_t)(MT_ulong_ptr_t) NULL)  {\r
1682      MOSAL_io_unmap(hob_p->fw_error_buf_start_va);\r
1683   }\r
1684 \r
1685   if (hob_p->fw_error_buf != NULL) {\r
1686       FREE(hob_p->fw_error_buf);\r
1687   }\r
1688 \r
1689   MOSAL_mutex_free(&(hob_p->mtx));\r
1690   /* Finally, free the THH object */\r
1691   FREE(hca_hndl->device);\r
1692   hca_hndl->device = NULL;\r
1693 \r
1694   return(fn_ret);\r
1695 }\r
1696 \r
1697 /******************************************************************************\r
1698  *  Function:     THH_hob_open_hca\r
1699  *\r
1700  *  Description:  This function opens the given HCA and initializes the HCA with \r
1701  *                given properties/ capabilities.  if prop_props_p is NULL a default \r
1702  *                HCA profile will be set up.\r
1703  *\r
1704  *  input:\r
1705  *                hca_hndl\r
1706  *                prop_props_p - Proprietary properties (Non IB)\r
1707  *  output: \r
1708  *                none\r
1709  *  returns:\r
1710  *                HH_OK\r
1711  *                HH_EINVAL\r
1712  *                HH_EBUSY\r
1713  *\r
1714  *  Comments:     If HCA is still open,THH_hob_close_hca() is \r
1715  *                invoked before freeing the THH_hob.\r
1716  *\r
1717  *                Returns HH_EINVAL_HCA_HNDL if any function called internally fails  \r
1718  *\r
1719  *****************************************************************************/\r
1720 HH_ret_t THH_hob_open_hca(HH_hca_hndl_t  hca_hndl, \r
1721                                  EVAPI_hca_profile_t  *prop_props_p,\r
1722                                  EVAPI_hca_profile_t  *sugg_profile_p)\r
1723 {\r
1724     MT_virt_addr_t            kar_addr;\r
1725     HH_ret_t               ret;\r
1726     THH_cmd_status_t       cmd_ret;\r
1727     THH_hca_props_t        local_hca_props;\r
1728     MT_phys_addr_t         *ddr_alloc_area;\r
1729     MT_size_t              *ddr_alloc_size;\r
1730     u_int32_t              i;\r
1731     THH_internal_mr_t      udav_internal_mr;\r
1732     MT_size_t              udav_entry_size = 0, udav_table_size = 0;\r
1733     MT_phys_addr_t            udav_phys_addr = 0;\r
1734     MT_virt_addr_t            udav_virt_addr = 0;\r
1735     VAPI_lkey_t            dummy_key;\r
1736     THH_eventp_res_t       event_res;\r
1737     u_int16_t              num_ports, last_port_initialized;\r
1738     THH_hob_t              thh_hob_p;\r
1739     VAPI_size_t            udav_vapi_size;\r
1740     THH_qpm_init_t         thh_qpm_init_params;\r
1741     MT_bool                have_fatal = FALSE;\r
1742 \r
1743     MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
1744     MTL_DEBUG4("Entering THH_hob_open_hca\n");\r
1745     if (MOSAL_get_exec_ctx() != MOSAL_IN_TASK) {\r
1746         MTL_ERROR1("THH_hob_open_hca: NOT IN TASK CONTEXT)\n");\r
1747         return HH_ERR;\r
1748     }\r
1749 \r
1750 \r
1751     if (hca_hndl == NULL) {\r
1752         MTL_ERROR1("THH_hob_open_hca : ERROR : Invalid HCA handle\n");\r
1753         return HH_EINVAL_HCA_HNDL;\r
1754     }\r
1755     thh_hob_p = THHOBP(hca_hndl);\r
1756 \r
1757     if (thh_hob_p == NULL) {\r
1758         MTL_ERROR1("THH_hob_open_hca: ERROR : No device registered\n");\r
1759         return HH_EAGAIN;\r
1760     }\r
1761   /* Get user profile if available -- if not, use default proportionally to resources. */\r
1762 \r
1763   /* DDR parameters.  Get from default profile.  For each one, check that does not exceed */\r
1764   /* The maximum resource value supportable by the installed card. */\r
1765 \r
1766 /*\r
1767    Objects:\r
1768            cmd;     -- already exists\r
1769            ddrmm;   -- already exists\r
1770            uldm;    -- uar, pd:  log2_max_uar, log2_max_pg_sz, max_pd\r
1771            mrwm;    -- log2_mpt_sz (log2 of number of entries in MPT)\r
1772                        log2_mtt_sz (Log2 of number of entries in the MTT) \r
1773                        max_mem_reg (Maximum memory regions to be allocated in the MPT for external registration only)\r
1774                        max_mem_reg_internal (Maximum memory regions to be alloc in the MPT for internal use only (WQEs and CQEs buffers) )\r
1775                        max_mem_win (Maximum memory windows to be allocated in the MPT)\r
1776            cqm;     -- log2_max_cq,\r
1777            eecm;    -- \r
1778            qpm;     -- log2_max_qp,\r
1779                        privileged_ud_av (boolean)\r
1780            udavm;   -- max_av\r
1781            mcgm;    -- num mcg's: IBTA min = 512, 8 QPs/group\r
1782            eventp;  -- 64 event queues\r
1783            kar;     -- UAR 0 (no extra resources needed)\r
1784         \r
1785 */\r
1786 \r
1787     /* Test if have fatal error, and move thh_state to "opening" */\r
1788     MOSAL_spinlock_dpc_lock(&thh_hob_p->fatal_spl);\r
1789     if ((thh_hob_p->thh_state & THH_STATE_HAVE_ANY_FATAL) != 0) {\r
1790         /* already in FATAL state */\r
1791         MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
1792         MTL_DEBUG4(MT_FLFMT("%s: already in FATAL state"), __func__);  \r
1793         MT_RETURN(HH_EFATAL);\r
1794     } else if (thh_hob_p->thh_state != THH_STATE_CLOSED) {\r
1795         MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
1796         MTL_ERROR1(MT_FLFMT("THH_hob_open_hca: ERROR : Device not closed. state = 0x%x"),thh_hob_p->thh_state );\r
1797         MT_RETURN(HH_EBUSY);\r
1798     }\r
1799     thh_hob_p->thh_state = THH_STATE_OPENING;\r
1800     MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
1801     \r
1802     /* get the MUTEX */\r
1803     if (MOSAL_mutex_acq(&(thh_hob_p->mtx), TRUE) != MT_OK) {\r
1804         MTL_ERROR1(MT_FLFMT("THH_hob_open_hca: received signal. returning"));\r
1805         ret = HH_EINTR;\r
1806         goto post_state_change_error;\r
1807     }\r
1808     if (hca_hndl->status == HH_HCA_STATUS_OPENED) {\r
1809         MTL_ERROR1("THH_hob_open_hca: ERROR : Device already open\n");\r
1810         ret = HH_EBUSY;\r
1811         goto post_mutex_acquire_err;\r
1812     }\r
1813 \r
1814     if (prop_props_p != NULL) {\r
1815         THH_PRINT_USR_PROFILE(prop_props_p);\r
1816     }\r
1817     ret = THH_calculate_profile(thh_hob_p, prop_props_p, sugg_profile_p);\r
1818     if (ret != HH_OK) {\r
1819       MTL_ERROR1(MT_FLFMT("THH_hob_open_hca: could not create internal profile (%d)"), ret);\r
1820       if (sugg_profile_p != NULL) {\r
1821           THH_PRINT_USR_PROFILE(sugg_profile_p);\r
1822       }\r
1823       //ret = HH_ERR;\r
1824       goto post_mutex_acquire_err;\r
1825     }\r
1826     if (sugg_profile_p != NULL) {\r
1827         THH_PRINT_USR_PROFILE(sugg_profile_p);\r
1828     }\r
1829 \r
1830     /* check profile against QUERY_DEV_LIMS data*/\r
1831     ret = THH_check_profile(thh_hob_p);\r
1832     if (ret != HH_OK) {\r
1833       MTL_ERROR1("THH_hob_open_hca: Profile check failed (%d)\n", ret);\r
1834       ret = HH_ERR;\r
1835       goto post_mutex_acquire_err;\r
1836     }\r
1837 \r
1838     /*  Do ddrmm allocation here, because we need the allocated MCG base address */\r
1839     /*  for the INIT_HCA command following the centralized DDR allocation */\r
1840     calculate_ddr_alloc_vec(thh_hob_p, &(thh_hob_p->profile), &(thh_hob_p->ddr_alloc_size_vec));\r
1841 \r
1842     /* Allocate all required DDR areas */\r
1843     ret = THH_ddrmm_alloc_sz_aligned(thh_hob_p->ddrmm, \r
1844                              thh_hob_p->profile.ddr_alloc_vec_size,      /*number of chunks */\r
1845                              (MT_size_t *) &(thh_hob_p->ddr_alloc_size_vec), /* IN  */\r
1846                              (MT_phys_addr_t *)&(thh_hob_p->ddr_alloc_base_addrs_vec) );  /* OUT */\r
1847     if (ret != HH_OK) {\r
1848         MTL_ERROR1("THH_hob_open_hca: could not allocate required areas in DDR (%s)\n", HH_strerror_sym(ret));\r
1849         ret = HH_ERR;\r
1850         goto post_mutex_acquire_err;\r
1851     }\r
1852     \r
1853     /* call cmd interface to initialize its mailboxes in DDR */\r
1854     ret = THH_cmd_assign_ddrmm(thh_hob_p->cmd, thh_hob_p->ddrmm);\r
1855     if (ret != HH_OK) {\r
1856       MTL_ERROR1("THH_hob_open_hca: Failed THH_cmd_assign_ddrmm (%s)\n",HH_strerror_sym(ret)); \r
1857       goto cmd_assign_ddrmm_err;\r
1858     }\r
1859     \r
1860     /* set up parameters for INIT HCA */\r
1861     memset(&local_hca_props, 0, sizeof(THH_hca_props_t));\r
1862 #ifdef MT_LITTLE_ENDIAN\r
1863     local_hca_props.he = TAVOR_IF_HOST_LTLENDIAN;\r
1864 #else\r
1865     local_hca_props.he = TAVOR_IF_HOST_BIGENDIAN;\r
1866 #endif\r
1867     local_hca_props.re = FALSE;   /* not a router */\r
1868     local_hca_props.udp = TRUE;   /* check port in UD AV */ \r
1869     local_hca_props.ud =  thh_hob_p->profile.use_priv_udav; \r
1870     \r
1871     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr = \r
1872         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.cqc_base_addr,thh_hob_p->ddr_props.dh,\r
1873                           thh_hob_p->ddr_props.ddr_start_adr);\r
1874     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.eec_base_addr = \r
1875         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.eec_base_addr,thh_hob_p->ddr_props.dh,\r
1876                           thh_hob_p->ddr_props.ddr_start_adr);\r
1877     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr = \r
1878         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.eqc_base_addr,thh_hob_p->ddr_props.dh,\r
1879                           thh_hob_p->ddr_props.ddr_start_adr);\r
1880     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr = \r
1881         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.qpc_base_addr,thh_hob_p->ddr_props.dh,\r
1882                           thh_hob_p->ddr_props.ddr_start_adr);\r
1883     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.rdb_base_addr = \r
1884         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.rdb_base_addr,thh_hob_p->ddr_props.dh,\r
1885                           thh_hob_p->ddr_props.ddr_start_adr);\r
1886     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.log_num_of_cq = \r
1887       (u_int8_t)thh_hob_p->profile.log2_max_cqs;\r
1888     // local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.log_num_of_ee = thh_hob_p->profile.log2_max_eecs;\r
1889     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.log_num_of_ee = 0;\r
1890     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.log_num_eq = thh_hob_p->profile.log2_max_eqs;\r
1891     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.log_num_of_qp = (u_int8_t)thh_hob_p->profile.log2_max_qps;\r
1892     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.eqpc_base_addr = \r
1893         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.eqpc_base_addr,thh_hob_p->ddr_props.dh,\r
1894                           thh_hob_p->ddr_props.ddr_start_adr);\r
1895     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.log_num_of_srq = (u_int8_t)thh_hob_p->profile.log2_max_srqs;\r
1896     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr = \r
1897         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.srqc_base_addr,thh_hob_p->ddr_props.dh,\r
1898                           thh_hob_p->ddr_props.ddr_start_adr);\r
1899     local_hca_props.qpc_eec_cqc_eqc_rdb_parameters.eeec_base_addr = \r
1900         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.eeec_base_addr,thh_hob_p->ddr_props.dh,\r
1901                           thh_hob_p->ddr_props.ddr_start_adr);\r
1902     \r
1903     local_hca_props.udavtable_memory_parameters.l_key = THH_UDAVM_PRIV_RESERVED_LKEY;\r
1904     local_hca_props.udavtable_memory_parameters.pd    = THH_RESERVED_PD;\r
1905     local_hca_props.udavtable_memory_parameters.xlation_en = TRUE;\r
1906     \r
1907     local_hca_props.tpt_parameters.log_mpt_sz = (u_int8_t)thh_hob_p->profile.log2_max_mpt_entries;\r
1908     local_hca_props.tpt_parameters.mpt_base_adr = \r
1909         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.mpt_base_addr,thh_hob_p->ddr_props.dh,\r
1910                           thh_hob_p->ddr_props.ddr_start_adr);\r
1911     local_hca_props.tpt_parameters.mtt_base_addr = \r
1912         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.mtt_base_addr,thh_hob_p->ddr_props.dh,\r
1913                           thh_hob_p->ddr_props.ddr_start_adr);\r
1914     local_hca_props.tpt_parameters.pfto = 0;   /* TBD -- not yet supported. Page Fault RNR Timeout */\r
1915     local_hca_props.tpt_parameters.mtt_segment_size = (u_int8_t)((thh_hob_p->profile.log2_mtt_entries_per_seg + THH_DDR_LOG2_MTT_ENTRY_SIZE)\r
1916                                                             - THH_DDR_LOG2_MIN_MTT_SEG_SIZE);\r
1917     \r
1918     local_hca_props.uar_parameters.uar_base_addr = thh_hob_p->hw_props.uar_base;\r
1919     local_hca_props.uar_parameters.uar_page_sz   = thh_hob_p->profile.log2_uar_pg_size - 12;\r
1920     local_hca_props.uar_parameters.uar_scratch_base_addr = \r
1921         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.uar_scratch_base_addr,thh_hob_p->ddr_props.dh,\r
1922                           thh_hob_p->ddr_props.ddr_start_adr);\r
1923     \r
1924     local_hca_props.multicast_parameters.log_mc_table_sz = (u_int8_t)thh_hob_p->profile.log2_max_mcgs;\r
1925     local_hca_props.multicast_parameters.mc_base_addr    = \r
1926         GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.mcg_base_addr,thh_hob_p->ddr_props.dh,\r
1927                           thh_hob_p->ddr_props.ddr_start_adr);\r
1928     local_hca_props.multicast_parameters.mc_hash_fn      = 0;\r
1929     local_hca_props.multicast_parameters.log_mc_table_entry_sz = (u_int16_t)(thh_hob_p->profile.log2_mcg_entry_size);\r
1930     local_hca_props.multicast_parameters.mc_table_hash_sz = 1 << (thh_hob_p->profile.log2_mcg_hash_size);\r
1931 \r
1932   /* INIT_HCA command */\r
1933     cmd_ret = THH_cmd_INIT_HCA(thh_hob_p->cmd,&local_hca_props);\r
1934     if (cmd_ret != THH_CMD_STAT_OK) {\r
1935         MTL_ERROR1("THH_hob_open_hca: CMD_error in THH_cmd_INIT_HCA (%d)\n", cmd_ret);\r
1936         ret = HH_EAGAIN;\r
1937         goto init_hca_err;\r
1938     }\r
1939 \r
1940   /* Now, query HCA to get actual allocated parameters */\r
1941     cmd_ret = THH_cmd_QUERY_HCA(thh_hob_p->cmd, &(thh_hob_p->hca_props));\r
1942     if (cmd_ret != THH_CMD_STAT_OK) {\r
1943         MTL_ERROR1("THH_hob_open_hca: CMD_error in THH_cmd_QUERY_HCA (%d)\n", cmd_ret);\r
1944         ret = HH_EAGAIN;\r
1945         goto query_hca_err;\r
1946     }\r
1947     \r
1948     /* create uldm */\r
1949     ret = THH_uldm_create(thh_hob_p, thh_hob_p->hw_props.uar_base, (u_int8_t) thh_hob_p->profile.log2_max_uar,\r
1950                            (u_int8_t) thh_hob_p->profile.log2_uar_pg_size, \r
1951                            (u_int32_t) (thh_hob_p->profile.max_num_pds + thh_hob_p->dev_lims.num_rsvd_pds + THH_NUM_RSVD_PD),\r
1952                            &(thh_hob_p->uldm));                      if (ret != HH_OK) {\r
1953         MTL_ERROR1("THH_hob_open_hca: could not create uldm (%d)\n", ret);\r
1954         goto uldm_create_err;\r
1955     }\r
1956 \r
1957     thh_hob_p->mrwm_props.mtt_base = GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.mtt_base_addr,thh_hob_p->ddr_props.dh,\r
1958                           thh_hob_p->ddr_props.ddr_start_adr);\r
1959     thh_hob_p->mrwm_props.mpt_base = GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.mpt_base_addr,thh_hob_p->ddr_props.dh,\r
1960                           thh_hob_p->ddr_props.ddr_start_adr);\r
1961     thh_hob_p->mrwm_props.log2_mpt_sz = (u_int8_t)thh_hob_p->profile.log2_max_mpt_entries;\r
1962     thh_hob_p->mrwm_props.log2_mtt_sz = (u_int8_t)thh_hob_p->profile.log2_max_mtt_entries;\r
1963     thh_hob_p->mrwm_props.log2_mtt_seg_sz = (u_int8_t)thh_hob_p->profile.log2_mtt_entries_per_seg;\r
1964     thh_hob_p->mrwm_props.max_mem_reg = thh_hob_p->profile.num_external_mem_regions;\r
1965     thh_hob_p->mrwm_props.max_mem_reg_internal = thh_hob_p->profile.max_num_qps + thh_hob_p->profile.max_num_cqs;\r
1966     thh_hob_p->mrwm_props.max_mem_win          = thh_hob_p->profile.num_mem_windows;\r
1967     thh_hob_p->mrwm_props.log2_max_mtt_segs    = (u_int8_t)(thh_hob_p->profile.log2_max_mtt_entries - \r
1968                                                            thh_hob_p->mrwm_props.log2_mtt_seg_sz);\r
1969     thh_hob_p->mrwm_props.log2_rsvd_mpts       = thh_hob_p->dev_lims.log2_rsvd_mrws;\r
1970     thh_hob_p->mrwm_props.log2_rsvd_mtt_segs   = thh_hob_p->dev_lims.log2_rsvd_mtts;\r
1971 \r
1972     ret = THH_mrwm_create(thh_hob_p, &(thh_hob_p->mrwm_props), &(thh_hob_p->mrwm));\r
1973     if (ret != HH_OK) {\r
1974         MTL_ERROR1("THH_hob_open_hca: could not create mrwm (%d)\n", ret);\r
1975         goto mrwm_create_err;\r
1976     }\r
1977     \r
1978     /* Create objects */\r
1979     ret = THH_cqm_create(thh_hob_p, (u_int8_t) thh_hob_p->profile.log2_max_cqs,\r
1980                          thh_hob_p->dev_lims.log2_rsvd_cqs, &(thh_hob_p->cqm));\r
1981     if (ret != HH_OK) {\r
1982         MTL_ERROR1("THH_hob_open_hca: could not create cqm (%d)\n", ret);\r
1983         goto cqm_create_err;\r
1984     }\r
1985     \r
1986     /* create qpm object here */\r
1987 \r
1988     /* initialize INIT_IB parameters here for possible use by qpm */\r
1989     num_ports = thh_hob_p->dev_lims.num_ports;\r
1990 \r
1991     thh_hob_p->init_ib_props = (THH_port_init_props_t *) MALLOC(num_ports * sizeof(THH_port_init_props_t));\r
1992     if (!(thh_hob_p->init_ib_props)) {\r
1993         MTL_ERROR1( "THH_hob_open_hca: ERROR : cannot allocate memory for port init props)\n");\r
1994         goto init_ib_props_malloc_err;\r
1995     }\r
1996     for (i = 1; i <= num_ports; i++) {\r
1997         /* redundant for now. However, leaving option for setting different properties per port */\r
1998         thh_hob_p->init_ib_props[i-1].e = TRUE;\r
1999         thh_hob_p->init_ib_props[i-1].g0 = FALSE;\r
2000         thh_hob_p->init_ib_props[i-1].max_gid = (1 << (thh_hob_p->dev_lims.log_max_gid));\r
2001         thh_hob_p->init_ib_props[i-1].mtu_cap = thh_hob_p->dev_lims.max_mtu;\r
2002         thh_hob_p->init_ib_props[i-1].max_pkey = (1 << (thh_hob_p->dev_lims.log_max_pkey));\r
2003         thh_hob_p->init_ib_props[i-1].vl_cap   = thh_hob_p->dev_lims.max_vl;\r
2004         thh_hob_p->init_ib_props[i-1].port_width_cap = thh_hob_p->dev_lims.max_port_width;\r
2005     }\r
2006     \r
2007     memset(&(thh_qpm_init_params), 0, sizeof(thh_qpm_init_params));\r
2008     thh_qpm_init_params.rdb_base_index = \r
2009         /* 32 low-order bits, right-shifted by log of size of rdb entry */\r
2010       (u_int32_t)(((u_int64_t)(GET_DDR_ADDR(thh_hob_p->ddr_alloc_base_addrs_vec.rdb_base_addr,thh_hob_p->ddr_props.dh,\r
2011                           thh_hob_p->ddr_props.ddr_start_adr))) & (u_int64_t)0xFFFFFFFF ) \r
2012                                   >> THH_DDR_LOG2_RDB_ENTRY_SIZE;\r
2013     thh_qpm_init_params.log2_max_qp = (u_int8_t) thh_hob_p->profile.log2_max_qps;\r
2014     thh_qpm_init_params.log2_max_outs_rdma_atom = thh_hob_p->profile.log2_inflight_rdma_per_qp;\r
2015     thh_qpm_init_params.log2_max_outs_dst_rd_atom = thh_hob_p->dev_lims.log_max_ra_req_qp;\r
2016     thh_qpm_init_params.n_ports = (u_int8_t)num_ports;\r
2017     thh_qpm_init_params.port_props = \r
2018         (thh_hob_p->module_flags.legacy_sqp == TRUE ? NULL : thh_hob_p->init_ib_props );\r
2019     thh_qpm_init_params.log2_rsvd_qps = thh_hob_p->dev_lims.log2_rsvd_qps;\r
2020     \r
2021     ret = THH_qpm_create(thh_hob_p, &(thh_qpm_init_params), &(thh_hob_p->qpm));\r
2022     if (ret != HH_OK) {\r
2023         MTL_ERROR1("THH_hob_open_hca: could not create qpm %s(%d)\n", HH_strerror_sym(ret), ret);\r
2024         goto qpm_create_err;\r
2025     }\r
2026 \r
2027     if (thh_hob_p->dev_lims.srq) {\r
2028       ret= THH_srqm_create(thh_hob_p, \r
2029                            (u_int8_t)thh_hob_p->profile.log2_max_srqs, thh_hob_p->dev_lims.log2_rsvd_srqs,\r
2030                            &(thh_hob_p->srqm));\r
2031       if (ret != HH_OK) {\r
2032           MTL_ERROR1("THH_hob_open_hca: could not create srqm - %s(%d)\n", HH_strerror_sym(ret), ret);\r
2033           goto srqm_create_err;\r
2034       }\r
2035     } else {\r
2036       thh_hob_p->srqm= (THH_srqm_t)THH_INVALID_HNDL; /* SRQs are not supported */\r
2037     }\r
2038 \r
2039     /* CREATE ALL CONTAINED OBJECTS  */\r
2040     \r
2041     /* create UDAVm if privileged UDAV is set */\r
2042     if (thh_hob_p->profile.use_priv_udav) {\r
2043         \r
2044         thh_hob_p->udavm_use_priv = TRUE;\r
2045         \r
2046         /* create the table in DDR memory */\r
2047         udav_entry_size = (unsigned)(sizeof(struct tavorprm_ud_address_vector_st) / 8);\r
2048         udav_table_size = thh_hob_p->profile.max_priv_udavs * udav_entry_size;\r
2049 \r
2050         ret = THH_ddrmm_alloc(thh_hob_p->ddrmm, udav_table_size, ceil_log2(udav_entry_size),\r
2051                           &udav_phys_addr);\r
2052         if (ret != HH_OK) {\r
2053             MTL_ERROR1("THH_hob_open_hca: could not allocate protected udavm area in DDR(err = %d)\n", ret);\r
2054             goto udavm_ddrmm_alloc_err;\r
2055         }\r
2056         udav_virt_addr = (MT_virt_addr_t) MOSAL_map_phys_addr( udav_phys_addr , udav_table_size,\r
2057                                  MOSAL_MEM_FLAGS_NO_CACHE | MOSAL_MEM_FLAGS_PERM_WRITE | MOSAL_MEM_FLAGS_PERM_READ , \r
2058                                  MOSAL_get_kernel_prot_ctx());\r
2059         if (udav_virt_addr == (MT_virt_addr_t) NULL) {\r
2060             MTL_ERROR1("THH_hob_open_hca: could not map physical address " PHYS_ADDR_FMT " to virtual\n", \r
2061                        udav_phys_addr);\r
2062             goto udavm_mosal_map_err;\r
2063         }\r
2064 \r
2065         memset(&udav_internal_mr, 0, sizeof(udav_internal_mr));\r
2066         udav_internal_mr.force_memkey = TRUE;\r
2067         udav_internal_mr.memkey       = THH_UDAVM_PRIV_RESERVED_LKEY;\r
2068         udav_internal_mr.pd           = THH_RESERVED_PD;\r
2069         udav_internal_mr.size         = udav_table_size;\r
2070         udav_internal_mr.start        = udav_virt_addr;\r
2071         udav_internal_mr.vm_ctx       = MOSAL_get_kernel_prot_ctx();\r
2072         if (udav_phys_addr) {\r
2073             VAPI_phy_addr_t udav_phy =  udav_phys_addr;\r
2074             udav_internal_mr.num_bufs = 1;      /*  != 0   iff   physical buffesrs supplied */\r
2075             udav_internal_mr.phys_buf_lst = &udav_phy;  /* size = num_bufs */\r
2076             udav_vapi_size  = (VAPI_size_t) udav_table_size;\r
2077             udav_internal_mr.buf_sz_lst = &udav_vapi_size;    /* [num_bufs], corresponds to phys_buf_lst */\r
2078         }\r
2079 \r
2080         thh_hob_p->udavm_table_size = udav_table_size;\r
2081         thh_hob_p->udavm_table      = udav_virt_addr;\r
2082         thh_hob_p->udavm_table_ddr  = udav_phys_addr;\r
2083 \r
2084         ret = THH_mrwm_register_internal(thh_hob_p->mrwm, &udav_internal_mr, &dummy_key);\r
2085         if (ret != HH_OK) {\r
2086             MTL_ERROR1("THH_hob_open_hca: could not register created udavm table (%d)\n", ret);\r
2087             goto udavm_table_register_err;\r
2088         }\r
2089         thh_hob_p->udavm_lkey = dummy_key;\r
2090 \r
2091         ret = THH_udavm_create(&(thh_hob_p->version_info), \r
2092                                dummy_key,\r
2093                                udav_virt_addr,\r
2094                                udav_table_size,\r
2095                                TRUE,\r
2096                                &(thh_hob_p->udavm),\r
2097                                &(thh_hob_p->av_ddr_base),\r
2098                                &(thh_hob_p->av_host_base));\r
2099         if (ret != HH_OK) {\r
2100             MTL_ERROR1("THH_hob_open_hca: could not create udavm (%d)\n", ret);\r
2101             goto udavm_create_err;\r
2102         }\r
2103 \r
2104     } else {\r
2105         thh_hob_p->udavm_use_priv = FALSE;\r
2106     }\r
2107 \r
2108     /* CREATE KAR (kernel UAR), using UAR 1 for this purpose. */\r
2109     kar_addr = (MT_virt_addr_t) MOSAL_map_phys_addr( thh_hob_p->hw_props.uar_base + ((MT_phys_addr_t)1 << thh_hob_p->profile.log2_uar_pg_size),\r
2110                                                  ((MT_size_t)1 << thh_hob_p->profile.log2_uar_pg_size),\r
2111                                                  MOSAL_MEM_FLAGS_NO_CACHE | MOSAL_MEM_FLAGS_PERM_WRITE, \r
2112                                                  MOSAL_get_kernel_prot_ctx());\r
2113     if (kar_addr == (MT_virt_addr_t) NULL) {\r
2114 #ifndef __DARWIN__\r
2115         MTL_ERROR1("THH_hob_open_hca: MOSAL_map_phys_addr failed for prot ctx %d, addr " PHYS_ADDR_FMT ", size %d\n",\r
2116                    MOSAL_get_kernel_prot_ctx(),\r
2117                    (MT_phys_addr_t) (thh_hob_p->hw_props.uar_base),\r
2118                    (1 << thh_hob_p->profile.log2_uar_pg_size));\r
2119 #else\r
2120         MTL_ERROR1("THH_hob_open_hca: MOSAL_map_phys_addr failed: addr " PHYS_ADDR_FMT ", size %d\n",\r
2121                    (MT_phys_addr_t) (thh_hob_p->hw_props.uar_base),\r
2122                    (1 << thh_hob_p->profile.log2_uar_pg_size));\r
2123 #endif\r
2124         goto kar_map_phys_addr_err;\r
2125     }\r
2126     thh_hob_p->kar_addr = kar_addr;\r
2127     MTL_DEBUG4("%s: MOSAL_map_phys_addr FOR KAR = " VIRT_ADDR_FMT "\n", __func__, kar_addr);\r
2128     ret = THH_uar_create(&(thh_hob_p->version_info), 1/* Kernel UAR page index */, \r
2129                          (void *) kar_addr, &(thh_hob_p->kar));\r
2130     if (ret != HH_OK) {\r
2131         MTL_ERROR1("THH_hob_open_hca: could not create KAR (%d)\n", ret);\r
2132         thh_hob_p->kar_addr = (MT_virt_addr_t) 0;\r
2133         goto kar_create_err;\r
2134     }\r
2135     \r
2136     //sharon: wrote fixed numbers till fw bug fixed\r
2137     if (THH_DEV_LIM_MCG_ENABLED(thh_hob_p)) {\r
2138         ret = THH_mcgm_create(thh_hob_p, \r
2139                           ((VAPI_size_t)1 << thh_hob_p->hca_props.multicast_parameters.log_mc_table_sz),\r
2140                           /*thh_hob_p->hca_props.multicast_parameters.mc_table_hash_sz*/\r
2141                           (VAPI_size_t)1 << (thh_hob_p->profile.log2_mcg_hash_size),\r
2142                           (u_int16_t)thh_hob_p->profile.qps_per_mcg,           \r
2143                            &(thh_hob_p->mcgm) );\r
2144         if (ret != HH_OK) {\r
2145             MTL_ERROR1("THH_hob_open_hca: could not create mcgm (%d)\n", ret);\r
2146             thh_hob_p->hca_capabilities.max_mcast_grp_num = 0;            \r
2147             thh_hob_p->hca_capabilities.max_mcast_qp_attach_num = 0;      \r
2148             thh_hob_p->hca_capabilities.max_total_mcast_qp_attach_num = 0;\r
2149             thh_hob_p->mcgm = (THH_mcgm_t)THH_INVALID_HNDL;\r
2150         }\r
2151     }\r
2152 \r
2153     /* CREATE EVENTP*/\r
2154     event_res.cr_base = thh_hob_p->hw_props.cr_base;\r
2155     event_res.intr_clr_bit = thh_hob_p->adapter_props.intapin;\r
2156     event_res.irq = thh_hob_p->hw_props.interrupt_props.irq;\r
2157     event_res.is_srq_enable = thh_hob_p->dev_lims.srq;\r
2158 \r
2159     ret = THH_eventp_create (thh_hob_p, &event_res, thh_hob_p->kar, &(thh_hob_p->eventp));\r
2160     if (ret != HH_OK) {\r
2161         MTL_ERROR1("THH_hob_open_hca: could not create eventp (%d)\n", ret);\r
2162         goto eventp_create_err;\r
2163     }\r
2164 \r
2165     /* CREATE THE VARIOUS EVENT QUEUES (eventp object operations) */\r
2166     /* register dummy completion and async event handlers */\r
2167     /* set max outstanding EQEs to max number of CQs configured */\r
2168 \r
2169     ret = THH_eventp_setup_ib_eq(thh_hob_p->eventp, \r
2170                                  &THH_dummy_async_event,\r
2171                                  NULL, \r
2172                                  (MT_size_t)(thh_hob_p->module_flags.async_eq_size == 0 ? \r
2173                                              THH_MAX_ASYNC_EQ_SIZE :\r
2174                                              thh_hob_p->module_flags.async_eq_size ), \r
2175                                  &(thh_hob_p->ib_eq));\r
2176     if (ret != HH_OK) {\r
2177         MTL_ERROR1(MT_FLFMT("THH_hob_open_hca: ERROR : cannot set up async event queue for size "SIZE_T_DFMT" (ret=%d)"), \r
2178                    (MT_size_t)(thh_hob_p->module_flags.async_eq_size == 0 ? \r
2179                                THH_MAX_ASYNC_EQ_SIZE :thh_hob_p->module_flags.async_eq_size ),ret);\r
2180         goto eventp_async_err;\r
2181     }\r
2182 \r
2183     ret = THH_eventp_setup_comp_eq(thh_hob_p->eventp, \r
2184                                    &THH_dummy_comp_event , \r
2185                                    NULL,\r
2186                                    (MT_size_t)(1 <<(thh_hob_p->profile.log2_max_cqs)) - \r
2187                                           (MT_size_t)(1ul << (thh_hob_p->dev_lims.log2_rsvd_cqs)), \r
2188                                    &(thh_hob_p->compl_eq));\r
2189     if (ret != HH_OK) {\r
2190         MTL_ERROR1( "THH_hob_open_hca: ERROR : cannot set up completion event queue (%d)\n", ret);\r
2191         goto eventp_compl_err;\r
2192     }\r
2193 \r
2194 \r
2195     /* PERFORM INIT_IB only for legacy SQPs.  Use max values obtained from QUERY_DEV_LIMS */\r
2196 \r
2197     last_port_initialized = 0;\r
2198     \r
2199         if (thh_hob_p->module_flags.legacy_sqp == TRUE) { \r
2200                 for (i = 1; i <= num_ports; i++) {\r
2201                         MTL_TRACE2("THH_hob_open_hca: INIT_IB COMMAND\n");\r
2202                         cmd_ret = THH_cmd_INIT_IB(thh_hob_p->cmd, (IB_port_t) i, &(thh_hob_p->init_ib_props[i-1]));\r
2203                         if (cmd_ret != THH_CMD_STAT_OK) {\r
2204                                 MTL_ERROR1("THH_hob_open_hca: CMD_error in THH_cmd_INIT_IB (%d) for port %d\n", cmd_ret, i);\r
2205                 if (cmd_ret ==THH_CMD_STAT_EFATAL) {\r
2206                     ret = HH_EFATAL;\r
2207                 } else {\r
2208                     ret = HH_EAGAIN;\r
2209                 }\r
2210                                 goto init_ib_err;\r
2211                         }\r
2212 \r
2213                         else {\r
2214                                 MTL_TRACE2("THH_hob_open_hca: INIT_IB COMMAND completed successfuly\n");\r
2215                         }\r
2216                         last_port_initialized++;\r
2217                 }\r
2218         }\r
2219 \r
2220 \r
2221         /* This must be called after INIT_IB, since it uses the max_pkey value stored in that struct */\r
2222     MTL_TRACE2("THH_hob_open_hca:  Before THH_hob_query_struct_init\n");\r
2223     ret = THH_hob_query_struct_init(thh_hob_p, \r
2224                               ((prop_props_p == NULL)? FALSE : TRUE),\r
2225                               &(thh_hob_p->hca_capabilities));\r
2226     if (ret != HH_OK) {\r
2227         MTL_ERROR1( "THH_hob_query_struct_init: ERROR : cannot initialize data for query_hca (%d)\n", ret);\r
2228         goto query_struct_init_err;\r
2229     }\r
2230 \r
2231     /* TK - start events after all CMDs are done */\r
2232 \r
2233 #if (! defined __DARWIN__) || (defined DARWIN_WITH_INTERRUPTS_CMDIF)\r
2234     ret = THH_eventp_setup_cmd_eq(thh_hob_p->eventp, CMD_EQ_SIZE /* to overcome a FW bug */\r
2235                                   /*(1 << (thh_hob_p->fw_props.log_max_outstanding_cmd))*/ );\r
2236     if (ret != HH_OK) {\r
2237         MTL_ERROR1( "THH_hob_open_hca: ERROR : cannot set up command event queue (%d)\n", ret);\r
2238         goto eventp_cmd_err;\r
2239     }\r
2240 #endif    \r
2241 \r
2242     /* move the HCA to running state if had no fatal. If had fatal, return HH_EFATAL */\r
2243     MOSAL_spinlock_dpc_lock(&thh_hob_p->fatal_spl);\r
2244     if ((thh_hob_p->thh_state & THH_STATE_HAVE_ANY_FATAL) != 0) {\r
2245         /* already in FATAL state */\r
2246         MTL_DEBUG4(MT_FLFMT("%s: already in FATAL state"), __func__);  \r
2247         MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
2248         ret = HH_EFATAL;\r
2249         goto fatal_err_at_end;\r
2250     }\r
2251     thh_hob_p->thh_state = THH_STATE_RUNNING;\r
2252     MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
2253     \r
2254     MTL_TRACE2("THH_hob_open_hca: device name %s\n", hca_hndl->dev_desc);\r
2255     hca_hndl->status   =   HH_HCA_STATUS_OPENED;\r
2256     \r
2257     /* free the mutex */\r
2258     MOSAL_mutex_rel(&(thh_hob_p->mtx));\r
2259 \r
2260     return(HH_OK);\r
2261 \r
2262 fatal_err_at_end:\r
2263 eventp_cmd_err:\r
2264 query_struct_init_err:\r
2265 init_ib_err:\r
2266     /* see if need to close IB for some ports. Do not close ports on fatal error*/\r
2267     MOSAL_spinlock_dpc_lock(&thh_hob_p->fatal_spl);\r
2268     /*test fatal again, here -- may have gotten FATAL before end of OPEN_hca process */\r
2269     if ((thh_hob_p->thh_state & THH_STATE_HAVE_ANY_FATAL) != 0) {\r
2270         /* got FATAL during OPEN_HCA */\r
2271         MTL_DEBUG4(MT_FLFMT("THH_hob_open_hca: In FATAL state")); \r
2272         have_fatal = TRUE;\r
2273     } else {\r
2274         have_fatal = FALSE;\r
2275     }\r
2276     MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
2277     if ((last_port_initialized) && (have_fatal == FALSE)) {\r
2278         for (i = 1; i <= last_port_initialized; i++) {\r
2279             MTL_DEBUG4(MT_FLFMT("THH_hob_open_hca: closing IB port %d"), i); \r
2280             THH_cmd_CLOSE_IB(thh_hob_p->cmd, (IB_port_t) i);\r
2281         }\r
2282     }\r
2283     thh_hob_p->compl_eq = THH_INVALID_EQN;\r
2284 \r
2285 eventp_compl_err:\r
2286     thh_hob_p->ib_eq = THH_INVALID_EQN;\r
2287 \r
2288 eventp_async_err:\r
2289     THH_eventp_destroy(thh_hob_p->eventp);\r
2290 \r
2291 eventp_create_err:\r
2292     if (thh_hob_p->mcgm != (THH_mcgm_t)THH_INVALID_HNDL) {\r
2293         THH_mcgm_destroy(thh_hob_p->mcgm );\r
2294         thh_hob_p->mcgm = (THH_mcgm_t)THH_INVALID_HNDL;\r
2295     }\r
2296 \r
2297     THH_uar_destroy(thh_hob_p->kar);\r
2298     thh_hob_p->kar = (THH_uar_t)THH_INVALID_HNDL;\r
2299 \r
2300 kar_create_err:\r
2301     MOSAL_unmap_phys_addr(MOSAL_get_kernel_prot_ctx(), (MT_virt_addr_t) kar_addr, \r
2302                                ((MT_size_t)1 << thh_hob_p->profile.log2_uar_pg_size));\r
2303     thh_hob_p->kar_addr = (MT_virt_addr_t) 0;\r
2304 \r
2305 kar_map_phys_addr_err:\r
2306     if (thh_hob_p->profile.use_priv_udav) {\r
2307         THH_udavm_destroy(thh_hob_p->udavm);\r
2308     }\r
2309     thh_hob_p->udavm = (THH_udavm_t)THH_INVALID_HNDL;\r
2310 udavm_create_err:\r
2311     if (thh_hob_p->profile.use_priv_udav) {\r
2312         THH_mrwm_deregister_mr(thh_hob_p->mrwm, dummy_key);\r
2313         thh_hob_p->udavm_lkey = 0;\r
2314     }\r
2315 udavm_table_register_err:\r
2316     if (thh_hob_p->profile.use_priv_udav) {\r
2317         MOSAL_unmap_phys_addr( MOSAL_get_kernel_prot_ctx(), (MT_virt_addr_t) udav_virt_addr , udav_table_size );\r
2318         thh_hob_p->udavm_table = (MT_virt_addr_t) NULL;\r
2319     }\r
2320 \r
2321 udavm_mosal_map_err:\r
2322     if (thh_hob_p->profile.use_priv_udav) {\r
2323         THH_ddrmm_free(thh_hob_p->ddrmm, udav_phys_addr, udav_table_size);\r
2324         thh_hob_p->udavm_table_ddr  = (MT_phys_addr_t) 0;\r
2325         thh_hob_p->udavm_table_size = 0;\r
2326     }\r
2327 \r
2328 udavm_ddrmm_alloc_err:\r
2329     THH_srqm_destroy(thh_hob_p->srqm);\r
2330     thh_hob_p->srqm = (THH_srqm_t)THH_INVALID_HNDL;\r
2331 \r
2332 srqm_create_err:\r
2333     THH_qpm_destroy( thh_hob_p->qpm, TRUE);\r
2334     thh_hob_p->qpm = (THH_qpm_t)THH_INVALID_HNDL;\r
2335 \r
2336 qpm_create_err:\r
2337     FREE(thh_hob_p->init_ib_props);\r
2338     thh_hob_p->init_ib_props = ( THH_port_init_props_t *) NULL;\r
2339 \r
2340 init_ib_props_malloc_err:\r
2341     THH_cqm_destroy( thh_hob_p->cqm, TRUE);\r
2342     thh_hob_p->cqm = (THH_cqm_t)THH_INVALID_HNDL;\r
2343 \r
2344 cqm_create_err:\r
2345     THH_mrwm_destroy(thh_hob_p->mrwm, TRUE);\r
2346     thh_hob_p->mrwm = (THH_mrwm_t)THH_INVALID_HNDL;\r
2347 \r
2348 mrwm_create_err:\r
2349     THH_uldm_destroy(thh_hob_p->uldm );\r
2350     thh_hob_p->uldm = (THH_uldm_t)THH_INVALID_HNDL;\r
2351 uldm_create_err:\r
2352 query_hca_err:\r
2353 #ifdef SIMULATE_HALT_HCA\r
2354     THH_cmd_CLOSE_HCA(thh_hob_p->cmd);\r
2355 #else\r
2356     MOSAL_spinlock_dpc_lock(&thh_hob_p->fatal_spl);\r
2357     /*test fatal again, here -- may have gotten FATAL before end of OPEN_hca process */\r
2358     if ((thh_hob_p->thh_state & THH_STATE_HAVE_ANY_FATAL) != 0) {\r
2359         /* got FATAL during OPEN_HCA */\r
2360         MTL_DEBUG4(MT_FLFMT("THH_hob_open_hca: In FATAL state")); \r
2361         have_fatal = TRUE;\r
2362     } else {\r
2363         have_fatal = FALSE;\r
2364     }\r
2365     MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
2366     if (have_fatal) {\r
2367         if (thh_hob_p->module_flags.fatal_delay_halt == 0) {\r
2368             MTL_DEBUG1(MT_FLFMT("%s: halting the HCA"), __func__);\r
2369             THH_cmd_CLOSE_HCA(thh_hob_p->cmd, TRUE);\r
2370         }\r
2371     } else {\r
2372         MTL_DEBUG1(MT_FLFMT("%s: closing the HCA on non-fatal error %d"), __func__, ret);\r
2373         THH_cmd_CLOSE_HCA(thh_hob_p->cmd, FALSE);\r
2374     }\r
2375 #endif\r
2376 \r
2377 init_hca_err:\r
2378     THH_cmd_revoke_ddrmm(thh_hob_p->cmd);\r
2379 \r
2380 cmd_assign_ddrmm_err:\r
2381 \r
2382     ddr_alloc_area = (MT_phys_addr_t *) &(thh_hob_p->ddr_alloc_base_addrs_vec);\r
2383     ddr_alloc_size = (MT_size_t *)&(thh_hob_p->ddr_alloc_size_vec);\r
2384     for (i = 0; i < thh_hob_p->profile.ddr_alloc_vec_size; i++, ddr_alloc_area++, ddr_alloc_size++) {\r
2385         if (*ddr_alloc_area != THH_DDRMM_INVALID_PHYS_ADDR) \r
2386           /* Do not free in case skipped during allocation (e.g., SRQC) */\r
2387           THH_ddrmm_free(thh_hob_p->ddrmm,*ddr_alloc_area, ((MT_size_t)1 << (*ddr_alloc_size)));\r
2388     }\r
2389 \r
2390 post_mutex_acquire_err:\r
2391     MOSAL_mutex_rel(&(thh_hob_p->mtx));\r
2392     \r
2393 post_state_change_error:\r
2394     MOSAL_spinlock_dpc_lock(&thh_hob_p->fatal_spl);\r
2395     /*test fatal again, here -- may have gotten FATAL before end of OPEN_hca process */\r
2396     if ((thh_hob_p->thh_state & THH_STATE_HAVE_ANY_FATAL) != 0) {\r
2397         /* got FATAL during OPEN_HCA */\r
2398         MTL_DEBUG4(MT_FLFMT("THH_hob_open_hca: In FATAL state")); \r
2399         have_fatal = TRUE;\r
2400     } else {\r
2401         /* restore the state to closed */\r
2402         have_fatal = FALSE;\r
2403         thh_hob_p->thh_state = THH_STATE_CLOSED;\r
2404     }\r
2405     MOSAL_spinlock_unlock(&thh_hob_p->fatal_spl);\r
2406     if (have_fatal) {\r
2407         THH_hob_restart(hca_hndl);\r
2408     }\r
2409     return ret;\r
2410 }\r
2411 \r
2412 /******************************************************************************\r
2413  *  Function:     THH_hob_query\r
2414  *\r
2415  *  Description:  Implements VAPI_query_hca verb.  Data is already stored in HOB object.\r
2416  *\r
2417  *  input:\r
2418  *                hca_hndl\r
2419  *  output: \r
2420  *                hca_cap_p -- pointer to output structure\r
2421  *  returns:\r
2422  *                HH_OK\r
2423  *                HH_EINVAL_HCA_HNDL\r
2424  *\r
2425  *****************************************************************************/\r
2426  HH_ret_t THH_hob_query(HH_hca_hndl_t  hca_hndl, \r
2427                                VAPI_hca_cap_t *hca_cap_p)\r
2428 {\r
2429     THH_hob_t             hob;\r
2430 \r
2431     MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
2432     if (hca_hndl == NULL) {\r
2433         MTL_ERROR1("THH_hob_query : ERROR : Invalid HCA handle\n");\r
2434         return HH_EINVAL_HCA_HNDL;\r
2435     }\r
2436     \r
2437     hob = THHOBP(hca_hndl);\r
2438 \r
2439     if (hob == NULL) {\r
2440         MTL_ERROR1("THH_hob_query : ERROR : No device registered\n");\r
2441         return HH_EINVAL;\r
2442     }\r
2443     \r
2444     TEST_RETURN_FATAL(hob);\r
2445 \r
2446     /* check if ib_init_props have been created -- indicates that open_hca called for this device */\r
2447     if (hob->init_ib_props == (THH_port_init_props_t *)NULL) {\r
2448         MTL_ERROR1("THH_hob_query: ERROR : HCA device has not yet been opened\n");\r
2449         return HH_EINVAL;\r
2450     }\r
2451 \r
2452     memcpy(hca_cap_p, &(hob->hca_capabilities), sizeof(VAPI_hca_cap_t));\r
2453     return HH_OK;\r
2454 }\r
2455 \r
2456 #define SET_MAX_SG(a)  (((a) < (u_int32_t)hob->dev_lims.max_sg) ? (a) : hob->dev_lims.max_sg)\r
2457 /******************************************************************************\r
2458  *  Function:     THH_hob_query_struct_init\r
2459  *\r
2460  *  Description:  Pre-computes the data for VAPI_query_hca.  Called during THH_hob_open_hca()\r
2461  *\r
2462  *  input:\r
2463  *                hob\r
2464  *  output: \r
2465  *                hca_cap_p -- pointer to output structure\r
2466  *  returns:\r
2467  *                HH_OK\r
2468  *                HH_EINVAL_HCA_HNDL\r
2469  *\r
2470  *  Comments:     Needs to use a MAD query for some of the parameters\r
2471  *\r
2472  *****************************************************************************/\r
2473 static  HH_ret_t THH_hob_query_struct_init(THH_hob_t  hob,\r
2474                                MT_bool have_usr_profile, \r
2475                                VAPI_hca_cap_t *hca_cap_p)\r
2476 {\r
2477     HH_ret_t  ret;\r
2478     u_int32_t flags = 0;\r
2479     u_int32_t log2_num_spare_segs = 0;\r
2480 \r
2481     MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
2482   MTL_DEBUG4("Entering THH_hob_query_struct_init\n");\r
2483         /* Maximum Number of QPs supported.                   */\r
2484 #if 0\r
2485   hca_cap_p->max_num_qp = hob->profile.max_num_qps - THH_NUM_RSVD_QP -\r
2486                     ((have_usr_profile == FALSE)? 0 : (1U<<hob->dev_lims.log2_rsvd_qps) );\r
2487 #else\r
2488   hca_cap_p->max_num_qp = (u_int32_t)hob->profile.max_num_qps;\r
2489 #endif\r
2490   hca_cap_p->max_num_srq = (u_int32_t)hob->profile.max_num_srqs;\r
2491   hca_cap_p->srq_resize_supported= TRUE;\r
2492         /* Maximum Number of oustanding WR on any WQ.         */\r
2493   hca_cap_p->max_qp_ous_wr = (1 << (hob->dev_lims.log_max_qp_sz)) - 1;                    \r
2494   hca_cap_p->max_wqe_per_srq = (1 << (hob->dev_lims.log_max_srq_sz)) - 1;                    \r
2495         \r
2496   /* Various flags (VAPI_hca_cap_flags_t)               */\r
2497 \r
2498 //  VAPI_RESIZE_OUS_WQE_CAP     = 1  /* Not currently supported */\r
2499 \r
2500   flags =  (hob->hca_props.udp ? VAPI_UD_AV_PORT_ENFORCE_CAP : 0) |\r
2501            (hob->dev_lims.apm ? VAPI_AUTO_PATH_MIG_CAP : 0 )      |\r
2502            (hob->dev_lims.rm  ? VAPI_RAW_MULTI_CAP     : 0)       |\r
2503            (hob->dev_lims.pkv ? VAPI_BAD_PKEY_COUNT_CAP : 0)      |\r
2504            (hob->dev_lims.qkv ? VAPI_BAD_QKEY_COUNT_CAP : 0)      |\r
2505            VAPI_CHANGE_PHY_PORT_CAP | VAPI_RC_RNR_NAK_GEN_CAP | VAPI_PORT_ACTIVE_EV_CAP;\r
2506            \r
2507 \r
2508   hca_cap_p->flags = flags;               \r
2509         /* Max num of scatter/gather entries for desc other than RD */\r
2510   hca_cap_p->max_num_sg_ent = SET_MAX_SG(28);       \r
2511         /* Max num of scatter entries for SRQs */\r
2512   hca_cap_p->max_srq_sentries = SET_MAX_SG(31);       \r
2513         /* Max num of scatter/gather entries for RD desc - not supported  */\r
2514   hca_cap_p->max_num_sg_ent_rd = 0 ;   \r
2515         /* Max num of supported CQs                           */\r
2516 #if 0\r
2517   hca_cap_p->max_num_cq = hob->profile.max_num_cqs -\r
2518              ((have_usr_profile == FALSE)? 0 : (1U<<hob->dev_lims.log2_rsvd_cqs) );\r
2519 #else\r
2520   hca_cap_p->max_num_cq = (u_int32_t)hob->profile.max_num_cqs;\r
2521 #endif        \r
2522   /* Max num of supported entries per CQ                */\r
2523   hca_cap_p->max_num_ent_cq = (1 << (hob->dev_lims.log_max_cq_sz)) - 1 /*for extra cqe needed */;      \r
2524         /* Maximum number of memory region supported.         */\r
2525 #if 0\r
2526   hca_cap_p->max_num_mr = hob->profile.num_external_mem_regions -           \r
2527                     ((have_usr_profile == FALSE)? 0 : (1U<<hob->dev_lims.log2_rsvd_mtts) );\r
2528 #else\r
2529   hca_cap_p->max_num_mr = (u_int32_t)hob->profile.num_external_mem_regions;          \r
2530 #endif        \r
2531         /* Largest contigous block of memory region in bytes. This may be achieved by registering\r
2532          * PHYSICAL memory directly for the region, (and using a page size for the region equal to\r
2533          * the size of the physical memory block you are registering).  The PRM allocates 5 bytes\r
2534          * for registering the log2 of the page size (with a 4K page size having page-size val 0).\r
2535          * Thus, the maximum page size per MTT entry is 4k * 2^31 (= 2^(31+12).  A single region \r
2536          * can include multiple entries, and we can use all the spare MTT entries available for\r
2537          * this HUGE region.  The driver requires that every memory region have at least a single\r
2538          * segment available for registration.  We can thus use all the spare segments (we have\r
2539          * allocated 2 segments per region, but only really need one) to this region. If there are\r
2540          * no spare MTT entries, we calculate the value based on the usual mtt entries per segment.\r
2541          * This will still be a HUGE number (probably 2^46 or greater). \r
2542          */\r
2543   if (hob->profile.log2_mtt_segs_per_region == 0)\r
2544       log2_num_spare_segs = (u_int32_t)hob->profile.log2_mtt_entries_per_seg;\r
2545   else \r
2546       log2_num_spare_segs  = (u_int32_t)(hob->profile.log2_max_mtt_entries - hob->profile.log2_mtt_segs_per_region);\r
2547 \r
2548   /* check that do not overflow 2^64 !! */\r
2549   if (log2_num_spare_segs >= 21) \r
2550        hca_cap_p->max_mr_size = MAKE_ULONGLONG(0xFFFFFFFFFFFFFFFF);\r
2551   else\r
2552        hca_cap_p->max_mr_size = (((u_int64_t)1L) << (31 + 12 + log2_num_spare_segs)) ;         \r
2553         /* Maximum number of protection domains supported.    */\r
2554 #if 0\r
2555   hca_cap_p->max_pd_num = hob->profile.max_num_pds - THH_NUM_RSVD_PD - \r
2556       ((have_usr_profile == FALSE)? 0 : hob->dev_lims.num_rsvd_pds );\r
2557 #else\r
2558   hca_cap_p->max_pd_num = (u_int32_t)hob->profile.max_num_pds;\r
2559 #endif\r
2560   /* Largest page size supported by this HCA            */\r
2561   hca_cap_p->page_size_cap = (1 << (hob->dev_lims.log_pg_sz));       \r
2562         /* Number of physical ports of the HCA.                */\r
2563   hca_cap_p->phys_port_num = hob->dev_lims.num_ports;       \r
2564         /* Maximum number of partitions supported .           */\r
2565   hca_cap_p->max_pkeys = hob->init_ib_props[0].max_pkey;           \r
2566         /* Maximum number of oust. RDMA read/atomic as target */\r
2567   hca_cap_p->max_qp_ous_rd_atom = 1 << (hob->profile.log2_inflight_rdma_per_qp);  \r
2568         /* EE Maximum number of outs. RDMA read/atomic as target -- NOT YET SUPPORTED  */\r
2569   hca_cap_p->max_ee_ous_rd_atom = 0;  \r
2570         /* Max. Num. of resources used for RDMA read/atomic as target */\r
2571   hca_cap_p->max_res_rd_atom = ((1 << (hob->ddr_alloc_size_vec.log2_rdb_size - THH_DDR_LOG2_RDB_ENTRY_SIZE)) > 255 ? \r
2572                                     255 :(1 << (hob->ddr_alloc_size_vec.log2_rdb_size - THH_DDR_LOG2_RDB_ENTRY_SIZE))) ;     \r
2573         /* Max. Num. of outs. RDMA read/atomic as initiator. Note that 255 is the max in the struct  */\r
2574   hca_cap_p->max_qp_init_rd_atom = ((1 << (hob->dev_lims.log_max_ra_req_qp)) > 255 ? \r
2575                                     255 :  (1 << (hob->dev_lims.log_max_ra_req_qp))); \r
2576         /* EE Max. Num. of outs. RDMA read/atomic as initiator  -- NOT YET SUPPORTED   */\r
2577   hca_cap_p->max_ee_init_rd_atom = 0;\r
2578         /* Level of Atomicity supported:  if supported, is only within this HCA*/\r
2579   hca_cap_p->atomic_cap = (hob->dev_lims.atm ? VAPI_ATOMIC_CAP_HCA : VAPI_ATOMIC_CAP_NONE);        \r
2580         /* Maximum number of EEC supported.   -- NOT YET SUPPORTED  */\r
2581 #if 0\r
2582   hca_cap_p->max_ee_num = 1 << (hob->hca_props.qpc_eec_cqc_rdb_parameters.log_num_of_ee);\r
2583 #else\r
2584   hca_cap_p->max_ee_num = 0;\r
2585 #endif\r
2586         /* Maximum number of IB_RDD supported  -- NOT YET SUPPORTED */\r
2587   hca_cap_p-> max_rdd_num = 0;                 \r
2588         /* Maximum Number of memory windows supported  */\r
2589 #if 0\r
2590   hca_cap_p->max_mw_num = hob->profile.num_mem_windows -                    \r
2591       ((have_usr_profile == FALSE)? 0 : (1U<<hob->dev_lims.log2_rsvd_mrws) );\r
2592 #else\r
2593   hca_cap_p->max_mw_num = (u_int32_t)hob->profile.num_mem_windows;                   \r
2594 #endif\r
2595         /* Maximum number of Raw IPV6 QPs supported  -- NOT YET SUPPORTED */ \r
2596   hca_cap_p->max_raw_ipv6_qp = 0;              \r
2597         /* Maximum number of Raw Ethertypes QPs supported  -- NOT YET SUPPORTED */\r
2598   hca_cap_p->max_raw_ethy_qp = 0;              \r
2599         /* Maximum Number of multicast groups  */\r
2600   hca_cap_p->max_mcast_grp_num = 1 << (hob->hca_props.multicast_parameters.log_mc_table_sz);            \r
2601         /* Maximum number of QP per multicast group    */\r
2602   hca_cap_p->max_mcast_qp_attach_num = ( (1U<<(hob->hca_props.multicast_parameters.log_mc_table_entry_sz)) \r
2603                                                -  THH_DDR_MCG_ENTRY_HEADER_SIZE) / \r
2604                                                              THH_DDR_MCG_BYTES_PER_QP;\r
2605         /* Maximum number of QPs which can be attached to a mcast grp */\r
2606   hca_cap_p->max_total_mcast_qp_attach_num = hca_cap_p->max_mcast_grp_num * hca_cap_p->max_mcast_qp_attach_num;\r
2607         /* Maximum number of address handles */\r
2608   hca_cap_p->max_ah_num = (u_int32_t)(hob->profile.use_priv_udav ? hob->profile.max_priv_udavs : \r
2609                                 THHUL_PDM_MAX_UL_UDAV_PER_PD*(hob->profile.max_num_pds+THH_NUM_RSVD_PD));\r
2610         /* max number of fmrs for the use is the number of user entries in MPT */\r
2611 #if 0\r
2612   hca_cap_p->max_num_fmr    = hob->profile.num_external_mem_regions - \r
2613       ((have_usr_profile == FALSE)? 0 : (1U<<hob->dev_lims.log2_rsvd_mtts) );\r
2614 #else\r
2615   hca_cap_p->max_num_fmr    = (u_int32_t)((hob->ddr_props.dh == FALSE) ? hob->profile.num_external_mem_regions : 0);\r
2616 #endif\r
2617 /* max maps per fmr is the max number that can be expressed by the MS bits of a u_int32_t\r
2618            that are unused for MPT addressing (which will occupy the LS bits of that u_int32_t).*/\r
2619   hca_cap_p->max_num_map_per_fmr = (1 << (32 - hob->profile.log2_max_mpt_entries)) - 1;\r
2620   \r
2621         /* Log2 4.096usec Max. RX to ACK or NAK delay */\r
2622   hca_cap_p->local_ca_ack_delay = hob->dev_lims.local_ca_ack_delay;\r
2623 \r
2624   /* Node GUID for this hca */\r
2625   ret = THH_hob_get_node_guid(hob,&(hca_cap_p->node_guid));           \r
2626 \r
2627   return(ret);\r
2628 }\r
2629 \r
2630 /******************************************************************************\r
2631  *  Function:     THH_hob_modify\r
2632  *\r
2633  *  Description:  Implements the VAPI_modify_hca verb\r
2634  *\r
2635  *  input:\r
2636  *                hca_hndl\r
2637  *                port_num - 1 or 2\r
2638  *                hca_attr_p - contains values to modify\r
2639  *                hca_attr_mask_p - mask specifying which values in hca_attr_p should\r
2640  *                                  be used for modification.\r
2641  *  output: \r
2642  *                none\r
2643  *  returns:\r
2644  *                HH_OK\r
2645  *                HH_EINVAL\r
2646  *                HH_EINVAL_HCA_HNDL\r
2647  *                HH_EINVAL_PORT\r
2648  *                HH_ENOSYS\r
2649  *\r
2650  *  Comments:     Implements IB Spec 1.0a now.  must be modified to support IB Spec 1.1\r
2651  *                JPM\r
2652  *\r
2653  *****************************************************************************/\r
2654 HH_ret_t THH_hob_modify(\r
2655                         HH_hca_hndl_t        hca_hndl,\r
2656                         IB_port_t            port_num,\r
2657                         VAPI_hca_attr_t      *hca_attr_p,\r
2658                         VAPI_hca_attr_mask_t *hca_attr_mask_p)\r
2659 {\r
2660   /* TBD, will use SET_IB command.  Problem is that can only set PKey and QKey counters to zero. */\r
2661   HH_ret_t  retn;\r
2662   THH_cmd_status_t cmd_ret;\r
2663   VAPI_hca_port_t  port_props;\r
2664   THH_set_ib_props_t    set_ib_props;\r
2665   IB_port_cap_mask_t    capabilities;           \r
2666   THH_hob_t             hob;\r
2667    \r
2668   MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
2669   if (MOSAL_get_exec_ctx() != MOSAL_IN_TASK) {\r
2670       MTL_ERROR1("THH_hob_modify: NOT IN TASK CONTEXT)\n");\r
2671       return HH_ERR;\r
2672   }\r
2673 \r
2674   if (hca_hndl == NULL) {\r
2675       MTL_ERROR1("THH_hob_modify : ERROR : Invalid HCA handle\n");\r
2676       return HH_EINVAL_HCA_HNDL;\r
2677   }\r
2678 \r
2679   hob = THHOBP(hca_hndl);\r
2680 \r
2681   if (hob == NULL) {\r
2682       MTL_ERROR1("THH_hob_modify : ERROR : No device registered\n");\r
2683       return HH_EINVAL;\r
2684   }\r
2685   TEST_RETURN_FATAL(hob);\r
2686 \r
2687   if (port_num > hob->dev_lims.num_ports || port_num < 1) {\r
2688       MTL_ERROR2( "THH_hob_modify: ERROR : invalid port number(%d)\n", port_num);\r
2689       return HH_EINVAL_PORT;\r
2690   }\r
2691 \r
2692   memset(&set_ib_props, 0, sizeof(THH_set_ib_props_t));\r
2693   \r
2694   set_ib_props.rqk = hca_attr_p->reset_qkey_counter;\r
2695 \r
2696   /* start with current capabilities */\r
2697   retn = THH_hob_query_port_prop(hca_hndl, port_num, &port_props);\r
2698   if (retn != HH_OK) {\r
2699       MTL_ERROR1("THH_hob_modify : ERROR : cannot get current capabilities (%d)\n", retn);\r
2700       return HH_EAGAIN;\r
2701   }\r
2702   capabilities = port_props.capability_mask;\r
2703   \r
2704   /* now, modify the capability mask according to the input */\r
2705   if (HCA_ATTR_IS_FLAGS_SET(*hca_attr_mask_p)) {\r
2706       /* calculate capabilities modification mask */\r
2707       if(HCA_ATTR_IS_SET(*hca_attr_mask_p, HCA_ATTR_IS_SM) ) {\r
2708           if (hca_attr_p->is_sm) {\r
2709               IB_CAP_MASK_SET(capabilities, IB_CAP_MASK_IS_SM);\r
2710           } else {\r
2711               IB_CAP_MASK_CLR(capabilities, IB_CAP_MASK_IS_SM);\r
2712           }\r
2713       }\r
2714       if(HCA_ATTR_IS_SET(*hca_attr_mask_p, HCA_ATTR_IS_SNMP_TUN_SUP) ) {\r
2715           if (hca_attr_p->is_snmp_tun_sup) {\r
2716               IB_CAP_MASK_SET(capabilities, IB_CAP_MASK_IS_SNMP_TUNN_SUP);\r
2717           } else {\r
2718               IB_CAP_MASK_CLR(capabilities, IB_CAP_MASK_IS_SNMP_TUNN_SUP);\r
2719           }\r
2720       }\r
2721       if(HCA_ATTR_IS_SET(*hca_attr_mask_p, HCA_ATTR_IS_DEV_MGT_SUP) ) {\r
2722           if (hca_attr_p->is_dev_mgt_sup) {\r
2723               IB_CAP_MASK_SET(capabilities, IB_CAP_MASK_IS_DEVICE_MGMT_SUP);\r
2724           } else {\r
2725               IB_CAP_MASK_CLR(capabilities, IB_CAP_MASK_IS_DEVICE_MGMT_SUP);\r
2726           }\r
2727       }\r
2728       if(HCA_ATTR_IS_SET(*hca_attr_mask_p, HCA_ATTR_IS_VENDOR_CLS_SUP) ) {\r
2729           if (hca_attr_p->is_vendor_cls_sup) {\r
2730               IB_CAP_MASK_SET(capabilities, IB_CAP_MASK_IS_VENDOR_CLS_SUP);\r
2731           } else {\r
2732               IB_CAP_MASK_CLR(capabilities, IB_CAP_MASK_IS_VENDOR_CLS_SUP);\r
2733           }\r
2734       }\r
2735   }\r
2736 \r
2737   set_ib_props.capability_mask = capabilities;\r
2738   \r
2739   /* now, perform the CMD */\r
2740   cmd_ret = THH_cmd_SET_IB(hob->cmd , port_num, &set_ib_props);\r
2741   if (cmd_ret != THH_CMD_STAT_OK) {\r
2742       TEST_CMD_FATAL(cmd_ret);\r
2743       MTL_ERROR1("THH_hob_modify: CMD_error in THH_cmd_SET_IB (%d)\n", cmd_ret);\r
2744       return HH_EINVAL;\r
2745   }\r
2746 \r
2747   return(HH_OK);\r
2748 }\r
2749 /******************************************************************************\r
2750  *  Function:     THH_hob_query_port_prop\r
2751  *\r
2752  *  Description:  Implements the VAPI_query_hca_port_prop verb\r
2753  *\r
2754  *  input:\r
2755  *                hca_hndl\r
2756  *                port_num - 1 or 2\r
2757  *  output: \r
2758  *                hca_port_p - port properties output structure\r
2759  *  returns:\r
2760  *                HH_OK\r
2761  *                HH_EINVAL\r
2762  *                HH_EINVAL_HCA_HNDL\r
2763  *                HH_EINVAL_PORT\r
2764  *                HH_ERR\r
2765  *\r
2766  *  Comments:     Does MAD query to get the data in real time.  Data is not pre-fetched, because\r
2767  *                the current port state is needed for the answer -- so the query must be performed\r
2768  *                anyway.\r
2769  *\r
2770  *****************************************************************************/\r
2771 HH_ret_t THH_hob_query_port_prop(HH_hca_hndl_t  hca_hndl,\r
2772                                     IB_port_t           port_num,\r
2773                                     VAPI_hca_port_t     *hca_port_p ) \r
2774 {\r
2775     SM_MAD_PortInfo_t  port_info;\r
2776     u_int8_t       *mad_frame_in;\r
2777     u_int8_t       *mad_frame_out;\r
2778     THH_cmd_status_t  cmd_ret;\r
2779 \r
2780     THH_hob_t  hob;\r
2781 \r
2782     MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
2783     if (MOSAL_get_exec_ctx() != MOSAL_IN_TASK) {\r
2784         MTL_ERROR1("THH_hob_query_port_prop: NOT IN TASK CONTEXT)\n");\r
2785         return HH_ERR;\r
2786     }\r
2787 \r
2788     if (hca_hndl == NULL) {\r
2789         MTL_ERROR1("THH_hob_query_port_prop : ERROR : Invalid HCA handle\n");\r
2790         return HH_EINVAL_HCA_HNDL;\r
2791     }\r
2792     hob = THHOBP(hca_hndl);\r
2793     if (hob == NULL) {\r
2794         MTL_ERROR1("THH_hob_query_port_prop : ERROR : No device registered\n");\r
2795         return HH_EINVAL;\r
2796     }\r
2797     TEST_RETURN_FATAL(hob);\r
2798 \r
2799     if (port_num > hob->dev_lims.num_ports || port_num < 1) {\r
2800         MTL_ERROR2( "THH_hob_query_port_prop: ERROR : invalid port number(%d)\n", port_num);\r
2801         return HH_EINVAL_PORT;\r
2802     }\r
2803 \r
2804     mad_frame_in = TNMALLOC(u_int8_t, IB_MAD_SIZE);\r
2805     if ( !mad_frame_in ) {\r
2806       return HH_EAGAIN;\r
2807     }\r
2808     mad_frame_out = TNMALLOC(u_int8_t, IB_MAD_SIZE);\r
2809     if ( !mad_frame_out ) {\r
2810       FREE(mad_frame_in);\r
2811       return HH_EAGAIN;\r
2812     }\r
2813     memset(mad_frame_in, 0, sizeof(mad_frame_in));\r
2814     memset(mad_frame_out, 0, sizeof(mad_frame_out));\r
2815 \r
2816     /* get port props using MAD commands in THH_cmd object */\r
2817     /* First, build the MAD header */\r
2818     MADHeaderBuild(IB_CLASS_SMP, \r
2819                       0,\r
2820                       IB_METHOD_GET,\r
2821                       IB_SMP_ATTRIB_PORTINFO,\r
2822                       (u_int32_t)   port_num,\r
2823                       &(mad_frame_in[0]));\r
2824 \r
2825     /* issue the query */\r
2826     cmd_ret = THH_cmd_MAD_IFC(hob->cmd, 0, 0, port_num, &(mad_frame_in[0]), &(mad_frame_out[0]));\r
2827     if (cmd_ret != THH_CMD_STAT_OK) {\r
2828         TEST_CMD_FATAL(cmd_ret);\r
2829         MTL_ERROR2( "THH_hob_query_port_prop: ERROR : Get Port Info command failed (%d) for port %d\n", cmd_ret, port_num);\r
2830         FREE(mad_frame_out);\r
2831         FREE(mad_frame_in);\r
2832         if ( cmd_ret == THH_CMD_STAT_EINTR ) {\r
2833           return HH_EINTR;\r
2834         }\r
2835         return HH_ERR;\r
2836     }\r
2837     /* now, translate the response to a structure */\r
2838     PortInfoMADToSt(&port_info, &(mad_frame_out[0]));\r
2839 \r
2840     /* finally, extract the information we want */\r
2841     hca_port_p->bad_pkey_counter = port_info.wPKViolations;\r
2842     hca_port_p->capability_mask  = port_info.dwCapMask;\r
2843     hca_port_p->gid_tbl_len      = port_info.bGUIDCap;\r
2844     hca_port_p->lid              = port_info.wLID;\r
2845     hca_port_p->lmc              = port_info.cLMC;\r
2846     hca_port_p->max_msg_sz       = IB_MAX_MESSAGE_SIZE;\r
2847     hca_port_p->max_mtu          = hob->dev_lims.max_mtu;\r
2848     hca_port_p->max_vl_num       = port_info.cVLCap;\r
2849     hca_port_p->pkey_tbl_len     = hob->init_ib_props[port_num-1].max_pkey;\r
2850     hca_port_p->qkey_viol_counter = port_info.wQKViolations;\r
2851     hca_port_p->sm_lid            = port_info.wMasterSMLID;\r
2852     hca_port_p->sm_sl             = port_info.cMasterSMSL;\r
2853     hca_port_p->state             = port_info.cPortState;\r
2854     hca_port_p->subnet_timeout    = port_info.cSubnetTO;\r
2855 \r
2856     hca_port_p->initTypeReply     = 0;   /* not yet supported in FW */\r
2857     \r
2858   FREE(mad_frame_out);\r
2859   FREE(mad_frame_in);\r
2860   return(HH_OK);\r
2861 }\r
2862 \r
2863 /******************************************************************************\r
2864  *  Function:     THH_hob_get_pkey_tbl_local\r
2865  *\r
2866  *  Description:  Gets PKEY table for a given port  \r
2867  *\r
2868  *  input:\r
2869  *                hca_hndl\r
2870  *                port_num - 1 or 2\r
2871  *                tbl_len_in - size of table provided for response (in pkeys)\r
2872  *                use_mad_query_for_pkeys - if TRUE, query Tavor for pkeys\r
2873  *                       else, use pkey_table tracking in thh_qpm\r
2874  *  output: \r
2875  *                tbl_len_out - size of returned table (in pkeys)\r
2876  *                pkey_tbl_p  - pointer to table containing data (space provided by caller)\r
2877  *  returns:\r
2878  *                HH_OK\r
2879  *                HH_EINVAL\r
2880  *                HH_EINVAL_HCA_HNDL\r
2881  *                HH_ERR\r
2882  *\r
2883  *  Comments:     Does MAD query to get the data in real time. \r
2884  *\r
2885  *****************************************************************************/\r
2886 static HH_ret_t THH_hob_get_pkey_tbl_local(HH_hca_hndl_t  hca_hndl,\r
2887                                      IB_port_t     port_num,\r
2888                                      u_int16_t     tbl_len_in,\r
2889                                      u_int16_t     *tbl_len_out,\r
2890                                      IB_pkey_t     *pkey_tbl_p,\r
2891                                      MT_bool       use_mad_query_for_pkeys)\r
2892 {\r
2893   SM_MAD_Pkey_table_t  pkey_table;\r
2894   u_int8_t       *mad_frame_in;\r
2895   u_int8_t       *mad_frame_out;\r
2896   int  i,j;\r
2897   int num_pkeys, pkey_index, num_pkeytable_commands;\r
2898   THH_cmd_status_t  cmd_ret;\r
2899   THH_hob_t  thh_hob_p;\r
2900   THH_qpm_t      qpm;\r
2901   HH_ret_t     hh_ret = HH_OK;\r
2902   MT_RETURN_IF_LOW_STACK(THH_WATERMARK);\r
2903 \r
2904   if (MOSAL_get_exec_ctx() != MOSAL_IN_TASK) {\r
2905       MTL_ERROR1("THH_hob_get_pkey_tbl: NOT IN TASK CONTEXT)\n");\r
2906       return HH_ERR;\r
2907   }\r
2908 \r
2909   if (hca_hndl == NULL) {\r
2910       MTL_ERROR1("THH_hob_get_pkey_tbl : ERROR : Invalid HCA handle\n");\r
2911       return HH_EINVAL_HCA_HNDL;\r
2912   }\r
2913   thh_hob_p = THHOBP(hca_hndl);\r
2914 \r
2915   /* check if have valid port number */\r
2916   if (port_num > thh_hob_p->dev_lims.num_ports || port_num < 1) {\r
2917       MTL_ERROR1("THH_hob_get_pkey_tbl: port number (%d) not valid)\n", port_num);\r
2918       return HH_EINVAL_PORT;\r
2919   }\r
2920   \r
2921   if (tbl_len_out == NULL) {\r
2922       return HH_EINVAL;\r
2923   }\r
2924   \r
2925 \r
2926   /* check that pkey table has enough space */\r
2927   num_pkeys =  thh_hob_p->init_ib_props[port_num-1].max_pkey;\r
2928 /*** warning C4242: '=' : conversion from 'int' to 'u_int16_t', possible loss of data ***/\r
2929   *tbl_len_out = (u_int16_t)num_pkeys;\r
2930 \r
2931   if (tbl_len_in < num_pkeys) {\r
2932       if (!tbl_len_in) {\r
2933           MTL_TRACE2( "THH_hob_get_pkey_tbl: returning number of pkeys configured (%d)\n", num_pkeys);\r
2934       } else {\r
2935           MTL_ERROR2( "THH_hob_get_pkey_tbl: ERROR : not enough space in return value table. num keys = %d\n",\r
2936                       num_pkeys);\r
2937       }\r
2938       return HH_EAGAIN;\r
2939   }\r
2940 \r
2941   /* check that have valid output buffer area */\r
2942   if (pkey_tbl_p == NULL) {\r
2943       return HH_EINVAL;\r
2944   }\r
2945 \r
2946 \r
2947   mad_frame_in = TNMALLOC(u_int8_t, IB_MAD_SIZE);\r
2948   if ( !mad_frame_in ) {\r
2949     return HH_EAGAIN;\r
2950   }\r
2951   mad_frame_out = TNMALLOC(u_int8_t, IB_MAD_SIZE);\r
2952   if ( !mad_frame_out ) {\r
2953     FREE(mad_frame_in);\r
2954     return HH_EAGAIN;\r
2955   }\r
2956   \r
2957   /* get KEY table using MAD command in THH_cmd object */\r
2958   /* get PKey table using MAD commands in THH_cmd object */\r
2959   /* First, build the MAD header */\r
2960   if (use_mad_query_for_pkeys == TRUE) {\r
2961       num_pkeytable_commands = ((num_pkeys - 1) / 32) + 1;\r
2962     \r
2963       pkey_index =  0;\r
2964       for (i = 0; i < num_pkeytable_commands; i++) {\r
2965           memset(mad_frame_in, 0, sizeof(mad_frame_in));\r
2966           memset(mad_frame_out, 0, sizeof(mad_frame_out));\r
2967           MADHeaderBuild(IB_CLASS_SMP, \r
2968                             0,\r
2969                             IB_METHOD_GET,\r
2970                             IB_SMP_ATTRIB_PARTTABLE,\r
2971                             (u_int32_t)   (32*i),\r
2972                             &(mad_frame_in[0]));\r
2973     \r
2974           cmd_ret = THH_cmd_MAD_IFC(thh_hob_p->cmd, 0, 0, port_num, &(mad_frame_in[0]), &(mad_frame_out[0]));\r
2975           if (cmd_ret != THH_CMD_STAT_OK) {\r
2976               TEST_CMD_FATAL(cmd_ret);\r
2977               MTL_ERROR2( "THH_hob_get_pkey_tbl: ERROR : Get Partition Table command failed (%d) for port %d\n", cmd_ret, port_num);\r
2978               FREE(mad_frame_out);\r
2979               FREE(mad_frame_in);\r
2980               return HH_ERR;\r
2981           }\r
2982           PKeyTableMADToSt(&pkey_table, &(mad_frame_out[0]));\r
2983     \r
2984           for (j = 0; j < 32; j++) {\r
2985               pkey_tbl_p[pkey_index++] = pkey_table.pkey[j];\r
2986               if (pkey_index == num_pkeys) {\r
2987                   break;\r
2988               }\r
2989           }\r
2990       }\r
2991   } else {\r
2992       hh_ret =  THH_hob_get_qpm ( thh_hob_p, &qpm );\r
2993       if (hh_ret != HH_OK) {\r
2994           MTL_ERROR2( "THH_hob_get_qpm: invalid QPM handle (ret= %d)\n", hh_ret);\r
2995           FREE(mad_frame_out);\r
2996           FREE(mad_frame_in);\r
2997           return HH_EINVAL;\r
2998       }\r
2999 /*** warning C4242: '=' : conversion from 'int' to 'u_int16_t', possible loss of data ***/\r
3000       hh_ret = THH_qpm_get_all_pkeys(qpm,port_num,(u_int16_t)num_pkeys, pkey_tbl_p);\r
3001       if (hh_ret != HH_OK) {\r
3002           MTL_ERROR2( "THH_qpm_get_all_sgids failed (ret= %d)\n", hh_ret);\r
3003           FREE(mad_frame_out);\r
3004           FREE(mad_frame_in);\r
3005           return HH_EINVAL;\r
3006       }\r
3007   }\r
3008 \r
3009   FREE(mad_frame_out);\r
3010   FREE(mad_frame_in);\r
3011   return(HH_OK);\r
3012 }\r
3013 /******************************************************************************\r
3014  *  Function:     THH_hob_get_pkey_tbl\r