[HCA] Fix solicited CQ event notification request
[mirror/winof/.git] / hw / mt23108 / vapi / Hca / hcahal / tavor / thhul_qpm / thhul_qpm.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 #define C_THHUL_QPM_C\r
34 \r
35 #include <mosal.h>\r
36 #include <ib_defs.h>\r
37 #include <nMPGA.h>\r
38 #include <vapi.h>\r
39 #include <tlog2.h>\r
40 #include <MT23108.h>\r
41 #include <thhul.h>\r
42 #include <uar.h>\r
43 #include <thhul_hob.h>\r
44 #include <thhul_cqm.h>\r
45 #include <thhul_srqm.h>\r
46 #include <thhul_pdm.h>\r
47 #include <udavm.h>\r
48 #include <vapi_common.h>\r
49 #include <complib/cl_math.h>\r
50 \r
51 \r
52 /* THH_qpm Pkey and GID table access for usage of the special QPs (mlx IB headers) */\r
53 #ifdef MT_KERNEL\r
54 #include <thh_hob.h>\r
55 #endif\r
56 \r
57 #if defined(MT_KERNEL) && defined(__LINUX__)\r
58 #include <linux/mm.h>\r
59 #include <asm/pgtable.h>\r
60 #include <linux/highmem.h>\r
61 #endif\r
62 \r
63 #include "thhul_qpm.h"\r
64 \r
65 #ifdef WIN32\r
66 #include "hca_data.h"\r
67 #endif\r
68 \r
69 #include <mtperf.h>\r
70 MTPERF_NEW_SEGMENT(THH_uar_sendq_dbell,200);\r
71 MTPERF_NEW_SEGMENT(WQE_build_send,2000);\r
72 MTPERF_NEW_SEGMENT(SQ_WQE_copy,2000);\r
73 \r
74 #define USE_FAST_POST 1\r
75 \r
76 #ifndef MT_KERNEL\r
77 /* instead of "ifdef"ing all over the code we define an empty macro */\r
78 #define MOSAL_pci_phys_free_consistent(addr,sz)  do {} while(0);\r
79 #endif\r
80 \r
81 \r
82 /* Limit kmalloc to 2 pages (if this fails, vmalloc will fail too) */\r
83 #define WQ_KMALLOC_LIMIT (4*MOSAL_SYS_PAGE_SIZE)\r
84 #define SMALL_VMALLOC_AREA (1<<28)  /* VMALLOC area of 256MB or less is considered a scarce resource */\r
85 \r
86 #define LOG2_QP_HASH_TBL_SZ 8\r
87 #define QP_HASH_TBL_SZ  (1<<8)\r
88 \r
89 #define WQE_ALIGN_SHIFT 6        /* WQE address should be aligned to 64 Byte */\r
90 #define WQE_SZ_MULTIPLE_SHIFT 4           /* WQE size must be 16 bytes multiple */\r
91 /* WQE segments sizes */\r
92 #define WQE_SEG_SZ_NEXT (sizeof(struct wqe_segment_next_st)/8)            /* NEXT segment */\r
93 #define WQE_SEG_SZ_CTRL (sizeof(struct wqe_segment_ctrl_send_st)/8)       /* CTRL segment */\r
94 #define WQE_SEG_SZ_RD   (sizeof(struct wqe_segment_rd_st)/8)              /* DATAGRAM:RD */\r
95 #define WQE_SEG_SZ_UD   (sizeof(struct wqe_segment_ud_st)/8)              /* DATAGRAM:UD */\r
96 #define WQE_SEG_SZ_RADDR (sizeof(struct wqe_segment_remote_address_st)/8) /* Remote address */\r
97 #define WQE_SEG_SZ_ATOMIC (sizeof(struct wqe_segment_atomic_st)/8)        /* Atomic */\r
98 #define WQE_SEG_SZ_BIND (sizeof(struct wqe_segment_bind_st)/8)            /* Bind */\r
99 /* There is either BIND or RADDR+ATOMIC */\r
100 #define WQE_SEG_SZ_BIND_RADDR_ATOMIC ((WQE_SEG_SZ_RADDR+WQE_SEG_SZ_ATOMIC) >  WQE_SEG_SZ_BIND ? \\r
101    (WQE_SEG_SZ_RADDR+WQE_SEG_SZ_ATOMIC) : WQE_SEG_SZ_BIND )\r
102 #define WQE_SEG_SZ_SG_ENTRY (sizeof(struct wqe_segment_data_ptr_st)/8)/* Scatter/Gather entry(ptr)*/\r
103 #define WQE_SEG_SZ_SG_ENTRY_DW (sizeof(struct wqe_segment_data_ptr_st)/32)/* (same in DWORDs) */\r
104 /* INLINE segment for UD headers (SMI/GSI) */\r
105 #define IB_RWH_SZ 4\r
106 #define IB_ICRC_SZ 4\r
107 #define WQE_INLINE_SZ_BCOUNT 4\r
108 /* INLINE segment for UD headers (SMI/GSI) */\r
109 #define WQE_INLINE_SZ_UD_HDR \\r
110   MT_UP_ALIGNX_U32((WQE_INLINE_SZ_BCOUNT+IB_LRH_LEN+IB_GRH_LEN+IB_BTH_LEN+IB_DETH_LEN),4)\r
111 /* INLINE segment for RAW-Ethertype */\r
112 #define WQE_INLINE_SZ_RAW_HDR \\r
113   MT_UP_ALIGNX_U32((WQE_INLINE_SZ_BCOUNT+IB_LRH_LEN+IB_RWH_SZ),4)\r
114 #define WQE_INLINE_ICRC MT_UP_ALIGNX_U32(WQE_INLINE_SZ_BCOUNT+IB_ICRC_SZ,4)\r
115 #define MAX_WQE_SZ 1008\r
116 #define BIND_WQE_SZ (WQE_SEG_SZ_NEXT+WQE_SEG_SZ_CTRL+WQE_SEG_SZ_BIND)\r
117 \r
118 #define MAX_ALLOC_RETRY 3  /* Maximum retries to get WQEs buffer which does not cross 4GB boundry */\r
119 \r
120 #define IS_VALID_QPN(qpn) ((qpn) <=  0x00FFFFFF)\r
121 #define DEFAULT_PKEY 0xFFFF\r
122 #define QP1_PKEY_INDEX 0xFFFFFFFF\r
123 \r
124 #define RESERVED_MEMBIND_EECN 0  /* Pseudo EE-context reserved for memory binding processing */\r
125 \r
126 /* Dpool in size granularity of 1KB */\r
127 #define THHUL_DPOOL_SZ_MIN_KB 1 /* Minimum WQEs buffer of 1KB */\r
128 #define THHUL_DPOOL_SZ_MAX_KB 64 /* Max. is 64KB */\r
129 #define THHUL_DPOOL_SZ_UNIT_SHIFT 10 /* 1KB units shift */\r
130 #define THHUL_DPOOL_GRANULARITY_SHIFT 10 /* 1KB garnularity - for alignment */\r
131 #define THHUL_DPOOL_SZ_BASE_BUF_KB \\r
132   (THHUL_DPOOL_SZ_MAX_KB*2) /* Size of buffer shared among dpools*/\r
133 \r
134 /* Descriptors pool for small QPs */\r
135 /* This data structure allows sharing of locked pages among QPs in order to reduce amount of\r
136   locked pages and assure they cover full pages (fork support) */\r
137 typedef struct THHUL_qp_dpool_st {\r
138   MT_size_t buf_size_kb;     /* Each buffer in the pool */\r
139   void* free_buf_list;\r
140   unsigned long ref_cnt;  /* When reached zero, may be freed */\r
141   void* orig_buf;  /* Pointer to allocated memory chunk */\r
142   MT_size_t orig_size;\r
143   MT_bool used_virt_alloc;\r
144   struct THHUL_qp_dpool_st *prev; /* list of dpools of same size */\r
145   struct THHUL_qp_dpool_st *next; /* list of dpools of same size */\r
146 } THHUL_qpm_dpool_t;\r
147 \r
148 typedef struct {\r
149   VAPI_ud_av_t av;\r
150   MPGA_headers_t hdrs;\r
151 } special_qp_temp_t;\r
152 \r
153 #define CHIME_WORDS_PREFIX volatile\r
154 #define WQE_IO_WRITE MOSAL_MMAP_IO_WRITE_DWORD\r
155 \r
156 typedef struct { /* Queue resources context */\r
157   MT_virt_addr_t wqe_buf;  /* The buffer for this queue WQEs - aligned to WQE size */ \r
158   VAPI_wr_id_t *wqe_id; /* Array of max_outs entries for holding each WQE ID (WQE index based) */\r
159   u_int32_t max_outs; /* Max. outstanding (number of WQEs in buffer) */\r
160   u_int32_t cur_outs; /* Currently outstanding */\r
161   u_int32_t max_sg_sz;  /* Max. Scatter/Gather list size */\r
162   MT_size_t log2_max_wqe_sz; /* WQE size is a power of 2 (software implementation requirement) */\r
163   u_int32_t max_inline_data; /* For send queue only */\r
164   u_int32_t next2post_index; /* Next WQE to use for posting (producer index)*/\r
165   u_int32_t next2free_index; /* Next WQE to use free (consumer index) */\r
166   volatile u_int32_t* last_posted_p;  /* For WQE chain linkage (== NULL if none) */\r
167   special_qp_temp_t *wqe_tmp; /* For av,headers in special QP Send */\r
168   u_int32_t *wqe_draft;\r
169   /* Implementation note:\r
170    * Using the "wqe_draft" scratchpad is required since we may\r
171    * perform many read-modify-writes while packing the WQE fields and we\r
172    * have no idea on WQEs buffer location. In cases where the actual WQE is\r
173    * in the attached DDR memory, a direct WQE packing will increase the \r
174    * building latency since that memory is not cached and each "read-modify-write"\r
175    * would consume time as well as PCI bandwidth.\r
176    * So we build the WQE on the local stack and then copy it (along with the \r
177    * swapping to big-endian, if needed).\r
178    * Also note that this allows us to allocate the WQE on after all WQE is formatted,\r
179    * thus minimizing the QP (spin)locking time.\r
180    */\r
181   VAPI_qp_state_t qp_state; /* User level assumed QP state */\r
182   /* Implementation note:\r
183    * qp_state is held per queue in order to avoid race in qp_state updates \r
184    * which may result from polling different CQs for each queue.\r
185    * We would also like to keep the common THHUL_qp_t static during the life\r
186    * of the QP in order to avoid additional synchronization between send and\r
187    * receive queue \r
188    */\r
189   MOSAL_spinlock_t q_lock;   /* Protect concurrent usage of the queue */\r
190 } queue_res_t;\r
191 \r
192 /* HHUL_qp_hndl_t is a pointer to this structure */\r
193 typedef struct THHUL_qp_st {\r
194   VAPI_special_qp_t sqp_type; /* VAPI_REGULAR_QP for non-special QP */\r
195   IB_ts_t ts_type;\r
196   IB_wqpn_t qpn;\r
197   HHUL_pd_hndl_t pd;\r
198   THH_uar_t uar;  /* UAR to use for this QP */\r
199   char *av_ddr_base;\r
200   char *av_host_base;\r
201   MT_bool is_priv_ud_av;      /* Privileged UD AVs are enforced */\r
202   VAPI_lkey_t   ud_av_memkey; /* Memory key to put for UD AV handles */\r
203   HHUL_cq_hndl_t  sq_cq;\r
204   HHUL_cq_hndl_t  rq_cq;\r
205   void* wqe_buf_orig;   /* Pointer returned by qpm_malloc_within_4GB() for WQE buffer */\r
206   MT_bool used_virt_alloc;     /* Used "MOSAL_pci_virt_alloc_consistent" for buffer allocation */\r
207   MT_size_t wqe_buf_orig_size; /* size in bytes of wqe_buf_orig */\r
208   THHUL_qpm_dpool_t *dpool_p; /* If not NULL, wqe_buf_orig taken from this descriptors pool */\r
209   queue_res_t sq_res;   /* Send queue resources */\r
210   queue_res_t rq_res;   /* Receive queue resources */\r
211   HHUL_srq_hndl_t srq;  /* Set to HHUL_INVAL_SRQ_HNDL if not associated with a SRQ */\r
212 } *THHUL_qp_t;   \r
213 \r
214 #define QPM_USE_FIXED_QP_ARRAY   1\r
215 #define TOTAL_QP_ARRAY_PER_QPM 2048\r
216 #define QPM_QP_PER_ARRAY  TOTAL_QP_ARRAY_PER_QPM/QP_HASH_TBL_SZ\r
217 #define QP_ARRAY_REUSE      0xFFFFFFFE    /* reuse qp array */\r
218 #define QP_ARRAY_UNUSED     0xFFFFFFFF    /* first unused array */\r
219 \r
220 typedef struct qp_array_st {  \r
221   IB_wqpn_t qpn;\r
222   THHUL_qp_t qp;\r
223 } qp_array_t;\r
224 \r
225 \r
226 typedef struct qp_hash_entry_st {  /* QPN-to-QP hash table entry */\r
227   IB_wqpn_t qpn;\r
228   THHUL_qp_t qp;\r
229   struct qp_hash_entry_st *next;  /* next in this hash bin */\r
230 } qp_hash_entry_t;\r
231 \r
232 \r
233 typedef struct qp_array_entry_st {\r
234   qp_array_t qp_array[QPM_QP_PER_ARRAY+1]; /* set last one to QP_ARRAY_UNUSED*/\r
235 }qp_array_entry_t;\r
236 \r
237 /* fixed array table is two dimensional.\r
238  * QP_ARRAY_UNUSED : next entry in array.\r
239  * QP_ARRAY_REUSE : Used previousely, but qp was destroyed. This can be recycled.\r
240  * ex: array_tbl[i]->[qpn][QP_ARRAY_REUSE(can be reused)][qpn][QP_ARRAY_UNUSED(next entry)]...\r
241  */ \r
242 struct THHUL_qpm_st { /* THHUL_qpm_t is a pointer to this */\r
243   qp_hash_entry_t* hash_tbl[QP_HASH_TBL_SZ];\r
244   qp_array_entry_t array_tbl[QP_HASH_TBL_SZ];\r
245   u_int32_t qp_cnt; /* Total number of QPs */\r
246   MOSAL_spinlock_t hash_lock; /* used for qp_cnt protection, too */\r
247   THHUL_qpm_dpool_t *dpool_p[THHUL_DPOOL_SZ_MAX_KB - THHUL_DPOOL_SZ_MIN_KB + 1];/* KB garanularity */\r
248 #ifdef THHUL_QPM_DEBUG_DPOOL\r
249   unsigned long dpool_cnt; \r
250 #endif\r
251   MOSAL_mutex_t dpool_lock;\r
252   THHUL_srqm_t srqm;\r
253 };\r
254 \r
255 /**********************************************************************************************\r
256  *                    Private functions protoypes declarations\r
257  **********************************************************************************************/\r
258 static HH_ret_t qp_prep(\r
259   HHUL_hca_hndl_t hca, \r
260   VAPI_special_qp_t qp_type, \r
261   HHUL_qp_init_attr_t *qp_init_attr_p, \r
262   HHUL_qp_hndl_t *qp_hndl_p, \r
263   VAPI_qp_cap_t *qp_cap_out_p, \r
264   THH_qp_ul_resources_t *qp_ul_resources_p, \r
265   MT_bool in_ddr_mem  /* WQEs buffer allocated in attached DDR mem. or in main memory */\r
266 );\r
267 \r
268 static HH_ret_t init_qp(\r
269   HHUL_hca_hndl_t hca, \r
270   HHUL_qp_init_attr_t *qp_init_attr_p, \r
271   THHUL_qp_t new_qp\r
272 );\r
273 \r
274 static HH_ret_t qpm_alloc_wqe_buf(\r
275   /*IN*/ THHUL_qpm_t qpm,\r
276   /*IN*/ MT_bool in_ddr_mem,   /* Allocation of WQEs buffer is requested in attached DDR mem. */\r
277   /*IN*/ u_int32_t max_outs_wqes, /* HCA cap. */\r
278   /*IN*/ u_int32_t max_sg_ent, /* HCA cap. of max.s/g entries */\r
279   /*IN/OUT*/ THHUL_qp_t new_qp,\r
280   /*OUT*/    THH_qp_ul_resources_t *qp_ul_resources_p\r
281 );\r
282 \r
283 static HH_ret_t qpm_alloc_aux_data_buf(\r
284   /*IN/OUT*/ THHUL_qp_t new_qp\r
285 );\r
286 \r
287 static HH_ret_t insert_to_hash(THHUL_qpm_t qpm, THHUL_qp_t qp);\r
288 \r
289 static HH_ret_t remove_from_hash(THHUL_qpm_t qpm, THHUL_qp_t qp);\r
290 \r
291 #ifndef __KERNEL__\r
292 static void* dpool_alloc(THHUL_qpm_t qpm, u_int8_t buf_size_kb, THHUL_qpm_dpool_t **dpool_pp);\r
293 \r
294 static void dpool_free(THHUL_qpm_t qpm, THHUL_qpm_dpool_t *dpool_p, void* buf);\r
295 \r
296 #else\r
297 #define dpool_free(qpm,dpool_p,buf) \\r
298   MTL_ERROR1(MT_FLFMT("%s: Invoked dpool_free in kernel by mistake"), __func__)\r
299    \r
300 #endif\r
301 \r
302 /**********************************************************************************************\r
303  *                    Private inline functions \r
304  **********************************************************************************************/\r
305 /* Computer hash value (bin index) for given QP number */\r
306 inline static u_int32_t get_hash_index(IB_wqpn_t qpn)\r
307 {\r
308   return (qpn & MASK32(LOG2_QP_HASH_TBL_SZ));\r
309 }\r
310 \r
311 inline static u_int32_t get_wqe_index(\r
312   /*IN*/ queue_res_t *q_res_p, \r
313   /*IN*/ u_int32_t wqe_addr_32lsb,\r
314   /*OUT*/ u_int32_t *wqe_index_p\r
315 )\r
316 {\r
317   u_int32_t wqe_buf_base_32lsb;\r
318 \r
319   /* TBD: On QP resize this will have to be modified (buffers may change during QP life cycle) */\r
320   \r
321   wqe_buf_base_32lsb= (u_int32_t)(q_res_p->wqe_buf);\r
322   if (wqe_addr_32lsb >= wqe_buf_base_32lsb) { /* Assure index computation is positive */\r
323     *wqe_index_p= (wqe_addr_32lsb - wqe_buf_base_32lsb) >> q_res_p->log2_max_wqe_sz;\r
324     if (*wqe_index_p < q_res_p->max_outs)  { /* WQE is within this queue */\r
325       /* TBD: check if given wqe_addr_32lsb is aligned to WQE size */\r
326       return HH_OK;\r
327     }\r
328   } \r
329   \r
330   return HH_EINVAL; /* WQE is not withing this queue */\r
331 }\r
332 \r
333 \r
334 \r
335 static void dump_qp(qp_hash_entry_t *qp_p)\r
336 {\r
337   MTL_ERROR1("==== dump of qpn=%d ====\n", qp_p->qp->qpn);\r
338   MTL_ERROR1("sqp_type=%s\n", VAPI_special_qp_sym(qp_p->qp->sqp_type));\r
339   MTL_ERROR1("ts_type=%s\n", VAPI_ts_type_sym(qp_p->qp->ts_type));\r
340   MTL_ERROR1("pd=%lu\n", qp_p->qp->pd);\r
341   MTL_ERROR1("uar=%p\n", qp_p->qp->uar);\r
342   MTL_ERROR1("is_priv_ud_av=%s\n", qp_p->qp->is_priv_ud_av ? "Yes" : "No");\r
343   MTL_ERROR1("ud_av_memkey=0x%x\n", qp_p->qp->ud_av_memkey);\r
344   MTL_ERROR1("sq_cq=%p\n", qp_p->qp->sq_cq);\r
345   MTL_ERROR1("rq_cq=%p\n", qp_p->qp->rq_cq);\r
346   MTL_ERROR1("wqe_buf_orig=%p\n", qp_p->qp->wqe_buf_orig);\r
347   MTL_ERROR1("used_virt_alloc=%s\n", qp_p->qp->used_virt_alloc ? "Yes" : "No");\r
348   MTL_ERROR1("wqe_buf_orig_size="SIZE_T_FMT"\n", qp_p->qp->wqe_buf_orig_size);\r
349   MTL_ERROR1("dpool_p=%p\n", qp_p->qp->dpool_p);\r
350 }\r
351 \r
352 \r
353 #if QPM_USE_FIXED_QP_ARRAY\r
354 \r
355 inline static HH_ret_t find_wqe_from_array(\r
356   /*IN*/ THHUL_qpm_t qpm, \r
357   /*IN*/ IB_wqpn_t qpn, \r
358   /*IN*/ u_int32_t wqe_addr_32lsb,\r
359   /*OUT*/ THHUL_qp_t *qp_p,\r
360   /*OUT*/ queue_res_t **q_res_pp,\r
361   /*OUT*/ u_int32_t *wqe_index_p,\r
362   /*OUT*/ VAPI_wr_id_t *wqe_id_p\r
363 )\r
364 {\r
365         \r
366   u_int32_t hash_index= get_hash_index(qpn);\r
367   int i = 0;    \r
368   qp_array_entry_t *qp_array_p = &qpm->array_tbl[hash_index];\r
369   IB_wqpn_t m_qpn = qp_array_p->qp_array[i].qpn;\r
370 \r
371    \r
372   while(m_qpn != QP_ARRAY_UNUSED)\r
373   {\r
374     if(m_qpn == qpn)\r
375     {\r
376          THHUL_qp_t qp = *qp_p= qp_array_p->qp_array[i].qp;    \r
377     \r
378          /* check if this WQE is of SQ */ \r
379          if ((*wqe_index_p = (wqe_addr_32lsb - (u_int32_t)qp->sq_res.wqe_buf) >> qp->sq_res.log2_max_wqe_sz) \r
380                          < qp->sq_res.max_outs) \r
381          {\r
382          \r
383                 *q_res_pp= &((*qp_p)->sq_res);  \r
384                 *wqe_id_p= (*q_res_pp)->wqe_id[*wqe_index_p]; \r
385                 return HH_OK;\r
386          }\r
387          /* check if this WQE is of RQ */\r
388          if ((*qp_p)->srq == HHUL_INVAL_SRQ_HNDL) {\r
389                  if ((*wqe_index_p = (wqe_addr_32lsb - (u_int32_t)qp->rq_res.wqe_buf) >> qp->rq_res.log2_max_wqe_sz) \r
390                          < qp->rq_res.max_outs) \r
391                  { \r
392                          *q_res_pp= &((*qp_p)->rq_res);\r
393                          *wqe_id_p= (*q_res_pp)->wqe_id[*wqe_index_p]; \r
394                          return HH_OK;\r
395                  }      \r
396          } else { /* From SRQ ? */\r
397                  HH_ret_t       rc;\r
398                  *q_res_pp= NULL;\r
399                  rc= THHUL_srqm_comp(qpm->srqm, (*qp_p)->srq, wqe_addr_32lsb, wqe_id_p);\r
400                  if (rc == HH_OK) {\r
401                          return HH_OK;\r
402                  }\r
403          }\r
404     }\r
405    m_qpn = qp_array_p->qp_array[++i].qpn; \r
406   }  \r
407 \r
408   return HH_EINVAL; /* Invalid WQE address for this QP */  \r
409 }\r
410 #endif\r
411 \r
412 /* Find the queue context from the QP number and WQE address - using the hash table */\r
413 #if 0  /*find_wqe */\r
414 inline static HH_ret_t find_wqe(\r
415   /*IN*/ THHUL_qpm_t qpm, \r
416   /*IN*/ IB_wqpn_t qpn, \r
417   /*IN*/ u_int32_t wqe_addr_32lsb,\r
418   /*OUT*/ THHUL_qp_t *qp_p,\r
419   /*OUT*/ queue_res_t **q_res_pp,\r
420   /*OUT*/ u_int32_t *wqe_index_p,\r
421   /*OUT*/ VAPI_wr_id_t *wqe_id_p\r
422 )\r
423 {\r
424   u_int32_t hash_index= get_hash_index(qpn);\r
425   qp_hash_entry_t *cur_entry;\r
426   HH_ret_t rc;\r
427 \r
428 #if QPM_USE_FIXED_QP_ARRAY      \r
429   if(find_wqe_from_array(qpm,qpn,wqe_addr_32lsb,qp_p,q_res_pp,wqe_index_p,wqe_id_p) == HH_OK)\r
430           return HH_OK;\r
431 #endif\r
432   \r
433   MOSAL_spinlock_dpc_lock(&(qpm->hash_lock));\r
434   for (cur_entry= qpm->hash_tbl[hash_index]; cur_entry != NULL;\r
435        cur_entry= cur_entry->next) {\r
436     if (cur_entry->qpn == qpn) break;\r
437   }\r
438   MOSAL_spinlock_unlock(&(qpm->hash_lock));\r
439   if (cur_entry == NULL) {\r
440     MTL_ERROR1(MT_FLFMT("%s(pid="MT_PID_FMT"): failed to find qpn=0x%x in the hash table"),\r
441                __func__, MOSAL_getpid(), qpn);\r
442     return HH_EINVAL_QP_NUM;  /* not found */\r
443   }\r
444   *qp_p= cur_entry->qp;\r
445   \r
446   /* check if this WQE is of SQ */\r
447   *q_res_pp= &((*qp_p)->sq_res);\r
448   rc= get_wqe_index(*q_res_pp,wqe_addr_32lsb,wqe_index_p);\r
449   if (rc == HH_OK)  {\r
450     *wqe_id_p= (*q_res_pp)->wqe_id[*wqe_index_p]; \r
451     return HH_OK;\r
452   }\r
453   \r
454   /* check if this WQE is of RQ */\r
455   if ((*qp_p)->srq == HHUL_INVAL_SRQ_HNDL) {\r
456     *q_res_pp= &((*qp_p)->rq_res);\r
457     rc= get_wqe_index(*q_res_pp,wqe_addr_32lsb,wqe_index_p);\r
458     if (rc == HH_OK)  {\r
459       *wqe_id_p= (*q_res_pp)->wqe_id[*wqe_index_p]; \r
460       return HH_OK;\r
461     }\r
462   } else { /* From SRQ ? */\r
463     *q_res_pp= NULL;\r
464     rc= THHUL_srqm_comp(qpm->srqm, (*qp_p)->srq, wqe_addr_32lsb, wqe_id_p);\r
465     if (rc != HH_OK) {\r
466       MTL_ERROR2(MT_FLFMT("%s: Failed to find WQE in SRQ (WQE=0x%X QPn=0x%X)"), __func__,\r
467                  wqe_addr_32lsb, (*qp_p)->qpn);\r
468     }\r
469   }\r
470   \r
471   MTL_ERROR1(MT_FLFMT("%s(pid="MT_PID_FMT"): failed to find wqe"), __func__, MOSAL_getpid());\r
472   dump_qp(cur_entry);\r
473   return rc; /* Invalid WQE address for this QP */\r
474 }\r
475 #else /* find_wqe */\r
476 \r
477 /* optimized version of find_wqe */\r
478 inline static HH_ret_t find_wqe(\r
479   /*IN*/ THHUL_qpm_t qpm, \r
480   /*IN*/ IB_wqpn_t qpn, \r
481   /*IN*/ u_int32_t wqe_addr_32lsb,\r
482   /*OUT*/ THHUL_qp_t *qp_p,\r
483   /*OUT*/ queue_res_t **q_res_pp,\r
484   /*OUT*/ u_int32_t *wqe_index_p,\r
485   /*OUT*/ VAPI_wr_id_t *wqe_id_p\r
486 )\r
487 {\r
488         u_int32_t hash_index;\r
489         qp_hash_entry_t *cur_entry;\r
490 #if QPM_USE_FIXED_QP_ARRAY      \r
491         if(find_wqe_from_array(qpm,qpn,wqe_addr_32lsb,qp_p,q_res_pp,wqe_index_p,wqe_id_p) == HH_OK)\r
492                 return HH_OK;\r
493 #endif  \r
494 \r
495         hash_index = get_hash_index(qpn);\r
496 \r
497         MOSAL_spinlock_dpc_lock(&(qpm->hash_lock));\r
498         for (cur_entry= qpm->hash_tbl[hash_index]; cur_entry != NULL;\r
499                 cur_entry= cur_entry->next)\r
500         {\r
501                 if (cur_entry->qpn == qpn)\r
502                 {        \r
503                         THHUL_qp_t qp = *qp_p= cur_entry->qp;\r
504                         MOSAL_spinlock_unlock(&(qpm->hash_lock));\r
505                         /* check if this WQE is of SQ */ \r
506                         if ((*wqe_index_p = (wqe_addr_32lsb - (u_int32_t)qp->sq_res.wqe_buf) >> qp->sq_res.log2_max_wqe_sz) \r
507                                 < qp->sq_res.max_outs) \r
508                         {\r
509                                 *q_res_pp= &((*qp_p)->sq_res);  \r
510                                 *wqe_id_p= (*q_res_pp)->wqe_id[*wqe_index_p]; \r
511                                 return HH_OK;\r
512                         }\r
513                         /* check if this WQE is of RQ */\r
514                         if ((*qp_p)->srq == HHUL_INVAL_SRQ_HNDL)\r
515                         {\r
516                                 if ((*wqe_index_p = (wqe_addr_32lsb - (u_int32_t)qp->rq_res.wqe_buf) >> qp->rq_res.log2_max_wqe_sz) \r
517                                         < qp->rq_res.max_outs) \r
518                                 {\r
519                                         *q_res_pp= &((*qp_p)->rq_res);\r
520                                         *wqe_id_p= (*q_res_pp)->wqe_id[*wqe_index_p]; \r
521                                         return HH_OK;\r
522                                 }       \r
523                         }\r
524                         else\r
525                         { /* From SRQ ? */\r
526                                 HH_ret_t        rc;\r
527                                 *q_res_pp= NULL;\r
528                                 rc= THHUL_srqm_comp(qpm->srqm, (*qp_p)->srq, wqe_addr_32lsb, wqe_id_p);\r
529                                 if (rc != HH_OK)\r
530                                 {\r
531                                         MTL_ERROR2(MT_FLFMT("%s: Failed to find WQE in SRQ (WQE=0x%X QPn=0x%X)"), __func__,\r
532                                                 wqe_addr_32lsb, (*qp_p)->qpn);\r
533                                 }\r
534                                 return rc;\r
535                         }\r
536                 }        \r
537         }\r
538         MOSAL_spinlock_unlock(&(qpm->hash_lock));\r
539 \r
540         return HH_EINVAL; /* Invalid WQE address for this QP */\r
541 }\r
542 #endif  /*find_wqe */\r
543 \r
544 #if 0   /* valid_2send, valid2recv */\r
545 \r
546 inline static MT_bool is_qpstate_valid_2send(VAPI_qp_state_t cur_state)\r
547 {\r
548     switch (cur_state) {\r
549     case VAPI_RTS:\r
550     case VAPI_SQD:\r
551     case VAPI_ERR:\r
552     case VAPI_SQE:  return TRUE;\r
553                     break;\r
554     default:        return FALSE;\r
555     }\r
556 \r
557 }\r
558 inline static MT_bool is_qpstate_valid_2recv(VAPI_qp_state_t cur_state)\r
559 {\r
560     switch (cur_state) {\r
561     case VAPI_INIT: \r
562     case VAPI_RTR:\r
563     case VAPI_RTS:\r
564     case VAPI_SQD:\r
565     case VAPI_ERR:\r
566     case VAPI_SQE:  return TRUE;\r
567                     break;\r
568     default:        return FALSE;\r
569     }\r
570 \r
571 }\r
572 #else /* valid_2send, valid2recv */\r
573  \r
574 inline static bool is_qpstate_valid_2send(VAPI_qp_state_t cur_state)\r
575 {\r
576     if(MOSAL_EXPECT_FALSE(cur_state < VAPI_RTS))\r
577         return FALSE;\r
578     return TRUE;    \r
579 }\r
580 \r
581 inline static bool is_qpstate_valid_2recv(VAPI_qp_state_t cur_state)\r
582 {\r
583     if(MOSAL_EXPECT_FALSE(cur_state < VAPI_INIT))\r
584         return FALSE;\r
585     return TRUE;    \r
586 }\r
587 \r
588 #endif /* valid_2send, valid2recv */\r
589 \r
590 inline static tavor_if_nopcode_t encode_nopcode(VAPI_wr_opcode_t opcode)\r
591 {\r
592   switch (opcode) {\r
593     case VAPI_RDMA_WRITE:\r
594       return TAVOR_IF_NOPCODE_RDMAW;\r
595     case VAPI_RDMA_WRITE_WITH_IMM:\r
596       return TAVOR_IF_NOPCODE_RDMAW_IMM;\r
597     case VAPI_SEND:\r
598       return  TAVOR_IF_NOPCODE_SEND;\r
599     case VAPI_SEND_WITH_IMM:\r
600       return TAVOR_IF_NOPCODE_SEND_IMM;\r
601     case VAPI_RDMA_READ:\r
602       return TAVOR_IF_NOPCODE_RDMAR;\r
603     case VAPI_ATOMIC_CMP_AND_SWP:\r
604       return TAVOR_IF_NOPCODE_ATOM_CMPSWP;\r
605     case VAPI_ATOMIC_FETCH_AND_ADD:\r
606       return TAVOR_IF_NOPCODE_ATOM_FTCHADD;\r
607     default:\r
608       return TAVOR_IF_NOPCODE_NOP;\r
609   }\r
610 }\r
611 \r
612 /*********** WQE building functions ***********/\r
613 inline u_int64_t translate_av(THHUL_qp_t qp, u_int64_t ah)\r
614 {\r
615   return ah - (u_int64_t)(MT_ulong_ptr_t)qp->av_host_base + (u_int64_t)(MT_ulong_ptr_t)qp->av_ddr_base;\r
616 }\r
617 \r
618 /* Init a not-connected (invalid) "next" segment (i.e. NDS=0) */\r
619 #if 0 /* qpm_WQE_init_next */\r
620 inline static u_int32_t qpm_WQE_init_next(u_int32_t *wqe_buf)\r
621 {\r
622   memset(wqe_buf,0,WQE_SEG_SZ_NEXT);\r
623   return WQE_SEG_SZ_NEXT;\r
624 }\r
625 #else  /* qpm_WQE_init_next */\r
626 /* Optimized qpm_WQE_init_next */\r
627 inline static u_int32_t qpm_WQE_init_next(u_int32_t *wqe_buf)\r
628 {\r
629   /* WQE_SEG_SZ_NEXT = 8bytes, so write 64bit zero to address */        \r
630   *(u_int64_t *)wqe_buf = 0;\r
631  \r
632   return WQE_SEG_SZ_NEXT;\r
633 }\r
634 #endif\r
635 \r
636 inline static u_int32_t qpm_WQE_pack_send_next(u_int32_t *segment_p, \r
637   tavor_if_nopcode_t nopcode, MT_bool fence, u_int32_t dbd,\r
638   u_int32_t next_wqe_32lsb, u_int32_t wqe_sz_16B_chunks,\r
639   IB_eecn_t eecn)\r
640 {\r
641   memset(segment_p,0,WQE_SEG_SZ_NEXT);  /* Clear all "RESERVED" */\r
642   segment_p[MT_BYTE_OFFSET(wqe_segment_next_st,nda_31_6)>>2]= next_wqe_32lsb & (~MASK32(6));\r
643   MT_INSERT_ARRAY32(segment_p,nopcode,\r
644     MT_BIT_OFFSET(wqe_segment_next_st,nopcode),MT_BIT_SIZE(wqe_segment_next_st,nopcode));\r
645   MT_INSERT_ARRAY32(segment_p,fence ? 1 : 0,\r
646     MT_BIT_OFFSET(wqe_segment_next_st,f),MT_BIT_SIZE(wqe_segment_next_st,f));\r
647   MT_INSERT_ARRAY32(segment_p,dbd,\r
648     MT_BIT_OFFSET(wqe_segment_next_st,dbd),MT_BIT_SIZE(wqe_segment_next_st,dbd));\r
649   MT_INSERT_ARRAY32(segment_p,wqe_sz_16B_chunks,\r
650    MT_BIT_OFFSET(wqe_segment_next_st,nds),MT_BIT_SIZE(wqe_segment_next_st,nds));\r
651   MT_INSERT_ARRAY32(segment_p,eecn,\r
652     MT_BIT_OFFSET(wqe_segment_next_st,nee),MT_BIT_SIZE(wqe_segment_next_st,nee));\r
653   return WQE_SEG_SZ_NEXT;\r
654 }\r
655 \r
656 // u_int32_t offsets within wqe_segment_next_st structure\r
657 #define NEXT_ST_NDA_31_6_DWORD_OFFSET   MT_BYTE_OFFSET(wqe_segment_next_st,nda_31_6)>>2\r
658 #define NEXT_ST_NDS_DWORD_OFFSET  MT_BYTE_OFFSET(wqe_segment_next_st,nds)>>2\r
659 \r
660         // bit offsets within the given u_int32_t within wqe_segment_next_st\r
661 #define BIT_MASK_FOR_NEXT_WQE_31SB      (~MASK32(6))    \r
662 #define NEXT_ST_NDS_BIT_OFFSET   (MT_BIT_OFFSET(wqe_segment_next_st,nds) & 0x1f)\r
663 #define NEXT_ST_DBD_BIT_OFFSET   (MT_BIT_OFFSET(wqe_segment_next_st,dbd) & 0x1f)\r
664 #define NEXT_ST_F_BIT_OFFSET     (MT_BIT_OFFSET(wqe_segment_next_st,f) & 0x1f)\r
665 #define NEXT_ST_NEE_BIT_OFFSET   (MT_BIT_OFFSET(wqe_segment_next_st,nee) & 0x1f)\r
666 /* Converted into Big Endian version */\r
667 inline static u_int32_t WQE_pack_send_next_be(u_int32_t *segment_p, \r
668   tavor_if_nopcode_t nopcode, MT_bool fence, u_int32_t dbd,\r
669   u_int32_t next_wqe_32lsb, u_int32_t wqe_sz_16B_chunks,\r
670   IB_eecn_t eecn)\r
671 {\r
672   segment_p[NEXT_ST_NDA_31_6_DWORD_OFFSET] = MOSAL_cpu_to_be32(0\r
673                                 | (u_int32_t)nopcode\r
674                                 | (next_wqe_32lsb & BIT_MASK_FOR_NEXT_WQE_31SB ));\r
675   \r
676   \r
677   segment_p[NEXT_ST_NDS_DWORD_OFFSET] = MOSAL_cpu_to_be32(0 \r
678                 | (wqe_sz_16B_chunks << NEXT_ST_NDS_BIT_OFFSET ) // specify in 16 byte chunks\r
679                 | (fence << NEXT_ST_F_BIT_OFFSET )\r
680                 | (dbd << NEXT_ST_DBD_BIT_OFFSET)\r
681                 | (eecn << NEXT_ST_NEE_BIT_OFFSET)\r
682                 );\r
683   return WQE_SEG_SZ_NEXT;\r
684 }\r
685 \r
686 /* Pack Control segment (for sends) */\r
687 inline static u_int32_t WQE_pack_ctrl_send(u_int32_t *segment_p,  \r
688     VAPI_comp_type_t comp_type, MT_bool se_bit, u_int32_t event_bit,\r
689     u_int32_t imm_data)\r
690 {\r
691   memset(segment_p,0,WQE_SEG_SZ_CTRL);  /* Clear all "RESERVED" */\r
692   MT_INSERT_ARRAY32(segment_p,1,\r
693     MT_BIT_OFFSET(wqe_segment_ctrl_send_st,always1),MT_BIT_SIZE(wqe_segment_ctrl_send_st,always1));\r
694   MT_INSERT_ARRAY32(segment_p,(comp_type == VAPI_SIGNALED) ? 1 : 0,\r
695     MT_BIT_OFFSET(wqe_segment_ctrl_send_st,c),MT_BIT_SIZE(wqe_segment_ctrl_send_st,c));\r
696   MT_INSERT_ARRAY32(segment_p,se_bit ? 1 : 0,\r
697     MT_BIT_OFFSET(wqe_segment_ctrl_send_st,s),MT_BIT_SIZE(wqe_segment_ctrl_send_st,s));\r
698   MT_INSERT_ARRAY32(segment_p,event_bit,\r
699     MT_BIT_OFFSET(wqe_segment_ctrl_send_st,e),MT_BIT_SIZE(wqe_segment_ctrl_send_st,e));\r
700   segment_p[MT_BYTE_OFFSET(wqe_segment_ctrl_send_st,immediate)>>2]= imm_data;\r
701   return WQE_SEG_SZ_CTRL;\r
702 }\r
703 \r
704 /* Optimized vwerion of WQE_pack_ctrl_send\r
705  * remove memset and pre-calculate offsets \r
706  */\r
707 #define CTRL_SEND_IMMEDIATE_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_ctrl_send_st,immediate)>>2\r
708 #define CTRL_SEND_RESERVED0_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_ctrl_send_st,reserved0)>>2          \r
709 #define CTRL_SEND_ALWAYS_BIT_OFFSET   MT_BIT_OFFSET(wqe_segment_ctrl_send_st,always1)\r
710 #define CTRL_SEND_S_BIT_OFFSET        MT_BIT_OFFSET(wqe_segment_ctrl_send_st,s)\r
711 #define CTRL_SEND_C_BIT_OFFSET        MT_BIT_OFFSET(wqe_segment_ctrl_send_st,c)\r
712 #define CTRL_SEND_E_BIT_OFFSET        MT_BIT_OFFSET(wqe_segment_ctrl_send_st,e)\r
713 \r
714 inline static u_int32_t WQE_pack_ctrl_send_be(u_int32_t *segment_p,  \r
715     VAPI_comp_type_t comp_type, MT_bool se_bit, u_int32_t event_bit,\r
716     u_int32_t imm_data)\r
717 {\r
718          \r
719         u_int32_t *cur_loc_p = segment_p; \r
720         segment_p[CTRL_SEND_RESERVED0_DWORD_OFFSET] = 0;\r
721         WQE_IO_WRITE(&cur_loc_p[0], MOSAL_cpu_to_be32(0\r
722                 | (1 << CTRL_SEND_ALWAYS_BIT_OFFSET ) // this bit must be on\r
723                 | ((u_int32_t)(se_bit & 1) << CTRL_SEND_S_BIT_OFFSET ) // solicited event bit\r
724                 | (0 << CTRL_SEND_E_BIT_OFFSET )  // event bit is always zero right now\r
725                 | ((u_int32_t)((comp_type + 1) & 1) << CTRL_SEND_C_BIT_OFFSET ) \r
726                 ));\r
727 \r
728         WQE_IO_WRITE(&cur_loc_p[CTRL_SEND_IMMEDIATE_DWORD_OFFSET], imm_data);\r
729 \r
730   return WQE_SEG_SZ_CTRL;\r
731 }\r
732 \r
733 inline static u_int32_t WQE_pack_ud(u_int32_t *segment_p,\r
734   VAPI_lkey_t ud_av_memkey, u_int64_t ah, \r
735   IB_wqpn_t destination_qp, IB_qkey_t q_key)\r
736 {\r
737   memset(segment_p,0,WQE_SEG_SZ_UD);  /* Clear all "RESERVED" */\r
738   segment_p[MT_BYTE_OFFSET(wqe_segment_ud_st,l_key)>>2]= ud_av_memkey;\r
739   segment_p[MT_BYTE_OFFSET(wqe_segment_ud_st,av_address_63_32)>>2]= (u_int32_t)(ah>>32);\r
740   segment_p[MT_BYTE_OFFSET(wqe_segment_ud_st,av_address_31_5)>>2]= ((u_int32_t)ah & (~MASK32(5)) );\r
741   MT_INSERT_ARRAY32(segment_p,destination_qp,\r
742     MT_BIT_OFFSET(wqe_segment_ud_st,destination_qp),\r
743     MT_BIT_SIZE(wqe_segment_ud_st,destination_qp));\r
744   segment_p[MT_BYTE_OFFSET(wqe_segment_ud_st,q_key)>>2]= q_key;\r
745   return WQE_SEG_SZ_UD;\r
746 }\r
747 \r
748 /* Optimized version of WQE_pack_ud\r
749  * remove memset and pre-calculate offset\r
750  */\r
751 #define UD_ST_RESERV0_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_ud_st,reserved0)>>2  \r
752 #define UD_ST_RESERV1_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_ud_st,reserved1)>>2  \r
753 #define UD_ST_RESERV2_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_ud_st,reserved2)>>2\r
754 #define UD_ST_RESERV2_DWORD_OFFSET1 ((MT_BYTE_OFFSET(wqe_segment_ud_st,reserved2)>>2)+ 1)\r
755 #define UD_ST_RESERV2_DWORD_OFFSET2 ((MT_BYTE_OFFSET(wqe_segment_ud_st,reserved2)>>2)+ 2)\r
756 #define UD_ST_RESERV2_DWORD_OFFSET3 ((MT_BYTE_OFFSET(wqe_segment_ud_st,reserved2)>>2)+ 3)\r
757         \r
758 #define UD_ST_RESERV3_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_ud_st,reserved3)>>2\r
759 #define UD_ST_RESERV4_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_ud_st,reserved4)>>2\r
760 #define UD_ST_RESERV4_DWORD_OFFSET1 ((MT_BYTE_OFFSET(wqe_segment_ud_st,reserved4)>>2) + 1)\r
761 \r
762 #define UD_ST_LKEY_DWORD_OFFSET          MT_BYTE_OFFSET(wqe_segment_ud_st,l_key)>>2\r
763 #define UD_ST_ADDR_63_32_DWORD_OFFSET    MT_BYTE_OFFSET(wqe_segment_ud_st,av_address_63_32)>>2\r
764 #define UD_ST_ADDR_31_5_DWORD_OFFSET     MT_BYTE_OFFSET(wqe_segment_ud_st,av_address_31_5)>>2\r
765 #define UD_ST_DESTINATION_DWORD_OFFSET   MT_BYTE_OFFSET(wqe_segment_ud_st,destination_qp)>>2\r
766 #define UD_ST_QKEY_DWORD_OFFSET          MT_BYTE_OFFSET(wqe_segment_ud_st,q_key)>>2\r
767 #define UD_ST_AH_MASK                   (~MASK32(5))\r
768 \r
769 /* Convert into Big Endian version */\r
770 inline static u_int32_t WQE_pack_ud_be(u_int32_t *segment_p,\r
771   VAPI_lkey_t ud_av_memkey, u_int64_t ah, \r
772   IB_wqpn_t destination_qp, IB_qkey_t q_key)\r
773 {\r
774   /* Clear all "RESERVED" */    \r
775   /* zero out reserved fields, look at  wqe_segment_ud_st in MT23108_PRM_append.h */    \r
776   segment_p[UD_ST_RESERV0_DWORD_OFFSET] = 0;\r
777   segment_p[UD_ST_RESERV1_DWORD_OFFSET] = 0;\r
778   segment_p[UD_ST_RESERV2_DWORD_OFFSET] = 0;\r
779   segment_p[UD_ST_RESERV2_DWORD_OFFSET1] = 0;\r
780   segment_p[UD_ST_RESERV2_DWORD_OFFSET2] = 0;\r
781   segment_p[UD_ST_RESERV2_DWORD_OFFSET3] = 0;\r
782   \r
783   segment_p[UD_ST_RESERV4_DWORD_OFFSET] = 0;\r
784   segment_p[UD_ST_RESERV4_DWORD_OFFSET1] = 0;\r
785 \r
786   segment_p[UD_ST_LKEY_DWORD_OFFSET]= MOSAL_cpu_to_be32(ud_av_memkey);\r
787   segment_p[UD_ST_ADDR_63_32_DWORD_OFFSET]= MOSAL_cpu_to_be32((u_int32_t)(ah>>32));\r
788   segment_p[UD_ST_ADDR_31_5_DWORD_OFFSET]= MOSAL_cpu_to_be32(((u_int32_t)ah & UD_ST_AH_MASK ));\r
789 #ifdef WIN32\r
790   segment_p[UD_ST_DESTINATION_DWORD_OFFSET] = destination_qp;\r
791   segment_p[UD_ST_QKEY_DWORD_OFFSET]= q_key;\r
792 #else\r
793   segment_p[UD_ST_DESTINATION_DWORD_OFFSET] = MOSAL_cpu_to_be32(destination_qp);\r
794   segment_p[UD_ST_QKEY_DWORD_OFFSET]= MOSAL_cpu_to_be32(q_key);\r
795 #endif  \r
796   return WQE_SEG_SZ_UD;\r
797 }\r
798 \r
799 inline static u_int32_t WQE_pack_rd(u_int32_t *segment_p,\r
800   IB_wqpn_t destination_qp, IB_qkey_t q_key)\r
801 {\r
802   memset(segment_p,0,WQE_SEG_SZ_RD);  /* Clear all "RESERVED" */\r
803   MT_INSERT_ARRAY32(segment_p,destination_qp,\r
804     MT_BIT_OFFSET(wqe_segment_rd_st,destination_qp),\r
805     MT_BIT_SIZE(wqe_segment_rd_st,destination_qp));\r
806   segment_p[MT_BYTE_OFFSET(wqe_segment_rd_st,q_key)>>2]= q_key;\r
807   return WQE_SEG_SZ_RD;\r
808 }\r
809 \r
810 /* Optimized version \r
811  * remove memset and pre-calculate offset\r
812  */\r
813 #define RD_ST_RESERV0_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_rd_st,reserved0)>>2  \r
814 #define RD_ST_RESERV1_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_rd_st,reserved1)>>2  \r
815 #define RD_ST_RESERV1_DWORD_OFFSET1 ((MT_BYTE_OFFSET(wqe_segment_rd_st,reserved1)>>2)+1) \r
816 \r
817 #define RD_ST_DESTINATION_DWORD_OFFSET   MT_BYTE_OFFSET(wqe_segment_rd_st,destination_qp)>>2\r
818 #define RD_ST_QKEY_DWORD_OFFSET          MT_BYTE_OFFSET(wqe_segment_rd_st,q_key)>>2\r
819 \r
820 /* Convert into Big Endian version */\r
821 inline static u_int32_t WQE_pack_rd_be(u_int32_t *segment_p,\r
822   IB_wqpn_t destination_qp, IB_qkey_t q_key)\r
823 {\r
824   segment_p[RD_ST_RESERV1_DWORD_OFFSET] = 0;\r
825   segment_p[RD_ST_RESERV1_DWORD_OFFSET1] = 0;\r
826       \r
827   segment_p[RD_ST_DESTINATION_DWORD_OFFSET]= MOSAL_cpu_to_be32(destination_qp);\r
828   segment_p[RD_ST_QKEY_DWORD_OFFSET]= MOSAL_cpu_to_be32(q_key);\r
829 \r
830   return WQE_SEG_SZ_RD;\r
831 }\r
832 \r
833 \r
834 inline static u_int32_t WQE_pack_remote_addr(u_int32_t *segment_p,\r
835   IB_virt_addr_t remote_addr, IB_rkey_t remote_rkey)\r
836 {\r
837   memset(segment_p,0,WQE_SEG_SZ_RADDR);  /* Clear all "RESERVED" */\r
838   segment_p[MT_BYTE_OFFSET(wqe_segment_remote_address_st,remote_virt_addr_h)>>2]= \r
839     (u_int32_t)(remote_addr >> 32);\r
840   segment_p[MT_BYTE_OFFSET(wqe_segment_remote_address_st,remote_virt_addr_l)>>2]= \r
841     (u_int32_t)(remote_addr & 0xFFFFFFFF);\r
842   segment_p[MT_BYTE_OFFSET(wqe_segment_remote_address_st,rkey)>>2]= remote_rkey;\r
843   return WQE_SEG_SZ_RADDR;\r
844 }\r
845 \r
846 \r
847 /* Optimized version of WQE_pack_remote_addr\r
848  * remove memset and pre-calculaute offset\r
849  */\r
850 #define REMOTE_ADR_ST_RESERV0_DWORD_OFFSET      MT_BYTE_OFFSET(wqe_segment_remote_address_st,reserved0)>>2 \r
851 #define REMOTE_ADR_VIRT_ADDR_H_DWORD_OFFSET             MT_BYTE_OFFSET(wqe_segment_remote_address_st,remote_virt_addr_h)>>2\r
852 #define REMOTE_ADR_VIRT_ADDR_L_DWORD_OFFSET             MT_BYTE_OFFSET(wqe_segment_remote_address_st,remote_virt_addr_l)>>2\r
853 #define REMOTE_ADR_RKEY_DWORD_OFFSET            MT_BYTE_OFFSET(wqe_segment_remote_address_st,rkey)>>2   \r
854 \r
855 /* Convert into Big Endian version */\r
856 inline static u_int32_t WQE_pack_remote_addr_be(u_int32_t *segment_p,\r
857   IB_virt_addr_t remote_addr, IB_rkey_t remote_rkey)\r
858 {\r
859   segment_p[REMOTE_ADR_ST_RESERV0_DWORD_OFFSET] = 0;    \r
860   \r
861   segment_p[REMOTE_ADR_VIRT_ADDR_H_DWORD_OFFSET]= \r
862     MOSAL_cpu_to_be32((u_int32_t)(remote_addr >> 32));\r
863   segment_p[REMOTE_ADR_VIRT_ADDR_L_DWORD_OFFSET]= \r
864     MOSAL_cpu_to_be32((u_int32_t)(remote_addr));\r
865   segment_p[REMOTE_ADR_RKEY_DWORD_OFFSET]= MOSAL_cpu_to_be32(remote_rkey);\r
866 \r
867   return WQE_SEG_SZ_RADDR;\r
868 }\r
869 /* this is same as WQE_pack_remote_addr but return number of DWORD(32bits)\r
870  * written, instead bytes. \r
871  */\r
872 inline static u_int32_t WQE_pack_remote_addr_req2(u_int32_t *segment_p,\r
873   IB_virt_addr_t remote_addr, IB_rkey_t remote_rkey)\r
874 {\r
875 #define WQE_SEG_SZ_RADDR_DWORD  WQE_SEG_SZ_RADDR>>2     \r
876   segment_p[REMOTE_ADR_ST_RESERV0_DWORD_OFFSET] = 0;    \r
877     \r
878   segment_p[REMOTE_ADR_VIRT_ADDR_H_DWORD_OFFSET]= \r
879     MOSAL_cpu_to_be32((u_int32_t)(remote_addr >> 32));\r
880   segment_p[REMOTE_ADR_VIRT_ADDR_L_DWORD_OFFSET]= \r
881     MOSAL_cpu_to_be32((u_int32_t)(remote_addr));\r
882   segment_p[REMOTE_ADR_RKEY_DWORD_OFFSET]= MOSAL_cpu_to_be32(remote_rkey);\r
883    \r
884   return WQE_SEG_SZ_RADDR_DWORD;\r
885 }\r
886 \r
887 inline static u_int32_t qpm_WQE_pack_recv_next(u_int32_t *segment_p, \r
888   u_int32_t next_wqe_32lsb, u_int32_t wqe_sz_16B_chunks)\r
889 {\r
890   memset(segment_p,0,WQE_SEG_SZ_NEXT);  /* Clear all "RESERVED" */\r
891   segment_p[MT_BYTE_OFFSET(wqe_segment_next_st,nda_31_6)>>2]= ( next_wqe_32lsb & (~MASK32(6)) ) \r
892     | 1 ;  /* LS-bit is set to work around bug #16159/16160/16161 */;\r
893   MT_INSERT_ARRAY32(segment_p,1, /* DBD always '1 for RQ */\r
894     MT_BIT_OFFSET(wqe_segment_next_st,dbd),MT_BIT_SIZE(wqe_segment_next_st,dbd));\r
895   MT_INSERT_ARRAY32(segment_p,wqe_sz_16B_chunks,\r
896     MT_BIT_OFFSET(wqe_segment_next_st,nds),MT_BIT_SIZE(wqe_segment_next_st,nds));\r
897   return WQE_SEG_SZ_NEXT;\r
898 }\r
899 \r
900 /* Optimized Version */\r
901 /* remove memset */\r
902 /* pre calculation for WQE_pack_recv_next */\r
903 #define NEXT_ST_NDA_31_6_DWORD_OFFSET   MT_BYTE_OFFSET(wqe_segment_next_st,nda_31_6)>>2\r
904 #define NEXT_ST_NDS_DWORD_OFFSET                MT_BYTE_OFFSET(wqe_segment_next_st,nds)>>2\r
905 \r
906 #define BIT_MASK_FOR_NEXT_WQE_31SB      (~MASK32(6)) \r
907 \r
908 inline static u_int32_t WQE_pack_recv_next_be(u_int32_t *segment_p, \r
909   u_int32_t next_wqe_32lsb, u_int32_t wqe_sz_16B_chunks)\r
910 {\r
911         \r
912   segment_p[NEXT_ST_NDA_31_6_DWORD_OFFSET] = MOSAL_cpu_to_be32(0\r
913                                 | (next_wqe_32lsb & BIT_MASK_FOR_NEXT_WQE_31SB ));\r
914   segment_p[NEXT_ST_NDS_DWORD_OFFSET] = MOSAL_cpu_to_be32(0 \r
915                 | (wqe_sz_16B_chunks << NEXT_ST_NDS_BIT_OFFSET ) // specify in 16 byte chunks\r
916                 | (1 << NEXT_ST_DBD_BIT_OFFSET)\r
917                 );\r
918                 \r
919   return WQE_SEG_SZ_NEXT;\r
920 }\r
921 \r
922 inline static u_int32_t WQE_pack_atomic_cmpswp(u_int32_t *segment_p,\r
923   u_int64_t cmp_data, u_int64_t swap_data)\r
924 {\r
925   segment_p[MT_BYTE_OFFSET(wqe_segment_atomic_st,swap_add_h)>>2]= (u_int32_t)(swap_data >> 32);\r
926   segment_p[MT_BYTE_OFFSET(wqe_segment_atomic_st,swap_add_l)>>2]= (u_int32_t)(swap_data & 0xFFFFFFFF);\r
927   segment_p[MT_BYTE_OFFSET(wqe_segment_atomic_st,compare_h)>>2]= (u_int32_t)(cmp_data >> 32);\r
928   segment_p[MT_BYTE_OFFSET(wqe_segment_atomic_st,compare_l)>>2]= (u_int32_t)(cmp_data & 0xFFFFFFFF);\r
929   return WQE_SEG_SZ_ATOMIC;\r
930 }\r
931 \r
932 #define ATOMIC_ST_SWAP_ADDR_H_DWORD_OFFSET   MT_BYTE_OFFSET(wqe_segment_atomic_st,swap_add_h)>>2\r
933 #define ATOMIC_ST_SWAP_ADDR_L_DWORD_OFFSET   MT_BYTE_OFFSET(wqe_segment_atomic_st,swap_add_l)>>2\r
934 #define ATOMIC_ST_COMPARE_H_DWORD_OFFSET     MT_BYTE_OFFSET(wqe_segment_atomic_st,compare_h)>>2\r
935 #define ATOMIC_ST_CPMPARE_L_DWORD_OFFSET     MT_BYTE_OFFSET(wqe_segment_atomic_st,compare_l)>>2\r
936 /* Convert into Big Endian version */\r
937 inline static u_int32_t WQE_pack_atomic_cmpswp_be(u_int32_t *segment_p,\r
938   u_int64_t cmp_data, u_int64_t swap_data)\r
939 {       \r
940   segment_p[ATOMIC_ST_SWAP_ADDR_H_DWORD_OFFSET]= MOSAL_cpu_to_be32((u_int32_t)(swap_data >> 32));\r
941   segment_p[ATOMIC_ST_SWAP_ADDR_L_DWORD_OFFSET]= MOSAL_cpu_to_be32((u_int32_t)(swap_data ));\r
942   segment_p[ATOMIC_ST_COMPARE_H_DWORD_OFFSET]= MOSAL_cpu_to_be32((u_int32_t)(cmp_data >> 32));\r
943   segment_p[ATOMIC_ST_CPMPARE_L_DWORD_OFFSET]= MOSAL_cpu_to_be32((u_int32_t)(cmp_data ));\r
944 \r
945   return WQE_SEG_SZ_ATOMIC;\r
946 }\r
947 \r
948 inline static u_int32_t WQE_pack_atomic_fetchadd(u_int32_t *segment_p,u_int64_t add_data)\r
949 {\r
950   segment_p[MT_BYTE_OFFSET(wqe_segment_atomic_st,swap_add_h)>>2]= (u_int32_t)(add_data >> 32);\r
951   segment_p[MT_BYTE_OFFSET(wqe_segment_atomic_st,swap_add_l)>>2]= (u_int32_t)(add_data & 0xFFFFFFFF);\r
952   return WQE_SEG_SZ_ATOMIC;\r
953 }\r
954 \r
955 #define ATOMIC_ST_SWAP_ADDR_H_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_atomic_st,swap_add_h)>>2\r
956 #define ATOMIC_ST_SWAP_ADDR_L_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_atomic_st,swap_add_l)>>2\r
957 /* Convert into Big Endian version */\r
958 inline static u_int32_t WQE_pack_atomic_fetchadd_be(u_int32_t *segment_p,u_int64_t add_data)\r
959 {\r
960   segment_p[ATOMIC_ST_SWAP_ADDR_H_DWORD_OFFSET]= MOSAL_cpu_to_be32((u_int32_t)(add_data >> 32));\r
961   segment_p[ATOMIC_ST_SWAP_ADDR_L_DWORD_OFFSET]= MOSAL_cpu_to_be32((u_int32_t)(add_data & 0xFFFFFFFF));\r
962  \r
963   return WQE_SEG_SZ_ATOMIC;\r
964 }\r
965 \r
966 /* Build the scatter/gather list (pointer segments) */\r
967 #define DATA_PTR_BYTE_COUNT_DWORD_OFFSET  MT_BYTE_OFFSET(wqe_segment_data_ptr_st,byte_count)>>2\r
968 #define DATA_PTR_LKEY_DWORD_OFFSET        MT_BYTE_OFFSET(wqe_segment_data_ptr_st,l_key)>>2\r
969 #define DATA_PTR_LOCAL_ADDR_H_DWORD_OFFSET   MT_BYTE_OFFSET(wqe_segment_data_ptr_st,local_address_h)>>2\r
970 #define DATA_PTR_LOCAL_ADDR_L_DWORD_OFFSET   MT_BYTE_OFFSET(wqe_segment_data_ptr_st,local_address_l)>>2\r
971 #define DATA_PTR_LEN_MASK     MASK32(31)  \r
972 \r
973 inline static u_int32_t WQE_pack_sg_list(u_int32_t *segment_p,\r
974   u_int32_t sg_lst_len,VAPI_sg_lst_entry_t *sg_lst_p)\r
975 {\r
976    u_int32_t i;\r
977    u_int32_t *cur_loc_p= segment_p;\r
978 \r
979    for (i= 0; i < sg_lst_len; i++ , cur_loc_p+= WQE_SEG_SZ_SG_ENTRY_DW) {\r
980      cur_loc_p[MT_BYTE_OFFSET(wqe_segment_data_ptr_st,byte_count)>>2]= \r
981        (sg_lst_p[i].len & MASK32(31));\r
982      cur_loc_p[MT_BYTE_OFFSET(wqe_segment_data_ptr_st,l_key)>>2]= sg_lst_p[i].lkey;\r
983      cur_loc_p[MT_BYTE_OFFSET(wqe_segment_data_ptr_st,local_address_h)>>2]= \r
984        (u_int32_t)(sg_lst_p[i].addr >> 32);\r
985      cur_loc_p[MT_BYTE_OFFSET(wqe_segment_data_ptr_st,local_address_l)>>2]= \r
986        (u_int32_t)(sg_lst_p[i].addr & 0xFFFFFFFF);\r
987    }\r
988    return (u_int32_t)(((MT_virt_addr_t)cur_loc_p) - ((MT_virt_addr_t)segment_p));\r
989 }\r
990 \r
991 /* Convert into Big Endian version */\r
992 inline static u_int32_t WQE_pack_sg_list_be(u_int32_t *segment_p,\r
993   u_int32_t sg_lst_len,VAPI_sg_lst_entry_t *sg_lst_p)\r
994 {\r
995    u_int32_t i;\r
996    u_int32_t *cur_loc_p= segment_p;\r
997    \r
998    for (i= 0; i < sg_lst_len; i++ , cur_loc_p+= WQE_SEG_SZ_SG_ENTRY_DW) {\r
999      cur_loc_p[DATA_PTR_BYTE_COUNT_DWORD_OFFSET]= \r
1000        MOSAL_cpu_to_be32((sg_lst_p[i].len & DATA_PTR_LEN_MASK ));\r
1001      cur_loc_p[DATA_PTR_LKEY_DWORD_OFFSET]= MOSAL_cpu_to_be32(sg_lst_p[i].lkey);\r
1002      cur_loc_p[DATA_PTR_LOCAL_ADDR_H_DWORD_OFFSET]= \r
1003        MOSAL_cpu_to_be32((u_int32_t)(sg_lst_p[i].addr >> 32));\r
1004      cur_loc_p[DATA_PTR_LOCAL_ADDR_L_DWORD_OFFSET]= \r
1005        MOSAL_cpu_to_be32((u_int32_t)(sg_lst_p[i].addr));\r
1006    }\r
1007    return (u_int32_t)(((MT_ulong_ptr_t)cur_loc_p) - ((MT_ulong_ptr_t)segment_p));\r
1008 }\r
1009 \r
1010 /* Build the WQE in given wqe_buf.\r
1011  * Return WQE size.\r
1012  */\r
1013 inline static u_int32_t WQE_build_send(\r
1014   THHUL_qp_t qp,\r
1015   VAPI_sr_desc_t *send_req_p,\r
1016   u_int32_t *wqe_buf)\r
1017 {\r
1018   u_int8_t *cur_loc_p= (u_int8_t*)wqe_buf; /* Current location in the WQE */\r
1019 \r
1020   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
1021   cur_loc_p+= WQE_pack_ctrl_send((u_int32_t*)cur_loc_p,  /* Pack Control segment */\r
1022     send_req_p->comp_type, send_req_p->set_se, 0/*event bit*/,\r
1023     ((send_req_p->opcode == VAPI_RDMA_WRITE_WITH_IMM) ||\r
1024      (send_req_p->opcode == VAPI_SEND_WITH_IMM) ) ? send_req_p->imm_data : 0);\r
1025 \r
1026   /* Transport type checks: Datagram segment */\r
1027   switch (qp->ts_type) {\r
1028     case VAPI_TS_UD:  /* Check if UD (UD datagram segment) */\r
1029       cur_loc_p+= WQE_pack_ud((u_int32_t*)cur_loc_p,\r
1030         qp->ud_av_memkey,translate_av(qp, (u_int64_t)send_req_p->remote_ah),\r
1031         send_req_p->remote_qp,send_req_p->remote_qkey);\r
1032       break;\r
1033     case VAPI_TS_RD:  /* Check if RD (RD datagram segment) */\r
1034       cur_loc_p+= WQE_pack_rd((u_int32_t*)cur_loc_p,\r
1035         send_req_p->remote_qp,send_req_p->remote_qkey);\r
1036       break;\r
1037     default:\r
1038       break;\r
1039   }\r
1040   \r
1041   /* Opcode checks Remote-address/Atomic segments */\r
1042   switch (send_req_p->opcode) {\r
1043     /* For RDMA operations: only Remote-address segment */\r
1044     case VAPI_RDMA_READ:\r
1045     case VAPI_RDMA_WRITE:\r
1046     case VAPI_RDMA_WRITE_WITH_IMM:\r
1047      cur_loc_p+= WQE_pack_remote_addr((u_int32_t*)cur_loc_p,\r
1048        send_req_p->remote_addr,send_req_p->r_key);\r
1049      break;\r
1050      \r
1051     /* Check if Atomic operations (both remote-address and Atomic segments) */\r
1052     case VAPI_ATOMIC_CMP_AND_SWP:\r
1053       cur_loc_p+= WQE_pack_remote_addr((u_int32_t*)cur_loc_p,send_req_p->remote_addr,\r
1054         send_req_p->r_key);\r
1055       cur_loc_p+= WQE_pack_atomic_cmpswp((u_int32_t*)cur_loc_p,send_req_p->compare_add,\r
1056         send_req_p->swap);\r
1057       break;\r
1058     case VAPI_ATOMIC_FETCH_AND_ADD:\r
1059      cur_loc_p+= WQE_pack_remote_addr((u_int32_t*)cur_loc_p,send_req_p->remote_addr,\r
1060        send_req_p->r_key);\r
1061      cur_loc_p+= WQE_pack_atomic_fetchadd((u_int32_t*)cur_loc_p,send_req_p->compare_add);\r
1062      break;\r
1063     default: /*NOP*/\r
1064       break;\r
1065   }\r
1066   \r
1067   /* Pack scatter/gather list segments */\r
1068   cur_loc_p+= WQE_pack_sg_list((u_int32_t*)cur_loc_p,send_req_p->sg_lst_len,send_req_p->sg_lst_p);\r
1069   \r
1070   return (u_int32_t)(((MT_virt_addr_t)cur_loc_p) - ((MT_virt_addr_t)wqe_buf));\r
1071 }\r
1072   \r
1073  \r
1074 /* Build Big Endian version of WQE_build_send\r
1075  * to remove extra copy from wqe_draft to wqe_buf.\r
1076  */\r
1077 inline static u_int32_t WQE_build_send_be(\r
1078   THHUL_qp_t qp,\r
1079   VAPI_sr_desc_t *send_req_p,\r
1080   u_int32_t *wqe_buf)\r
1081 {\r
1082   u_int8_t *cur_loc_p= (u_int8_t*)wqe_buf; /* Current location in the WQE */\r
1083 \r
1084   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
1085   cur_loc_p+= WQE_pack_ctrl_send_be((u_int32_t*)cur_loc_p,  /* Pack Control segment */\r
1086     send_req_p->comp_type, send_req_p->set_se, 0/*event bit*/,\r
1087     ((send_req_p->opcode == VAPI_RDMA_WRITE_WITH_IMM) ||\r
1088      (send_req_p->opcode == VAPI_SEND_WITH_IMM) ) ? send_req_p->imm_data : 0);\r
1089 \r
1090   /* Transport type checks: Datagram segment */\r
1091   switch (qp->ts_type) {\r
1092     case VAPI_TS_UD:  /* Check if UD (UD datagram segment) */\r
1093       cur_loc_p+= WQE_pack_ud_be((u_int32_t*)cur_loc_p,\r
1094         qp->ud_av_memkey,translate_av(qp, (u_int64_t)send_req_p->remote_ah),\r
1095         send_req_p->remote_qp,send_req_p->remote_qkey);\r
1096       break;\r
1097     case VAPI_TS_RD:  /* Check if RD (RD datagram segment) */\r
1098       cur_loc_p+= WQE_pack_rd_be((u_int32_t*)cur_loc_p,\r
1099         send_req_p->remote_qp,send_req_p->remote_qkey);\r
1100       break;\r
1101     default:\r
1102       break;\r
1103   }\r
1104   \r
1105   /* Opcode checks Remote-address/Atomic segments */\r
1106   switch (send_req_p->opcode) {\r
1107     /* For RDMA operations: only Remote-address segment */\r
1108     case VAPI_RDMA_READ:\r
1109     case VAPI_RDMA_WRITE:\r
1110     case VAPI_RDMA_WRITE_WITH_IMM:\r
1111      cur_loc_p+= WQE_pack_remote_addr_be((u_int32_t*)cur_loc_p,\r
1112        send_req_p->remote_addr,send_req_p->r_key);\r
1113      break;\r
1114      \r
1115     /* Check if Atomic operations (both remote-address and Atomic segments) */\r
1116     case VAPI_ATOMIC_CMP_AND_SWP:\r
1117       cur_loc_p+= WQE_pack_remote_addr_be((u_int32_t*)cur_loc_p,send_req_p->remote_addr,\r
1118         send_req_p->r_key);\r
1119       cur_loc_p+= WQE_pack_atomic_cmpswp_be((u_int32_t*)cur_loc_p,send_req_p->compare_add,\r
1120         send_req_p->swap);\r
1121       break;\r
1122     case VAPI_ATOMIC_FETCH_AND_ADD:\r
1123      cur_loc_p+= WQE_pack_remote_addr_be((u_int32_t*)cur_loc_p,send_req_p->remote_addr,\r
1124        send_req_p->r_key);\r
1125      cur_loc_p+= WQE_pack_atomic_fetchadd_be((u_int32_t*)cur_loc_p,send_req_p->compare_add);\r
1126      break;\r
1127     default: /*NOP*/\r
1128       break;\r
1129   }\r
1130   \r
1131   /* Pack scatter/gather list segments */\r
1132   if(MOSAL_EXPECT_FALSE(send_req_p->sg_lst_len == 0 || send_req_p->sg_lst_p->len == 0))\r
1133           return (u_int32_t)(((MT_ulong_ptr_t)cur_loc_p) - ((MT_ulong_ptr_t)wqe_buf));\r
1134 \r
1135   cur_loc_p+= WQE_pack_sg_list_be((u_int32_t*)cur_loc_p,send_req_p->sg_lst_len,send_req_p->sg_lst_p);\r
1136   \r
1137   return (u_int32_t)(((MT_ulong_ptr_t)cur_loc_p) - ((MT_ulong_ptr_t)wqe_buf));\r
1138 }\r
1139 \r
1140 \r
1141 \r
1142 /* This is optimized version of WQE_build_send \r
1143  * This fcuntion can eliminate extra code because req2 \r
1144  * ony support ReliableConnection and UnrliableDatagram.\r
1145  * sg_list and remote_addr build is done seperate fcuntion,\r
1146  * which use IbAccess structure directly. See thhul_qpm_iba.h\r
1147  */\r
1148 inline static u_int32_t* WQE_build_send_be_req2(\r
1149   THHUL_qp_t qp, \r
1150   u_int32_t *wqe_buf,\r
1151   VAPI_comp_type_t     comp_type,\r
1152   u_int64_t            remote_ah,\r
1153   IB_wqpn_t            remote_qp,\r
1154   IB_qkey_t            remote_qkey, \r
1155   MT_bool              set_se,\r
1156   u_int32_t            imm_data \r
1157   )\r
1158 {\r
1159   u_int8_t *cur_loc_p= (u_int8_t*)wqe_buf; /* Current location in the WQE */\r
1160 \r
1161   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
1162   cur_loc_p+= WQE_pack_ctrl_send_be((u_int32_t*)cur_loc_p,  /* Pack Control segment */\r
1163     comp_type, set_se, 0/*event bit*/,\r
1164     imm_data);\r
1165 \r
1166   /* Transport type checks: Datagram segment */\r
1167   /* Req2 suport only ReliableConnection and UnrliableDatagram */       \r
1168   if(MOSAL_EXPECT_FALSE(qp->ts_type == VAPI_TS_UD))\r
1169   {\r
1170         /* Check if UD (UD datagram segment) */\r
1171         cur_loc_p+= WQE_pack_ud_be((u_int32_t*)cur_loc_p,\r
1172                 qp->ud_av_memkey,translate_av(qp, (u_int64_t)remote_ah),\r
1173                 remote_qp,remote_qkey);\r
1174   }\r
1175   return (u_int32_t*)cur_loc_p;\r
1176 }\r
1177 \r
1178 \r
1179 \r
1180 /* This is optimized version of WQE_build_send \r
1181  * This function can eliminate extra code because req3 \r
1182  * ony support ReliableConnection and UnrliableDatagram.\r
1183  * sg_list and remote_addr build is done seperate fcuntion,\r
1184  * which use IBAL structure directly. See thhul_qpm_ibal.h\r
1185  */\r
1186 inline static u_int32_t* WQE_build_send_be_req3(\r
1187   THHUL_qp_t qp, \r
1188   u_int32_t *wqe_buf,\r
1189   VAPI_comp_type_t     comp_type,\r
1190   ib_send_wr_t                  *p_wr,\r
1191   MT_bool              set_se,\r
1192   u_int32_t            imm_data \r
1193   )\r
1194 {\r
1195   u_int8_t *cur_loc_p= (u_int8_t*)wqe_buf; /* Current location in the WQE */\r
1196 \r
1197   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
1198   cur_loc_p+= WQE_pack_ctrl_send_be((u_int32_t*)cur_loc_p,  /* Pack Control segment */\r
1199     comp_type, set_se, 0/*event bit*/,\r
1200     imm_data);\r
1201 \r
1202   /* Transport type checks: Datagram segment */\r
1203   /* Req3 suport only ReliableConnection and UnrliableDatagram */       \r
1204   if(MOSAL_EXPECT_FALSE(qp->ts_type == VAPI_TS_UD))\r
1205   {\r
1206         /* Check if UD (UD datagram segment) */\r
1207         cur_loc_p+= WQE_pack_ud_be((u_int32_t*)cur_loc_p,\r
1208                 qp->ud_av_memkey,\r
1209                         translate_av(qp, (u_int64_t)p_wr->dgrm.ud.h_av->h_av),\r
1210                 p_wr->dgrm.ud.remote_qp, p_wr->dgrm.ud.remote_qkey);\r
1211   }\r
1212   return (u_int32_t*)cur_loc_p;\r
1213 }\r
1214 \r
1215 \r
1216 /* Build UD header as inline data for management QPs over MLX "transport" */\r
1217 inline static u_int32_t WQE_pack_mlx_ud_header(u_int32_t *segment_p,\r
1218   THHUL_qp_t qp, VAPI_sr_desc_t *send_req_p, VAPI_ud_av_t *av_p, HH_hca_hndl_t hh_hndl,\r
1219   VAPI_pkey_ix_t pkey_index /* take this index instead of QP's, if not QP1_PKEY_INDEX */)\r
1220 {\r
1221   MPGA_headers_t *hdrs;\r
1222   IB_LRH_st *LRH_p;\r
1223   IB_BTH_st *BTH_p;\r
1224   IB_DETH_st *DETH_p;\r
1225   u_int8_t *hdrs_buf_p;\r
1226 #ifdef MT_LITTLE_ENDIAN\r
1227   u_int32_t *hdrs_buf32_p;  /* pointer for endiness swapping */\r
1228   u_int16_t i;\r
1229 #endif\r
1230   u_int16_t hdrs_sz;\r
1231   MT_bool global= av_p->grh_flag;\r
1232 #ifdef MT_KERNEL\r
1233   IB_port_t num_ports;\r
1234   IB_port_t port= (qp->qpn & 0xf);  /* QPN of QP used for port 1 has the even index */\r
1235   IB_pkey_t cur_pkey= 0;\r
1236   HH_ret_t rc;\r
1237   \r
1238   rc= THH_hob_get_num_ports(hh_hndl,&num_ports);\r
1239   if (rc != HH_OK) {\r
1240     MTL_ERROR1(MT_FLFMT("Could not get number of HCA ports (%s).\n"),HH_strerror_sym(rc));\r
1241     return 0;\r
1242   }\r
1243   port = (port >= num_ports) ? ((port-num_ports)%num_ports)+1 : (port % num_ports)+1;\r
1244 #endif\r
1245 \r
1246   hdrs_sz= IB_LRH_LEN+IB_BTH_LEN+IB_DETH_LEN;\r
1247   if (global)  hdrs_sz+= IB_GRH_LEN;\r
1248 \r
1249   /* Set inline entry control */\r
1250   *segment_p= ((1<<31) | hdrs_sz) ; /* inline entry | ByteCount */\r
1251   hdrs_buf_p= ((u_int8_t*)segment_p) + WQE_INLINE_SZ_BCOUNT /* inline ctrl */ + hdrs_sz;\r
1252 \r
1253   /* Put headers data into MPGA structures */  \r
1254   hdrs = &qp->sq_res.wqe_tmp->hdrs;\r
1255   if (global) {\r
1256     LRH_p= &(hdrs->MPGA_G_ud_send_only.IB_LRH);\r
1257     BTH_p= &(hdrs->MPGA_G_ud_send_only.IB_BTH);\r
1258     DETH_p= &(hdrs->MPGA_G_ud_send_only.IB_DETH);\r
1259     /* Set GRH fields */\r
1260     hdrs->MPGA_G_ud_send_only.IB_GRH.IPVer= 6; /* ? */\r
1261     hdrs->MPGA_G_ud_send_only.IB_GRH.TClass= av_p->traffic_class;\r
1262     hdrs->MPGA_G_ud_send_only.IB_GRH.FlowLabel= av_p->flow_label;\r
1263     hdrs->MPGA_G_ud_send_only.IB_GRH.PayLen= IB_BTH_LEN+IB_DETH_LEN+IB_MAD_LEN+IB_ICRC_SZ;\r
1264     hdrs->MPGA_G_ud_send_only.IB_GRH.NxtHdr= 0x1B; /* IB-spec.: compliancy statement C8-7 */\r
1265     hdrs->MPGA_G_ud_send_only.IB_GRH.HopLmt= av_p->hop_limit; \r
1266     memcpy(&(hdrs->MPGA_G_ud_send_only.IB_GRH.DGID),&(av_p->dgid),sizeof(IB_gid_t));\r
1267 #ifdef MT_KERNEL\r
1268     /* SGID field is supported only in kernel space, due to limited access to the GID table */\r
1269     rc= THH_hob_get_sgid(hh_hndl,port,av_p->sgid_index,\r
1270       &(hdrs->MPGA_G_ud_send_only.IB_GRH.SGID));\r
1271     if (rc != HH_OK) {\r
1272       MTL_ERROR1(MT_FLFMT("Error in GID table access (%s).\n"),HH_strerror_sym(rc));\r
1273       return 0;\r
1274     }\r
1275 #endif\r
1276 \r
1277   } else {  /* local - no GRH */\r
1278     LRH_p= &(hdrs->MPGA_ud_send_only.IB_LRH);\r
1279     BTH_p= &(hdrs->MPGA_ud_send_only.IB_BTH);\r
1280     DETH_p= &(hdrs->MPGA_ud_send_only.IB_DETH);\r
1281   }\r
1282   \r
1283   /* Set LRH fields */\r
1284   memset(LRH_p,0,sizeof(IB_LRH_st));\r
1285   /* VL must be set for internal loopback ("vl15" bit is ignored) */\r
1286   if (qp->sqp_type == VAPI_SMI_QP) LRH_p->VL= 15;\r
1287   else LRH_p->VL= 0;\r
1288   LRH_p->LVer= 0;\r
1289   LRH_p->SL= av_p->sl;\r
1290   LRH_p->LNH= global ? IBA_GLOBAL : IBA_LOCAL;\r
1291 \r
1292   LRH_p->DLID= av_p->dlid;\r
1293   LRH_p->SLID= (av_p->dlid == PERMIS_LID) ? PERMIS_LID : (IB_lid_t) av_p->src_path_bits;\r
1294   /* If DLID is permissive LID, we set SLID to the permissive LID too. */\r
1295   /* Otherwise, we put in the SLID field the source path bits, and SLR=0, so */ \r
1296   /*   the LID is composed of actual port's LID concatenated with given path bits */\r
1297 \r
1298   LRH_p->PktLen= (hdrs_sz+IB_MAD_LEN + IB_ICRC_SZ) >> 2;\r
1299   /* Set BTH fields */\r
1300   memset(BTH_p,0,sizeof(IB_BTH_st));\r
1301   BTH_p->OpCode= UD_SEND_ONLY_OP;\r
1302   BTH_p->SE= send_req_p->set_se;\r
1303   BTH_p->M= 1;\r
1304   BTH_p->PadCnt= 0; /* MADs are always 4byte multiple */\r
1305   BTH_p->TVer= 0; \r
1306 #ifdef MT_KERNEL\r
1307   if (qp->sqp_type == VAPI_GSI_QP) {\r
1308     if (pkey_index == QP1_PKEY_INDEX) { /* use QP's pkey */\r
1309       rc= THH_hob_get_qp1_pkey(hh_hndl,port,&cur_pkey);\r
1310     } else {\r
1311       rc= THH_hob_get_pkey(hh_hndl,port,pkey_index,&cur_pkey);\r
1312     }\r
1313     if (rc != HH_OK) {\r
1314       MTL_ERROR1(MT_FLFMT("%s: Error in P-key table access (%s) - using pkey_index 0x%X.\n"),__func__,\r
1315                  HH_strerror_sym(rc),pkey_index);\r
1316       return 0;\r
1317     }\r
1318   } else {\r
1319       cur_pkey = DEFAULT_PKEY;\r
1320   }\r
1321   BTH_p->P_KEY= cur_pkey; \r
1322 #else\r
1323   BTH_p->P_KEY= DEFAULT_PKEY; /* For user space we do not have access to the Pkey table */\r
1324 #endif\r
1325   BTH_p->DestQP= send_req_p->remote_qp;\r
1326   /* AckReq and PSN are meaningless for UD */\r
1327   /* Set DETH fields */\r
1328   memset(DETH_p,0,sizeof(IB_DETH_st));\r
1329   DETH_p->SrcQP= (qp->sqp_type == VAPI_SMI_QP) ? 0 : 1; /* invoked only for SMI or GSI */ \r
1330   /* Qkey should be set according to IB-Spec. compliancy statement C10-15, But...      \r
1331    * Only QP1/GSI is the special QP which really validates Q-keys and it always uses\r
1332    * 0x80010000 (C9-49). So for QP1 we always put this if the high-order bit of the Qkey\r
1333    * is set.                                                                             */\r
1334   if (qp->sqp_type == VAPI_GSI_QP) {\r
1335     DETH_p->Q_Key= (send_req_p->remote_qkey & 0x80000000) ? 0x80010000: send_req_p->remote_qkey;\r
1336   } else { /* QP0 */\r
1337     /* For QP0 we don't care (QP0 always sends to another QP0 - none of which validates the Qkey) */\r
1338     DETH_p->Q_Key= send_req_p->remote_qkey; \r
1339   }\r
1340 \r
1341   /* Build the headers */\r
1342   if (MPGA_make_headers(hdrs,UD_SEND_ONLY_OP,\r
1343                         LRH_p->LNH,FALSE,IB_MAD_LEN,&hdrs_buf_p) != MT_OK) {\r
1344     return 0;\r
1345   }\r
1346   /* Verify headers size */\r
1347   if (hdrs_buf_p != (((u_int8_t*)segment_p) + WQE_INLINE_SZ_BCOUNT)) {/*Should be segment begin*/\r
1348     MTL_ERROR2(MT_FLFMT("Error in headers size (%d instead of %d).\n"),\r
1349      (unsigned) (hdrs_sz - (hdrs_buf_p - (((u_int8_t*)segment_p) + 4))), hdrs_sz);\r
1350     return 0;\r
1351   }\r
1352 \r
1353 #ifdef MT_LITTLE_ENDIAN\r
1354   /* MPGA headers returned in BIG endian.  WQE is built in CPU endianess  - so swap bytes */\r
1355   for (i= 0 , hdrs_buf32_p= (u_int32_t*)hdrs_buf_p; i < (hdrs_sz>>2); i++) {\r
1356     hdrs_buf32_p[i]= MOSAL_cpu_to_be32(hdrs_buf32_p[i]);\r
1357   }\r
1358 #endif\r
1359 \r
1360   return MT_UP_ALIGNX_U32(WQE_INLINE_SZ_BCOUNT + hdrs_sz , 4);  /* Align to WQE segment size */\r
1361 }\r
1362 \r
1363 /* Build UD header as inline data for management QPs over MLX "transport" */\r
1364 inline static u_int32_t WQE_pack_mlx_ud_header2(u_int32_t *segment_p,\r
1365   THHUL_qp_t qp, ib_send_wr_t* p_wr, VAPI_ud_av_t *av_p, HH_hca_hndl_t hh_hndl,\r
1366   VAPI_pkey_ix_t pkey_index /* take this index instead of QP's, if not QP1_PKEY_INDEX */)\r
1367 {\r
1368   MPGA_headers_t *hdrs;\r
1369   IB_LRH_st *LRH_p;\r
1370   IB_BTH_st *BTH_p;\r
1371   IB_DETH_st *DETH_p;\r
1372   u_int8_t *hdrs_buf_p;\r
1373 #ifdef MT_LITTLE_ENDIAN\r
1374   u_int32_t *hdrs_buf32_p;  /* pointer for endiness swapping */\r
1375   u_int16_t i;\r
1376 #endif\r
1377   u_int16_t hdrs_sz;\r
1378   MT_bool global= av_p->grh_flag;\r
1379 #ifdef MT_KERNEL\r
1380   IB_port_t port= 1 + (qp->qpn & 1);  /* QPN of QP used for port 1 has the even index */\r
1381   IB_pkey_t cur_pkey= 0;\r
1382   HH_ret_t rc;\r
1383 #endif\r
1384 \r
1385   hdrs_sz= IB_LRH_LEN+IB_BTH_LEN+IB_DETH_LEN;\r
1386   if (global)  hdrs_sz+= IB_GRH_LEN;\r
1387 \r
1388   /* Set inline entry control */\r
1389   *segment_p= ((1<<31) | hdrs_sz) ; /* inline entry | ByteCount */\r
1390   hdrs_buf_p= ((u_int8_t*)segment_p) + WQE_INLINE_SZ_BCOUNT /* inline ctrl */ + hdrs_sz;\r
1391 \r
1392   /* Put headers data into MPGA structures */  \r
1393   hdrs = &qp->sq_res.wqe_tmp->hdrs;\r
1394   if (global) {\r
1395     LRH_p= &(hdrs->MPGA_G_ud_send_only.IB_LRH);\r
1396     BTH_p= &(hdrs->MPGA_G_ud_send_only.IB_BTH);\r
1397     DETH_p= &(hdrs->MPGA_G_ud_send_only.IB_DETH);\r
1398     /* Set GRH fields */\r
1399     hdrs->MPGA_G_ud_send_only.IB_GRH.IPVer= 6; /* ? */\r
1400     hdrs->MPGA_G_ud_send_only.IB_GRH.TClass= av_p->traffic_class;\r
1401     hdrs->MPGA_G_ud_send_only.IB_GRH.FlowLabel= av_p->flow_label;\r
1402     hdrs->MPGA_G_ud_send_only.IB_GRH.PayLen= IB_BTH_LEN+IB_DETH_LEN+IB_MAD_LEN+IB_ICRC_SZ;\r
1403     hdrs->MPGA_G_ud_send_only.IB_GRH.NxtHdr= 0x1B; /* IB-spec.: compliancy statement C8-7 */\r
1404     hdrs->MPGA_G_ud_send_only.IB_GRH.HopLmt= av_p->hop_limit; \r
1405     memcpy(&(hdrs->MPGA_G_ud_send_only.IB_GRH.DGID),&(av_p->dgid),sizeof(IB_gid_t));\r
1406 #ifdef MT_KERNEL\r
1407     /* SGID field is supported only in kernel space, due to limited access to the GID table */\r
1408     rc= THH_hob_get_sgid(hh_hndl,port,av_p->sgid_index,\r
1409       &(hdrs->MPGA_G_ud_send_only.IB_GRH.SGID));\r
1410     if (rc != HH_OK) {\r
1411       MTL_ERROR1(MT_FLFMT("Error in GID table access (%s).\n"),HH_strerror_sym(rc));\r
1412       return 0;\r
1413     }\r
1414 #endif\r
1415 \r
1416   } else {  /* local - no GRH */\r
1417     LRH_p= &(hdrs->MPGA_ud_send_only.IB_LRH);\r
1418     BTH_p= &(hdrs->MPGA_ud_send_only.IB_BTH);\r
1419     DETH_p= &(hdrs->MPGA_ud_send_only.IB_DETH);\r
1420   }\r
1421   \r
1422   /* Set LRH fields */\r
1423   memset(LRH_p,0,sizeof(IB_LRH_st));\r
1424   /* VL must be set for internal loopback ("vl15" bit is ignored) */\r
1425   if (qp->sqp_type == VAPI_SMI_QP) LRH_p->VL= 15;\r
1426   else LRH_p->VL= 0;\r
1427   LRH_p->LVer= 0;\r
1428   LRH_p->SL= av_p->sl;\r
1429   LRH_p->LNH= global ? IBA_GLOBAL : IBA_LOCAL;\r
1430 \r
1431   LRH_p->DLID= av_p->dlid;\r
1432   LRH_p->SLID= (av_p->dlid == PERMIS_LID) ? PERMIS_LID : (IB_lid_t) av_p->src_path_bits;\r
1433   /* If DLID is permissive LID, we set SLID to the permissive LID too. */\r
1434   /* Otherwise, we put in the SLID field the source path bits, and SLR=0, so */ \r
1435   /*   the LID is composed of actual port's LID concatenated with given path bits */\r
1436 \r
1437   LRH_p->PktLen= (hdrs_sz+IB_MAD_LEN + IB_ICRC_SZ) >> 2;\r
1438   /* Set BTH fields */\r
1439   memset(BTH_p,0,sizeof(IB_BTH_st));\r
1440   BTH_p->OpCode= UD_SEND_ONLY_OP;\r
1441   BTH_p->SE= ((p_wr->send_opt & IB_SEND_OPT_SOLICITED) == IB_SEND_OPT_SOLICITED);\r
1442   BTH_p->M= 1;\r
1443   BTH_p->PadCnt= 0; /* MADs are always 4byte multiple */\r
1444   BTH_p->TVer= 0; \r
1445 #ifdef MT_KERNEL\r
1446   if (qp->sqp_type == VAPI_GSI_QP) {\r
1447     if (pkey_index == QP1_PKEY_INDEX) { /* use QP's pkey */\r
1448       rc= THH_hob_get_qp1_pkey(hh_hndl,port,&cur_pkey);\r
1449     } else {\r
1450       rc= THH_hob_get_pkey(hh_hndl,port,pkey_index,&cur_pkey);\r
1451     }\r
1452     if (rc != HH_OK) {\r
1453       MTL_ERROR1(MT_FLFMT("%s: Error in P-key table access (%s) - using pkey_index 0x%X.\n"),__func__,\r
1454                  HH_strerror_sym(rc),pkey_index);\r
1455       return 0;\r
1456     }\r
1457   } else {\r
1458       cur_pkey = DEFAULT_PKEY;\r
1459   }\r
1460   BTH_p->P_KEY= cur_pkey; \r
1461 #else\r
1462   BTH_p->P_KEY= DEFAULT_PKEY; /* For user space we do not have access to the Pkey table */\r
1463 #endif\r
1464   BTH_p->DestQP= cl_hton32( p_wr->dgrm.ud.remote_qp );\r
1465   /* AckReq and PSN are meaningless for UD */\r
1466   /* Set DETH fields */\r
1467   memset(DETH_p,0,sizeof(IB_DETH_st));\r
1468   DETH_p->SrcQP= (qp->sqp_type == VAPI_SMI_QP) ? 0 : 1; /* invoked only for SMI or GSI */ \r
1469   /* Qkey should be set according to IB-Spec. compliancy statement C10-15, But...      \r
1470    * Only QP1/GSI is the special QP which really validates Q-keys and it always uses\r
1471    * 0x80010000 (C9-49). So for QP1 we always put this if the high-order bit of the Qkey\r
1472    * is set.                                                                             */\r
1473   if( (qp->sqp_type == VAPI_GSI_QP) && (p_wr->dgrm.ud.remote_qkey & CL_HTON32(0x80000000)) )\r
1474   {\r
1475     DETH_p->Q_Key= 0x80010000;\r
1476   } else { /* QP0, or QKEY is not well known GSI QKEY */\r
1477     /* For QP0 we don't care (QP0 always sends to another QP0 - none of which validates the Qkey) */\r
1478     DETH_p->Q_Key= cl_hton32( p_wr->dgrm.ud.remote_qkey ); \r
1479   }\r
1480 \r
1481   /* Build the headers */\r
1482   if (MPGA_make_headers(hdrs,UD_SEND_ONLY_OP,\r
1483                         LRH_p->LNH,FALSE,IB_MAD_LEN,&hdrs_buf_p) != MT_OK) {\r
1484     return 0;\r
1485   }\r
1486   /* Verify headers size */\r
1487   if (hdrs_buf_p != (((u_int8_t*)segment_p) + WQE_INLINE_SZ_BCOUNT)) {/*Should be segment begin*/\r
1488     MTL_ERROR2(MT_FLFMT("Error in headers size (%d instead of %d).\n"),\r
1489      (unsigned) (hdrs_sz - (hdrs_buf_p - (((u_int8_t*)segment_p) + 4))), hdrs_sz);\r
1490     return 0;\r
1491   }\r
1492 \r
1493 #ifdef MT_LITTLE_ENDIAN\r
1494   /* MPGA headers returned in BIG endian.  WQE is built in CPU endianess  - so swap bytes */\r
1495   for (i= 0 , hdrs_buf32_p= (u_int32_t*)hdrs_buf_p; i < (hdrs_sz>>2); i++) {\r
1496     hdrs_buf32_p[i]= MOSAL_cpu_to_be32(hdrs_buf32_p[i]);\r
1497   }\r
1498 #endif\r
1499 \r
1500   return MT_UP_ALIGNX_U32(WQE_INLINE_SZ_BCOUNT + hdrs_sz , 4);  /* Align to WQE segment size */\r
1501 }\r
1502   \r
1503 /* Build ICRC segment for MLX (UD) */\r
1504 inline static u_int32_t WQE_pack_mlx_icrc_hw(u_int32_t *segment_p)\r
1505 {\r
1506   segment_p[0]= (1<<31) | 4 ; /* Inline ICRC (32 bits = 4 bytes) */\r
1507   segment_p[1]= 0;            /* Hardware generated ICRC */\r
1508   /* 2 dwords padded for a single Inline Data segment */\r
1509   return WQE_INLINE_ICRC;\r
1510 }\r
1511 \r
1512 /* Build ICRC segment for MLX (UD) */\r
1513 inline static u_int32_t WQE_pack_mlx_icrc_hw_be(u_int32_t *segment_p)\r
1514 {\r
1515   segment_p[0]= MOSAL_cpu_to_be32( (1<<31) | 4 ); /* Inline ICRC (32 bits = 4 bytes) */\r
1516   segment_p[1]= 0;            /* Hardware generated ICRC */\r
1517   /* 2 dwords padded for a single Inline Data segment */\r
1518   return WQE_INLINE_ICRC;\r
1519 }\r
1520 \r
1521 /* Pack Control segment (for mlx-sends) */\r
1522 inline static u_int32_t WQE_pack_ctrl_mlx(u_int32_t *segment_p,  \r
1523     VAPI_comp_type_t comp_type, MT_bool event_bit,\r
1524     IB_sl_t sl, IB_static_rate_t max_statrate, MT_bool slr, MT_bool v15,\r
1525     u_int16_t vcrc, IB_lid_t rlid)\r
1526 {\r
1527   memset(segment_p,0,WQE_SEG_SZ_CTRL);  /* Clear all "RESERVED" */\r
1528   MT_INSERT_ARRAY32(segment_p,(comp_type == VAPI_SIGNALED) ? 1 : 0,\r
1529     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,c),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,c));\r
1530   MT_INSERT_ARRAY32(segment_p,event_bit ? 1 : 0,\r
1531     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,e),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,e));\r
1532   MT_INSERT_ARRAY32(segment_p,sl,\r
1533     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,sl),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,sl));\r
1534   MT_INSERT_ARRAY32(segment_p,max_statrate > 0 ? 1 : 0,\r
1535     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,max_statrate),\r
1536     MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,max_statrate));\r
1537   MT_INSERT_ARRAY32(segment_p,slr ? 1 : 0,\r
1538     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,slr),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,slr));\r
1539   MT_INSERT_ARRAY32(segment_p,v15 ? 1 : 0,\r
1540     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,v15),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,v15));\r
1541   MT_INSERT_ARRAY32(segment_p,vcrc,\r
1542     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,vcrc),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,vcrc));\r
1543   MT_INSERT_ARRAY32(segment_p,rlid,\r
1544     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,rlid),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,rlid));\r
1545   return WQE_SEG_SZ_CTRL;\r
1546 }\r
1547 \r
1548 /* Pack Control segment (for mlx-sends) */\r
1549 inline static u_int32_t WQE_pack_ctrl_mlx_be(u_int32_t *segment_p,  \r
1550     VAPI_comp_type_t comp_type, MT_bool event_bit,\r
1551     IB_sl_t sl, IB_static_rate_t max_statrate, MT_bool slr, MT_bool v15,\r
1552     u_int16_t vcrc, IB_lid_t rlid)\r
1553 {\r
1554   memset(segment_p,0,WQE_SEG_SZ_CTRL);  /* Clear all "RESERVED" */\r
1555   MT_INSERT_ARRAY32_BE(segment_p,(comp_type == VAPI_SIGNALED) ? 1 : 0,\r
1556     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,c),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,c));\r
1557   MT_INSERT_ARRAY32_BE(segment_p,event_bit ? 1 : 0,\r
1558     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,e),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,e));\r
1559   MT_INSERT_ARRAY32_BE(segment_p,sl,\r
1560     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,sl),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,sl));\r
1561   MT_INSERT_ARRAY32_BE(segment_p,max_statrate > 0 ? 1 : 0,\r
1562     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,max_statrate),\r
1563     MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,max_statrate));\r
1564   MT_INSERT_ARRAY32_BE(segment_p,slr ? 1 : 0,\r
1565     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,slr),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,slr));\r
1566   MT_INSERT_ARRAY32_BE(segment_p,v15 ? 1 : 0,\r
1567     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,v15),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,v15));\r
1568   MT_INSERT_ARRAY32_BE(segment_p,vcrc,\r
1569     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,vcrc),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,vcrc));\r
1570   MT_INSERT_ARRAY32_BE(segment_p,rlid,\r
1571     MT_BIT_OFFSET(wqe_segment_ctrl_mlx_st,rlid),MT_BIT_SIZE(wqe_segment_ctrl_mlx_st,rlid));\r
1572   return WQE_SEG_SZ_CTRL;\r
1573 }\r
1574 \r
1575 inline static u_int32_t WQE_build_send_mlx(\r
1576   HH_hca_hndl_t hh_hndl,\r
1577   THHUL_qp_t qp,\r
1578   VAPI_sr_desc_t *send_req_p,\r
1579   VAPI_pkey_ix_t pkey_index, /* take this index instead of QP's, if not QP1_PKEY_INDEX */\r
1580   u_int32_t *wqe_buf\r
1581 )  \r
1582 {\r
1583   \r
1584   VAPI_ud_av_t *av = &qp->sq_res.wqe_tmp->av;\r
1585   u_int8_t *cur_loc_p= (u_int8_t*)wqe_buf; /* Current location in the WQE */\r
1586   u_int8_t *prev_loc_p;\r
1587   HH_ret_t rc;\r
1588 \r
1589   rc= THH_udavm_parse_udav_entry((u_int32_t*)(send_req_p->remote_ah),av);\r
1590   if (rc != HH_OK) {\r
1591     MTL_ERROR1(MT_FLFMT("Invalid UD AV handle - %s"),\r
1592       HH_strerror_sym(rc));\r
1593     return 0;\r
1594   }\r
1595 \r
1596    \r
1597   if ((av->dlid == PERMIS_LID) && (qp->sqp_type != VAPI_SMI_QP)) {\r
1598     MTL_ERROR1(MT_FLFMT("DLID==Permissive-LID while not an SMI QP.\n"));\r
1599     return 0;\r
1600   }\r
1601 \r
1602   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
1603   cur_loc_p+= WQE_pack_ctrl_mlx((u_int32_t*)cur_loc_p,  /* Pack Control segment */\r
1604     send_req_p->comp_type, FALSE/*event bit*/,\r
1605     av->sl,av->static_rate,(av->dlid == PERMIS_LID),(qp->sqp_type == VAPI_SMI_QP),\r
1606     0/*VCRC*/,av->dlid);\r
1607     \r
1608     \r
1609   /* Build inline headers */\r
1610   switch (qp->sqp_type) {\r
1611     case VAPI_SMI_QP:  \r
1612     case VAPI_GSI_QP:  \r
1613       prev_loc_p= cur_loc_p;\r
1614       cur_loc_p+= WQE_pack_mlx_ud_header((u_int32_t*)cur_loc_p,qp,send_req_p,av,hh_hndl,pkey_index);\r
1615       if (cur_loc_p == prev_loc_p) {\r
1616         return 0;\r
1617       }\r
1618       /* Pack scatter/gather list segments */\r
1619       cur_loc_p+= WQE_pack_sg_list((u_int32_t*)cur_loc_p,send_req_p->sg_lst_len,send_req_p->sg_lst_p);\r
1620       cur_loc_p+= WQE_pack_mlx_icrc_hw((u_int32_t*)cur_loc_p);\r
1621       break;\r
1622     case VAPI_RAW_ETY_QP:\r
1623     case VAPI_RAW_IPV6_QP:\r
1624     default:\r
1625       return 0;\r
1626   }\r
1627   \r
1628   return (u_int32_t)(((MT_virt_addr_t)cur_loc_p) - ((MT_virt_addr_t)wqe_buf));\r
1629 }\r
1630 \r
1631 #ifdef WIN32\r
1632 #include "thhul_qpm_ibal.h"\r
1633 \r
1634 inline static u_int32_t WQE_build_send_mlx2_be(\r
1635         IN                              HH_hca_hndl_t                           hh_hndl,\r
1636         IN                              THHUL_qp_t                                      qp,\r
1637         IN                              ib_send_wr_t                            *p_wr,\r
1638         IN                              VAPI_pkey_ix_t                          pkey_index, /* take this index instead of QP's, if not QP1_PKEY_INDEX */\r
1639         IN      OUT                     u_int32_t                                       *wqe_buf )\r
1640 {\r
1641         VAPI_ud_av_t *av = &qp->sq_res.wqe_tmp->av;\r
1642         u_int8_t *cur_loc_p = (u_int8_t*)wqe_buf; /* Current location in the WQE */\r
1643         u_int8_t *prev_loc_p;\r
1644         HH_ret_t rc;\r
1645 \r
1646         rc= THH_udavm_parse_udav_entry((u_int32_t*)(p_wr->dgrm.ud.h_av->h_av),av);\r
1647         if (rc != HH_OK) {\r
1648                 MTL_ERROR1(MT_FLFMT("Invalid UD AV handle - %s"),\r
1649                         HH_strerror_sym(rc));\r
1650                 return 0;\r
1651         }\r
1652 \r
1653         if ((av->dlid == PERMIS_LID) && (qp->sqp_type != VAPI_SMI_QP)) {\r
1654                 MTL_ERROR1(MT_FLFMT("DLID==Permissive-LID while not an SMI QP.\n"));\r
1655                 return 0;\r
1656         }\r
1657 \r
1658         cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
1659         cur_loc_p+= WQE_pack_ctrl_mlx_be((u_int32_t*)cur_loc_p,  /* Pack Control segment */\r
1660                 (p_wr->send_opt & IB_SEND_OPT_SIGNALED)? VAPI_SIGNALED : VAPI_UNSIGNALED,\r
1661                 FALSE/*event bit*/,av->sl,av->static_rate,(av->dlid == PERMIS_LID),\r
1662                 (qp->sqp_type == VAPI_SMI_QP),0/*VCRC*/,av->dlid);\r
1663 \r
1664         /* Build inline headers */\r
1665         switch( qp->sqp_type )\r
1666         {\r
1667         case VAPI_SMI_QP:  \r
1668         case VAPI_GSI_QP:  \r
1669                 prev_loc_p= cur_loc_p;\r
1670                 cur_loc_p+= WQE_pack_mlx_ud_header2((u_int32_t*)cur_loc_p,qp,p_wr,av,hh_hndl,pkey_index);\r
1671                 if (cur_loc_p == prev_loc_p) {\r
1672                         return 0;\r
1673                 }\r
1674 \r
1675                 /* Swap UD header into big-endian. */\r
1676                 for( prev_loc_p; prev_loc_p != cur_loc_p; prev_loc_p += 4 )\r
1677                         *(uint32_t*)prev_loc_p = MOSAL_cpu_to_be32( *(uint32_t*)prev_loc_p );\r
1678                 \r
1679                 /* Pack scatter/gather list segments in BE format */\r
1680                 if( p_wr->send_opt & IB_SEND_OPT_INLINE )\r
1681                 {\r
1682                         if( WQE_pack_inline_sgl_ibal(\r
1683                                 p_wr, &(uint32_t*)cur_loc_p, qp->sq_res.max_inline_data ) != HH_OK )\r
1684                         {\r
1685                                 return 0;\r
1686                         }\r
1687                 }\r
1688                 else\r
1689                 {\r
1690                         WQE_pack_sgl_ibal( p_wr, &(uint32_t*)cur_loc_p );\r
1691                 }\r
1692                 cur_loc_p+= WQE_pack_mlx_icrc_hw_be((u_int32_t*)cur_loc_p);\r
1693                 break;\r
1694         case VAPI_RAW_ETY_QP:\r
1695         case VAPI_RAW_IPV6_QP:\r
1696         default:\r
1697                 return 0;\r
1698         }\r
1699 \r
1700         return (u_int32_t)(((MT_virt_addr_t)cur_loc_p) - ((MT_virt_addr_t)wqe_buf));\r
1701 }\r
1702 #endif\r
1703 \r
1704 \r
1705 /* Pack Control segment (for receive work requests) */\r
1706 inline static u_int32_t qpm_WQE_pack_ctrl_recv(u_int32_t *segment_p,  \r
1707     VAPI_comp_type_t comp_type, u_int32_t event_bit)\r
1708 {\r
1709   memset(segment_p,0,WQE_SEG_SZ_CTRL);  /* Clear all "RESERVED" */\r
1710   MT_INSERT_ARRAY32(segment_p,(comp_type == VAPI_SIGNALED) ? 1 : 0,\r
1711     MT_BIT_OFFSET(wqe_segment_ctrl_recv_st,c),MT_BIT_SIZE(wqe_segment_ctrl_recv_st,c));\r
1712   MT_INSERT_ARRAY32(segment_p,event_bit,\r
1713     MT_BIT_OFFSET(wqe_segment_ctrl_recv_st,e),MT_BIT_SIZE(wqe_segment_ctrl_recv_st,e));\r
1714   return WQE_SEG_SZ_CTRL;\r
1715 }\r
1716 \r
1717 /* Optimized version of WQE_pack_ctrl_recv\r
1718  * remove memset and precalculate offset\r
1719  */\r
1720 #define CTRL_RECV_C_DWORD_OFFSET        MT_BYTE_OFFSET(wqe_segment_ctrl_recv_st,c)>>2\r
1721 #define CTRL_RECV_RESERVED2_DWORD_OFFSET MT_BYTE_OFFSET(wqe_segment_ctrl_recv_st,reserved2)>>2  \r
1722         \r
1723 #define CTRL_RECV_C_BIT_OFFSET          MT_BIT_OFFSET(wqe_segment_ctrl_recv_st,c)\r
1724 #define CTRL_RECV_E_BIT_OFFSET          MT_BIT_OFFSET(wqe_segment_ctrl_recv_st,e)\r
1725 /* Convert into Big Endian version */\r
1726 inline static u_int32_t WQE_pack_ctrl_recv_be(u_int32_t *segment_p,  \r
1727     VAPI_comp_type_t comp_type, u_int32_t event_bit)\r
1728 {\r
1729         \r
1730   segment_p[CTRL_RECV_RESERVED2_DWORD_OFFSET] = 0;\r
1731   segment_p[CTRL_RECV_C_DWORD_OFFSET] =  MOSAL_cpu_to_be32(0\r
1732                   | (((comp_type == VAPI_SIGNALED) ? 1 : 0) << CTRL_RECV_C_BIT_OFFSET)\r
1733                   | ( event_bit << CTRL_RECV_E_BIT_OFFSET)\r
1734                   );\r
1735                   \r
1736   return WQE_SEG_SZ_CTRL;\r
1737 }\r
1738 \r
1739 inline static u_int32_t qpm_WQE_build_recv(\r
1740   THHUL_qp_t qp,\r
1741   VAPI_rr_desc_t *recv_req_p,\r
1742   u_int32_t *wqe_buf\r
1743 )\r
1744 {\r
1745   u_int8_t *cur_loc_p= (u_int8_t*)wqe_buf; /* Current location in the WQE */\r
1746 \r
1747   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
1748   cur_loc_p+= qpm_WQE_pack_ctrl_recv((u_int32_t*)cur_loc_p,\r
1749     recv_req_p->comp_type, 0/*event bit*/);\r
1750   /* Pack scatter/gather list segments */\r
1751   cur_loc_p+= WQE_pack_sg_list((u_int32_t*)cur_loc_p,recv_req_p->sg_lst_len,recv_req_p->sg_lst_p);\r
1752   \r
1753   return (u_int32_t)(((MT_virt_addr_t)cur_loc_p) - ((MT_virt_addr_t)wqe_buf));\r
1754 }\r
1755 \r
1756 /* Build Big Endian version of WQE_build_recv to remove extra copy\r
1757  * from draft. Optimized version of post_send_recv use wqe_buf directly, so\r
1758  * should build big endian verison to wqe_buf\r
1759  */\r
1760 inline static u_int32_t WQE_build_recv_be(\r
1761   THHUL_qp_t qp,\r
1762   VAPI_rr_desc_t *recv_req_p,\r
1763   u_int32_t *wqe_buf\r
1764 )\r
1765 {\r
1766   u_int8_t *cur_loc_p= (u_int8_t*)wqe_buf; /* Current location in the WQE */\r
1767 \r
1768   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
1769   cur_loc_p+= WQE_pack_ctrl_recv_be((u_int32_t*)cur_loc_p,\r
1770     recv_req_p->comp_type, 0/*event bit*/);\r
1771   /* Pack scatter/gather list segments */\r
1772   cur_loc_p+= WQE_pack_sg_list_be((u_int32_t*)cur_loc_p,recv_req_p->sg_lst_len,recv_req_p->sg_lst_p);\r
1773   \r
1774   return (u_int32_t)(((MT_ulong_ptr_t)cur_loc_p) - ((MT_ulong_ptr_t)wqe_buf));\r
1775 }\r
1776 \r
1777 \r
1778 /* This is for post_send_recv2. sg_list buld directly from IbAccess structure.\r
1779  */\r
1780 inline static u_int32_t *WQE_build_recv_be_req2(\r
1781   THHUL_qp_t qp,\r
1782   u_int32_t *wqe_buf,\r
1783   VAPI_comp_type_t comp_type\r
1784 )\r
1785 {\r
1786   u_int8_t *cur_loc_p= (u_int8_t*)wqe_buf; /* Current location in the WQE */\r
1787 \r
1788   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
1789   cur_loc_p+= WQE_pack_ctrl_recv_be((u_int32_t*)cur_loc_p,\r
1790     comp_type, 0/*event bit*/);\r
1791   \r
1792   return (u_int32_t *)cur_loc_p;\r
1793 }\r
1794 \r
1795 \r
1796 inline static u_int32_t WQE_build_membind(\r
1797   HHUL_mw_bind_t *bind_props_p,\r
1798   IB_rkey_t new_rkey,\r
1799   u_int32_t *wqe_buf\r
1800 )\r
1801 {\r
1802   u_int32_t *cur_loc_p= wqe_buf; /* Current location in the WQE */\r
1803 \r
1804   cur_loc_p+= (qpm_WQE_init_next((u_int32_t*)cur_loc_p)>>2);  /* Make "unlinked" "next" segment */\r
1805   cur_loc_p+= (WQE_pack_ctrl_send((u_int32_t*)cur_loc_p,  /* Pack Control segment */\r
1806     bind_props_p->comp_type, 0/*SE bit*/, 0/*event bit*/,0/*Imm. data*/)>>2);\r
1807 \r
1808   memset(cur_loc_p,0,8);  /* clear reserved bits of first 2 dwords */\r
1809 \r
1810   /* Set access bits */\r
1811   if (bind_props_p->acl & VAPI_EN_REMOTE_READ) {\r
1812     MT_INSERT_ARRAY32(cur_loc_p,1,\r
1813       MT_BIT_OFFSET(wqe_segment_bind_st,rr),MT_BIT_SIZE(wqe_segment_bind_st,rr));\r
1814   }\r
1815   if (bind_props_p->acl & VAPI_EN_REMOTE_WRITE) {\r
1816     MT_INSERT_ARRAY32(cur_loc_p,1,\r
1817       MT_BIT_OFFSET(wqe_segment_bind_st,rw),MT_BIT_SIZE(wqe_segment_bind_st,rw));\r
1818   }\r
1819   if (bind_props_p->acl & VAPI_EN_REMOTE_ATOM) {\r
1820     MT_INSERT_ARRAY32(cur_loc_p,1,\r
1821       MT_BIT_OFFSET(wqe_segment_bind_st,a),MT_BIT_SIZE(wqe_segment_bind_st,a));\r
1822   }\r
1823 \r
1824   cur_loc_p[MT_BYTE_OFFSET(wqe_segment_bind_st,new_rkey)>>2]= new_rkey;\r
1825   cur_loc_p[MT_BYTE_OFFSET(wqe_segment_bind_st,region_lkey)>>2]= bind_props_p->mr_lkey;\r
1826   cur_loc_p[MT_BYTE_OFFSET(wqe_segment_bind_st,start_address_h)>>2]= \r
1827     (u_int32_t)(bind_props_p->start >> 32);\r
1828   cur_loc_p[MT_BYTE_OFFSET(wqe_segment_bind_st,start_address_l)>>2]= \r
1829     (u_int32_t)(bind_props_p->start & 0xFFFFFFFF);\r
1830   cur_loc_p[MT_BYTE_OFFSET(wqe_segment_bind_st,length_h)>>2]= \r
1831     (u_int32_t)(bind_props_p->size >> 32);\r
1832   cur_loc_p[MT_BYTE_OFFSET(wqe_segment_bind_st,length_l)>>2]= \r
1833     (u_int32_t)(bind_props_p->size & 0xFFFFFFFF);\r
1834 \r
1835   return (u_int32_t)(WQE_SEG_SZ_BIND + ((MT_virt_addr_t)cur_loc_p) - ((MT_virt_addr_t)wqe_buf));\r
1836 }\r
1837 \r
1838 /* - Allocate a WQE in given send queue, \r
1839    - put given WQE in it, \r
1840    - link to previos WQE and \r
1841    - ring the doorbell \r
1842    * q_lock must be acquired before invoking this function (to protect WQEs allocation).\r
1843  */ \r
1844 inline static HH_ret_t sq_alloc_wqe_link_and_ring(THHUL_qp_t qp, \r
1845   u_int32_t* wqe_draft, u_int32_t wqe_sz_dwords, \r
1846 #ifdef MT_LITTLE_ENDIAN\r
1847   u_int32_t swap_sz_dwords, \r
1848 #endif\r
1849   VAPI_sr_desc_t *send_req_p, tavor_if_nopcode_t nopcode)\r
1850 {\r
1851   u_int32_t next_draft[WQE_SEG_SZ_NEXT>>2]; /* Build "next" segment here */\r
1852   volatile u_int32_t* next_wqe; /* Actual WQE pointer */\r
1853   u_int32_t i;\r
1854   THH_uar_sendq_dbell_t sq_dbell;\r
1855   \r
1856   /* Check if any WQEs are free to be consumed */\r
1857   if (qp->sq_res.max_outs == qp->sq_res.cur_outs) {\r
1858     MTL_ERROR4("THHUL_qpm_post_send_req: Send queue is full (%u requests outstanding).\n",\r
1859       qp->sq_res.cur_outs);\r
1860     return HH_E2BIG_WR_NUM;\r
1861   }\r
1862   /* Allocate next WQE */\r
1863   next_wqe= (u_int32_t*)(qp->sq_res.wqe_buf + \r
1864                         (qp->sq_res.next2post_index << qp->sq_res.log2_max_wqe_sz) );\r
1865   qp->sq_res.wqe_id[qp->sq_res.next2post_index]= send_req_p->id;  /* Save WQE ID */\r
1866   qp->sq_res.next2post_index = (qp->sq_res.next2post_index + 1) % qp->sq_res.max_outs ;\r
1867   qp->sq_res.cur_outs++;\r
1868   \r
1869   /* copy (while swapping,if needed) the wqe_draft to the actual WQE */\r
1870   /* TBD: for big-endian machines we can optimize here and use memcpy */\r
1871   MTPERF_TIME_START(SQ_WQE_copy);\r
1872 #ifdef MT_LITTLE_ENDIAN\r
1873   for (i= 0; i < swap_sz_dwords; i++) {\r
1874     next_wqe[i]= MOSAL_cpu_to_be32(wqe_draft[i]);\r
1875   }\r
1876   /* The rest of the WQE should be copied as is (inline data) */\r
1877   for (; i < wqe_sz_dwords; i++) {\r
1878     next_wqe[i]= wqe_draft[i];\r
1879   }\r
1880 #else /* big endian */\r
1881   for (i= 0; i < wqe_sz_dwords; i++) {\r
1882     next_wqe[i]= wqe_draft[i];\r
1883   }\r
1884 #endif\r
1885 \r
1886   MTPERF_TIME_END(SQ_WQE_copy);\r
1887   \r
1888   /* Update "next" segment of previous WQE (if any) */\r
1889   if (qp->sq_res.last_posted_p != NULL) {\r
1890     /* Build linking "next" segment in last posted WQE*/\r
1891     qpm_WQE_pack_send_next(next_draft, nopcode, send_req_p->fence,\r
1892       1/*DBD*/, (u_int32_t)(MT_ulong_ptr_t) next_wqe, wqe_sz_dwords>>2, \r
1893       (qp->ts_type==VAPI_TS_RD) ? send_req_p->eecn : 0);\r
1894     for (i= 0;i < (WQE_SEG_SZ_NEXT>>2) ;i++) {  \r
1895       /* This copy assures big-endian as well as that NDS is written last */\r
1896       qp->sq_res.last_posted_p[i]= MOSAL_cpu_to_be32(next_draft[i]);\r
1897     }\r
1898   }\r
1899   qp->sq_res.last_posted_p= next_wqe;\r
1900   \r
1901   /* Ring doorbell (send or rd-send) */\r
1902   sq_dbell.qpn= qp->qpn;\r
1903   sq_dbell.nopcode= nopcode;\r
1904   sq_dbell.fence= send_req_p->fence;\r
1905   sq_dbell.next_addr_32lsb= (u_int32_t)((MT_virt_addr_t)next_wqe & 0xFFFFFFFF);\r
1906   sq_dbell.next_size= wqe_sz_dwords>>2;\r
1907   if (qp->ts_type == VAPI_TS_RD) {\r
1908     THH_uar_sendq_rd_dbell(qp->uar,&sq_dbell,send_req_p->eecn);\r
1909   } else {  /* non-RD send request */\r
1910     MTPERF_TIME_START(THH_uar_sendq_dbell);\r
1911     THH_uar_sendq_dbell(qp->uar,&sq_dbell);\r
1912     MTPERF_TIME_END(THH_uar_sendq_dbell);\r
1913   }\r
1914 \r
1915   return HH_OK;\r
1916 }\r
1917 \r
1918 /* Optimized version of sq_alloc_wqe_link_and_ring\r
1919  * remove devision and call inline version od dbell \r
1920  * remove extra copy of Update "next" segment\r
1921  */\r
1922 #define  SEND_DOORBELL_F_BIT_OFFSET     MT_BIT_OFFSET(tavorprm_send_doorbell_st,f) \r
1923 #define  SEDN_DOORBELL_QPN_BIT_OFFSET   (MT_BIT_OFFSET(tavorprm_send_doorbell_st,qpn) & 0x1f)\r
1924 inline static HH_ret_t sq_alloc_wqe_link_and_ring_be(THHUL_qp_t qp, \r
1925   u_int32_t* wqe_draft, u_int32_t wqe_sz_dwords, \r
1926 #ifdef MT_LITTLE_ENDIAN\r
1927   u_int32_t swap_sz_dwords, \r
1928 #endif\r
1929   VAPI_sr_desc_t *send_req_p, tavor_if_nopcode_t nopcode)\r
1930 {\r
1931   //THH_uar_sendq_dbell_t sq_dbell;\r
1932   volatile u_int32_t chimeWords[4];\r
1933   THH_uar_t uar;\r
1934   u_int32_t *cur_loc_p;\r
1935 \r
1936     \r
1937   qp->sq_res.wqe_id[qp->sq_res.next2post_index]= send_req_p->id;  /* Save WQE ID */\r
1938   \r
1939   ++qp->sq_res.next2post_index;   \r
1940   if (MOSAL_EXPECT_FALSE(qp->sq_res.next2post_index >= qp->sq_res.max_outs))\r
1941                 qp->sq_res.next2post_index = 0;\r
1942   \r
1943   qp->sq_res.cur_outs++;\r
1944 \r
1945   /* Update "next" segment of previous WQE (if any) */\r
1946   /* Build linking "next" segment in last posted WQE*/\r
1947   /* buld dirctly to wqe, so call big endian version */\r
1948   WQE_pack_send_next_be((u_int32_t*)qp->sq_res.last_posted_p, nopcode, send_req_p->fence,\r
1949       1/*DBD*/, (u_int32_t)(MT_long_ptr_t) wqe_draft, wqe_sz_dwords>>2, \r
1950       (qp->ts_type==VAPI_TS_RD) ? send_req_p->eecn : 0);\r
1951    \r
1952    qp->sq_res.last_posted_p= wqe_draft;\r
1953       \r
1954    /* Ring doorbell */\r
1955     \r
1956   uar = qp->uar;\r
1957   chimeWords[0] = MOSAL_cpu_to_be32(0\r
1958             | (u_int32_t)nopcode\r
1959             | ((send_req_p->fence & 0x1) << SEND_DOORBELL_F_BIT_OFFSET)\r
1960             | ((u_int32_t)(MT_ulong_ptr_t)wqe_draft & 0xFFFFFFFF));\r
1961   chimeWords[1] = MOSAL_cpu_to_be32(0\r
1962             | (u_int32_t)(wqe_sz_dwords >> 2) // specify in 16 byte chunks\r
1963             | ((u_int32_t)(qp->qpn) << SEDN_DOORBELL_QPN_BIT_OFFSET)\r
1964             );\r
1965   \r
1966   if (MOSAL_EXPECT_FALSE(qp->ts_type == VAPI_TS_RD)) {          \r
1967           cur_loc_p = (u_int32_t *)&uar->uar_base[UAR_SEND_DBELL_OFFSET];               \r
1968           chimeWords[2] = MOSAL_cpu_to_be32(send_req_p->eecn << 18);\r
1969           chimeWords[3] = MOSAL_cpu_to_be32((u_int32_t)qp->qpn << 8);\r
1970           MOSAL_spinlock_dpc_lock(&(uar->uar_lock));\r
1971       MOSAL_MMAP_IO_WRITE_QWORD( cur_loc_p, *(volatile u_int64_t*)&chimeWords[2]);\r
1972           MOSAL_MMAP_IO_WRITE_QWORD(&cur_loc_p[2],*(volatile u_int64_t*)chimeWords);\r
1973           MOSAL_spinlock_unlock(&(uar->uar_lock));      \r
1974   } else {\r
1975 #ifdef __MOSAL_MMAP_IO_WRITE_QWORD_ATOMIC__\r
1976           MOSAL_MMAP_IO_WRITE_QWORD(((u_int32_t *)&uar->uar_base[UAR_SEND_DBELL_OFFSET]),*(volatile u_int64_t*)chimeWords);\r
1977 #else\r
1978           MOSAL_spinlock_dpc_lock(&(uar->uar_lock));\r
1979           MOSAL_MMAP_IO_WRITE_QWORD(((u_int32_t *)&uar->uar_base[UAR_SEND_DBELL_OFFSET]),*(volatile u_int64_t*)chimeWords);\r
1980           MOSAL_spinlock_unlock(&(uar->uar_lock));\r
1981 #endif  \r
1982   }\r
1983  \r
1984 \r
1985   return HH_OK;\r
1986 }\r
1987 \r
1988 /* Extract NDS directly from (big-endian) WQE */\r
1989 inline static u_int8_t qpm_WQE_extract_nds(volatile u_int32_t* wqe)\r
1990 {\r
1991 /*** warning C4244: 'return' : conversion from 'unsigned long' to 'u_int8_t', possible loss of data ***/\r
1992 #if 0\r
1993   return (u_int8_t)MT_EXTRACT32(MOSAL_be32_to_cpu(wqe[MT_BYTE_OFFSET(wqe_segment_next_st,nds) >> 2]),\r
1994                    MT_BIT_OFFSET(wqe_segment_next_st,nds) & MASK32(5),\r
1995                    MT_BIT_SIZE(wqe_segment_next_st,nds) & MASK32(5));\r
1996 #endif  \r
1997  \r
1998 #define NEXT_ST_BIT_MASK  MASK32(5)\r
1999   return (u_int8_t)MT_EXTRACT32(MOSAL_be32_to_cpu(wqe[NEXT_ST_NDS_DWORD_OFFSET]),\r
2000                    MT_BIT_OFFSET(wqe_segment_next_st,nds) & NEXT_ST_BIT_MASK,\r
2001                    MT_BIT_SIZE(wqe_segment_next_st,nds) & NEXT_ST_BIT_MASK);\r
2002 \r
2003 }\r
2004 \r
2005 /* Extract NDA directly from (big-endian) WQE */\r
2006 inline static u_int32_t qpm_WQE_extract_nda(volatile u_int32_t* wqe)\r
2007 {\r
2008   return (MOSAL_be32_to_cpu(wqe[MT_BYTE_OFFSET(wqe_segment_next_st,nda_31_6) >> 2]) & (~MASK32(6)) );\r
2009 }\r
2010 \r
2011 inline static u_int8_t qpm_WQE_extract_dbd(volatile u_int32_t* wqe)\r
2012 {\r
2013 /*** warning C4244: 'return' : conversion from 'unsigned long' to 'u_int8_t', possible loss of data ***/\r
2014 #if 0   \r
2015   return (u_int8_t)MT_EXTRACT32(MOSAL_be32_to_cpu(wqe[MT_BYTE_OFFSET(wqe_segment_next_st,dbd) >> 2]),\r
2016   return (u_int8_t)MT_EXTRACT32(MOSAL_be32_to_cpu(wqe[MT_BYTE_OFFSET(wqe_segment_next_st,dbd) >> 2]),\r
2017                    MT_BIT_OFFSET(wqe_segment_next_st,dbd) & MASK32(5),\r
2018                    MT_BIT_SIZE(wqe_segment_next_st,dbd) & MASK32(5));\r
2019 #endif\r
2020 #define NEXT_ST_DBD_DWORD_OFFSET   MT_BYTE_OFFSET(wqe_segment_next_st,dbd) >> 2\r
2021 #define NEXT_ST_DBD_BIT_MASK        MASK32(5)\r
2022   return (u_int8_t)MT_EXTRACT32(MOSAL_be32_to_cpu(wqe[NEXT_ST_DBD_DWORD_OFFSET]),\r
2023                    MT_BIT_OFFSET(wqe_segment_next_st,dbd) & NEXT_ST_DBD_BIT_MASK,\r
2024                    MT_BIT_SIZE(wqe_segment_next_st,dbd) & NEXT_ST_DBD_BIT_MASK);  \r
2025 }\r
2026 \r
2027 #ifdef DUMP_SEND_REQ\r
2028   static void dump_send_req(THHUL_qp_t qp, HHUL_send_req_t *sr);\r
2029 #endif\r
2030 \r
2031 /**********************************************************************************************\r
2032  *                    Public API Functions (defined in thhul_hob.h)\r
2033  **********************************************************************************************/\r
2034 \r
2035 HH_ret_t THHUL_qpm_create( \r
2036   THHUL_hob_t hob, \r
2037   THHUL_srqm_t srqm,\r
2038   THHUL_qpm_t *qpm_p \r
2039\r
2040\r
2041   int i;\r
2042 \r
2043   *qpm_p= (THHUL_qpm_t) MALLOC(sizeof(struct THHUL_qpm_st));\r
2044   if (*qpm_p == NULL) {\r
2045     MTL_ERROR1("THHUL_qpm_create: Failed allocating THHUL_qpm_st.\n");\r
2046     return HH_EAGAIN;\r
2047   }\r
2048 \r
2049   /* init internal data structures */\r
2050   for (i= 0; i < QP_HASH_TBL_SZ; i++) {\r
2051     (*qpm_p)->hash_tbl[i]= NULL;\r
2052 #if QPM_USE_FIXED_QP_ARRAY\r
2053     (*qpm_p)->array_tbl[i].qp_array[0].qpn = QP_ARRAY_UNUSED;\r
2054     (*qpm_p)->array_tbl[i].qp_array[QPM_QP_PER_ARRAY].qpn = QP_ARRAY_UNUSED;\r
2055 #endif\r
2056   }\r
2057   (*qpm_p)->qp_cnt= 0;\r
2058   (*qpm_p)->srqm= srqm;\r
2059   for (i= THHUL_DPOOL_SZ_MIN_KB; i <= THHUL_DPOOL_SZ_MAX_KB; i++) {\r
2060     (*qpm_p)->dpool_p[i - THHUL_DPOOL_SZ_MIN_KB]= NULL;\r
2061   }\r
2062   MOSAL_mutex_init(&(*qpm_p)->dpool_lock);\r
2063   MOSAL_spinlock_init(&((*qpm_p)->hash_lock));\r
2064 \r
2065   return HH_OK;\r
2066 }\r
2067 \r
2068 \r
2069 static void THHUL_qpm_qp_destroy(\r
2070    THHUL_qpm_t qpm,\r
2071    THHUL_qp_t qp)\r
2072 {\r
2073    /* Clean all CQEs which refer to this QP */\r
2074    THHUL_cqm_cq_cleanup(qp->rq_cq, qp->qpn, qpm->srqm, qp->srq);\r
2075    if (qp->sq_cq != qp->rq_cq) /* additional cleaning required only if SQ's CQ is different */\r
2076        THHUL_cqm_cq_cleanup(qp->sq_cq, qp->qpn, qpm->srqm, HHUL_INVAL_SRQ_HNDL);\r
2077                                   \r
2078    /* Free QP resources: Auxilary buffer + WQEs buffer */\r
2079         if (qp->sq_res.wqe_id != NULL) {\r
2080                 THH_SMART_FREE(qp->sq_res.wqe_id, qp->sq_res.max_outs * sizeof(VAPI_wr_id_t)); \r
2081         }\r
2082         if (qp->rq_res.wqe_id != NULL) {\r
2083                 THH_SMART_FREE(qp->rq_res.wqe_id, qp->rq_res.max_outs * sizeof(VAPI_wr_id_t)); \r
2084         }\r
2085    if (qp->wqe_buf_orig != NULL) {/* WQEs buffer were allocated in process mem. or by the THH_qpm ? */ \r
2086       MTL_DEBUG4(MT_FLFMT("Freeing WQEs buffer at 0x%p"),qp->wqe_buf_orig);\r
2087         if (qp->dpool_p == NULL) { /* direct allocation */\r
2088                 if (qp->used_virt_alloc) \r
2089                         MOSAL_pci_virt_free_consistent(qp->wqe_buf_orig, qp->wqe_buf_orig_size);\r
2090                 else\r
2091                         MOSAL_pci_phys_free_consistent(qp->wqe_buf_orig, qp->wqe_buf_orig_size);    \r
2092         } else { /* used dpool */\r
2093                 dpool_free(qpm, qp->dpool_p, qp->wqe_buf_orig);\r
2094         }\r
2095    }\r
2096    FREE(qp->sq_res.wqe_draft);\r
2097    if (qp->sq_res.wqe_tmp)\r
2098        FREE(qp->sq_res.wqe_tmp);\r
2099    FREE(qp->rq_res.wqe_draft);\r
2100    FREE(qp);\r
2101 }\r
2102 \r
2103 \r
2104 HH_ret_t THHUL_qpm_destroy( \r
2105    THHUL_qpm_t qpm \r
2106\r
2107\r
2108   \r
2109     THHUL_qp_t qp;\r
2110     qp_hash_entry_t *entry2remove_p;\r
2111     int i;\r
2112 \r
2113 #if QPM_USE_FIXED_QP_ARRAY\r
2114     /* clean up qp in fixed array */\r
2115     int j;          \r
2116     for (i= 0; i < QP_HASH_TBL_SZ; i++) {\r
2117         qp_array_entry_t *qp_array_e  = &qpm->array_tbl[i];\r
2118         j = 0;\r
2119         while (qp_array_e->qp_array[j].qpn != QP_ARRAY_UNUSED) {\r
2120                  if(qp_array_e->qp_array[j].qpn != QP_ARRAY_REUSE)\r
2121                  {                                      \r
2122                         qp = qp_array_e->qp_array[j].qp;\r
2123                 \r
2124                         /* clean up qp structure */\r
2125                         THHUL_qpm_qp_destroy(qpm, qp);\r
2126                         qp_array_e->qp_array[j].qpn = QP_ARRAY_REUSE;\r
2127                         qp_array_e->qp_array[j].qp = 0; \r
2128                  }\r
2129                  j++;\r
2130         }/* while (array_tbl[i]...) */\r
2131     }\r
2132 #endif\r
2133     /* clean up qp in hash table */\r
2134     for (i= 0; i < QP_HASH_TBL_SZ; i++) {\r
2135         while (qpm->hash_tbl[i]) {\r
2136                 entry2remove_p = qpm->hash_tbl[i];\r
2137                 qpm->hash_tbl[i] = entry2remove_p->next;\r
2138                 qp = entry2remove_p->qp;\r
2139                 FREE(entry2remove_p); \r
2140 \r
2141                 /* clean up qp structure */\r
2142                 THHUL_qpm_qp_destroy(qpm, qp);\r
2143 \r
2144                 }/* while (hash_tbl[i]..)*/\r
2145     }/* for (i.. QP_HASH_TBL_SZ)*/\r
2146 \r
2147     \r
2148     FREE(qpm);\r
2149     return HH_OK;\r
2150 }\r
2151 \r
2152 \r
2153 HH_ret_t THHUL_qpm_create_qp_prep( \r
2154    HHUL_hca_hndl_t hca, \r
2155    HHUL_qp_init_attr_t *qp_init_attr_p, \r
2156    HHUL_qp_hndl_t *qp_hndl_p, \r
2157    VAPI_qp_cap_t *qp_cap_out_p, \r
2158    void/*THH_qp_ul_resources_t*/ *qp_ul_resources_p \r
2159\r
2160\r
2161   return qp_prep(hca,VAPI_REGULAR_QP,qp_init_attr_p,qp_hndl_p,qp_cap_out_p,\r
2162     (THH_qp_ul_resources_t*)qp_ul_resources_p,\r
2163     FALSE);  /* Default is allocation of WQEs buffer in host's mem. */\r
2164 }\r
2165 \r
2166 HH_ret_t THHUL_qpm_special_qp_prep( \r
2167    HHUL_hca_hndl_t hca, \r
2168    VAPI_special_qp_t qp_type, \r
2169    IB_port_t port, \r
2170    HHUL_qp_init_attr_t *qp_init_attr_p, \r
2171    HHUL_qp_hndl_t *qp_hndl_p, \r
2172    VAPI_qp_cap_t *qp_cap_out_p, \r
2173    void/*THH_qp_ul_resources_t*/ *qp_ul_resources_p \r
2174\r
2175\r
2176   return qp_prep(hca,qp_type,qp_init_attr_p,qp_hndl_p,qp_cap_out_p,\r
2177     (THH_qp_ul_resources_t*)qp_ul_resources_p,\r
2178     FALSE);  /* For special QPs no performance issue - WQEs in main memory */\r
2179 }\r
2180 \r
2181 \r
2182 HH_ret_t THHUL_qpm_create_qp_done( \r
2183   HHUL_hca_hndl_t hca, \r
2184   HHUL_qp_hndl_t hhul_qp, \r
2185   IB_wqpn_t hh_qp, \r
2186   void/*THH_qp_ul_resources_t*/ *qp_ul_resources_p\r
2187\r
2188\r
2189   THHUL_qpm_t qpm;\r
2190   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2191   THH_qp_ul_resources_t *ul_res_p= (THH_qp_ul_resources_t*)qp_ul_resources_p;\r
2192   HH_ret_t rc;\r
2193   \r
2194   rc= THHUL_hob_get_qpm(hca,&qpm);\r
2195   if (rc != HH_OK) {\r
2196     MTL_ERROR4("THHUL_qpm_create_qp_done: Invalid HCA handle (%p).",hca);\r
2197     return HH_EINVAL;\r
2198   }\r
2199   if (qp == NULL) {\r
2200     MTL_ERROR4("THHUL_qpm_create_qp_done: NULL hhul_qp handle.");\r
2201     return HH_EINVAL;\r
2202   }\r
2203   \r
2204   if ((qp->wqe_buf_orig == NULL) && (qp->wqe_buf_orig_size != 0)) { \r
2205     /* WQEs buffer allocated in DDR mem. by THH_qpm */\r
2206     if (ul_res_p->wqes_buf == 0) {\r
2207       MTL_ERROR1(MT_FLFMT("Got NULL WQEs buffer from qp_ul_res for new qpn=%d.\n"),qp->qpn);\r
2208       return HH_EINVAL;\r
2209     }\r
2210     /* Set the per queue resources */\r
2211     qp->rq_res.wqe_buf= MT_UP_ALIGNX_VIRT(ul_res_p->wqes_buf,qp->rq_res.log2_max_wqe_sz);\r
2212     if (qp->rq_res.wqe_buf != ul_res_p->wqes_buf) {\r
2213       MTL_ERROR1(\r
2214         "THHUL_qpm_create_qp_done: Buffer allocated by THH_qpm ("VIRT_ADDR_FMT") "\r
2215         "is not aligned to RQ WQE size (%d bytes).\n",\r
2216         ul_res_p->wqes_buf,1<<qp->rq_res.log2_max_wqe_sz);\r
2217       return HH_EINVAL;\r
2218     }\r
2219     /* SQ is after RQ - aligned to its WQE size */\r
2220     qp->sq_res.wqe_buf= MT_UP_ALIGNX_VIRT(qp->rq_res.wqe_buf + \r
2221         (qp->rq_res.max_outs << qp->rq_res.log2_max_wqe_sz), /* End of RQ WQEs buffer */\r
2222       qp->sq_res.log2_max_wqe_sz); \r
2223   }\r
2224   /* point at the last two 32 bit words in the wqe_buf, \r
2225    * this allows us to remove an if in VAPI_post_sr path */\r
2226   qp->sq_res.last_posted_p = (volatile u_int32_t*)(qp->sq_res.wqe_buf + (1 << qp->sq_res.log2_max_wqe_sz));\r
2227   qp->rq_res.last_posted_p = (volatile u_int32_t*)(qp->rq_res.wqe_buf + (1 << qp->rq_res.log2_max_wqe_sz));\r
2228   \r
2229   qp->qpn= hh_qp;\r
2230   /* Insert QP to the hash table with the given QP number */\r
2231   rc= insert_to_hash(qpm,qp);\r
2232   if (rc != HH_OK) {\r
2233     MTL_ERROR2("THHUL_qpm_create_qp_done: Failed inserting to hash table "\r
2234                "(QP will remain unusable) !"); \r
2235     qp->qpn= 0xFFFFFFFF; /* Mark that QP initialization was not completed with invalid QP num. */\r
2236     return rc;\r
2237   }\r
2238 \r
2239   MTL_DEBUG4(MT_FLFMT("%s: qpn=0x%X rq_res{buf_p=%p, sz=0x%X} sq_res{buf_p=%p, sz=0x%X}"), __func__,\r
2240              qp->qpn, \r
2241              (void*)qp->rq_res.wqe_buf, (1 << qp->rq_res.log2_max_wqe_sz) * qp->rq_res.max_outs,\r
2242              (void*)qp->sq_res.wqe_buf, (1 << qp->sq_res.log2_max_wqe_sz) * qp->sq_res.max_outs);\r
2243 \r
2244   return HH_OK;\r
2245 }\r
2246 \r
2247 \r
2248 HH_ret_t THHUL_qpm_destroy_qp_done( \r
2249    HHUL_hca_hndl_t hca, \r
2250    HHUL_qp_hndl_t hhul_qp \r
2251\r
2252\r
2253   THHUL_qpm_t qpm;\r
2254   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2255   HH_ret_t rc;\r
2256   if ( !qp ) {\r
2257     MTL_ERROR4("THHUL_qpm_destroy_qp_done: Invalid QP handle (%p).",qp);\r
2258     return HH_EINVAL;\r
2259   }\r
2260   MTL_DEBUG1("THHUL_qpm_destroy_qp_done(hca=%s,hhul_qp=%p) {\n",hca->dev_desc,qp);\r
2261   rc= THHUL_hob_get_qpm(hca,&qpm);\r
2262   if (rc != HH_OK) {\r
2263     MTL_ERROR4("THHUL_qpm_destroy_qp_done: Invalid HCA handle (%p).",hca);\r
2264     return HH_EINVAL;\r
2265   }\r
2266   MTL_DEBUG4(MT_FLFMT("Got qpm with %d QPs"),qpm->qp_cnt);\r
2267   \r
2268   if (IS_VALID_QPN(qp->qpn)) {  /* QP has completed THHUL_qpm_create_qp_done successfully */\r
2269     \r
2270     /* Clean all CQEs which refer to this QP */\r
2271     THHUL_cqm_cq_cleanup(qp->rq_cq, qp->qpn, qpm->srqm, qp->srq);\r
2272     if (qp->sq_cq != qp->rq_cq) /* additional cleaning required only if SQ's CQ is different */\r
2273     THHUL_cqm_cq_cleanup(qp->sq_cq, qp->qpn, qpm->srqm, HHUL_INVAL_SRQ_HNDL);\r
2274     \r
2275     /* Remove QP from hash table (after assured no more CQEs of this QP exist) */\r
2276     rc= remove_from_hash(qpm,qp);\r
2277     if (rc != HH_OK) {\r
2278       MTL_ERROR2("THHUL_qpm_destroy_qp_done: Failed removing qp from hash table "\r
2279                  "(assuming invalid QP handle) !"); \r
2280       return HH_EINVAL_QP_NUM;\r
2281     }\r
2282     MTL_DEBUG4(MT_FLFMT("QP %d removed from hash table"),qp->qpn);\r
2283   \r
2284   }\r
2285 \r
2286   /* Free QP resources: Auxilary buffer + WQEs buffer */\r
2287   MTL_DEBUG4(MT_FLFMT("Freeing user level WQE-IDs auxilary buffers"));\r
2288   if (qp->sq_res.wqe_id != NULL) {\r
2289     THH_SMART_FREE(qp->sq_res.wqe_id, qp->sq_res.max_outs * sizeof(VAPI_wr_id_t)); \r
2290   }\r
2291   if (qp->rq_res.wqe_id != NULL) {\r
2292     THH_SMART_FREE(qp->rq_res.wqe_id, qp->rq_res.max_outs * sizeof(VAPI_wr_id_t)); \r
2293   }\r
2294   if (qp->wqe_buf_orig != NULL) {/* WQEs buffer were allocated in process mem. or by the THH_qpm ? */ \r
2295     MTL_DEBUG4(MT_FLFMT("Freeing WQEs buffer at 0x%p"),qp->wqe_buf_orig);\r
2296     if (qp->dpool_p == NULL) { /* direct allocation */\r
2297 #ifdef WIN32\r
2298         cl_free( qp->wqe_buf_orig );\r
2299 #else\r
2300       if (qp->used_virt_alloc) \r
2301         MOSAL_pci_virt_free_consistent(qp->wqe_buf_orig, qp->wqe_buf_orig_size);\r
2302       else\r
2303         MOSAL_pci_phys_free_consistent(qp->wqe_buf_orig, qp->wqe_buf_orig_size);    \r
2304 #endif\r
2305     } else { /* used dpool */\r
2306       dpool_free(qpm, qp->dpool_p, qp->wqe_buf_orig);\r
2307     }\r
2308   }\r
2309   if (qp->sq_res.wqe_tmp)\r
2310     FREE(qp->sq_res.wqe_tmp);\r
2311   if ( qp->sq_res.wqe_draft ) FREE(qp->sq_res.wqe_draft);\r
2312   if ( qp->rq_res.wqe_draft ) FREE(qp->rq_res.wqe_draft);\r
2313   FREE(qp);\r
2314   /* update QPs counter */\r
2315   MOSAL_spinlock_dpc_lock(&(qpm->hash_lock));\r
2316   qpm->qp_cnt--;\r
2317   MOSAL_spinlock_unlock(&(qpm->hash_lock));\r
2318   MTL_DEBUG1("} /* THHUL_qpm_destroy_qp_done */ \n");\r
2319   return HH_OK;  \r
2320 }\r
2321 \r
2322 HH_ret_t THHUL_qpm_modify_qp_done( \r
2323    HHUL_hca_hndl_t hca, \r
2324    HHUL_qp_hndl_t hhul_qp, \r
2325    VAPI_qp_state_t cur_state \r
2326\r
2327\r
2328   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2329   THHUL_qpm_t qpm;\r
2330   HH_ret_t rc;\r
2331   \r
2332   if (qp == NULL) {\r
2333     MTL_ERROR1("THHUL_qpm_modify_qp_done: NULL hhul_qp.\n");\r
2334     return HH_EINVAL;\r
2335   }\r
2336 \r
2337   rc= THHUL_hob_get_qpm(hca,&qpm);\r
2338   if (rc != HH_OK) {\r
2339     MTL_ERROR1(MT_FLFMT("%s: Failed to get QPM handle (%d=%s)"), __func__, rc, HH_strerror_sym(rc));\r
2340     return rc;\r
2341   }\r
2342 \r
2343   /* Update in RQ */\r
2344   if (cur_state == VAPI_RESET) {  \r
2345     /* Cleanup all CQEs of RQ (flush) when moving to reset state */\r
2346     THHUL_cqm_cq_cleanup(qp->rq_cq, qp->qpn, qpm->srqm, qp->srq);\r
2347     MOSAL_spinlock_dpc_lock(&(qp->rq_res.q_lock));\r
2348     qp->rq_res.cur_outs= 0;\r
2349     qp->rq_res.next2free_index= qp->rq_res.next2post_index= 0;\r
2350     qp->rq_res.last_posted_p= NULL;\r
2351     qp->rq_res.qp_state= VAPI_RESET;\r
2352         \r
2353     /* point at the last two 32 bit words in the wqe_buf, \r
2354      * this allows us to remove an if in VAPI_post_sr path */\r
2355     qp->rq_res.last_posted_p = (volatile u_int32_t*)(qp->rq_res.wqe_buf + (1 << qp->rq_res.log2_max_wqe_sz));\r
2356    \r
2357     MOSAL_spinlock_unlock(&(qp->rq_res.q_lock));\r
2358   } else {\r
2359     qp->rq_res.qp_state= cur_state;\r
2360   }\r
2361   \r
2362   /* Update in SQ */\r
2363   if (cur_state == VAPI_RESET) {  \r
2364     /* Cleanup all CQEs of SQ (flush) when moving to reset state */\r
2365     if (qp->sq_cq != qp->rq_cq) /* additional cleaning required only if SQ's CQ is different */\r
2366       THHUL_cqm_cq_cleanup(qp->sq_cq, qp->qpn, qpm->srqm, HHUL_INVAL_SRQ_HNDL);\r
2367     MOSAL_spinlock_dpc_lock(&(qp->sq_res.q_lock));\r
2368     qp->sq_res.cur_outs= 0;\r
2369     qp->sq_res.next2free_index= qp->sq_res.next2post_index= 0;\r
2370     qp->sq_res.last_posted_p= NULL;\r
2371     qp->sq_res.qp_state= VAPI_RESET;\r
2372         \r
2373     /* point at the last two 32 bit words in the wqe_buf, \r
2374      * this allows us to remove an if in VAPI_post_sr path */\r
2375     qp->sq_res.last_posted_p = (volatile u_int32_t*)(qp->sq_res.wqe_buf + (1 << qp->sq_res.log2_max_wqe_sz));\r
2376     \r
2377     MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2378   } else {\r
2379     qp->sq_res.qp_state= cur_state;\r
2380   }\r
2381 \r
2382   return HH_OK;\r
2383 }\r
2384 \r
2385 \r
2386 \r
2387 #if !(USE_FAST_POST)\r
2388 /* Original version */\r
2389 HH_ret_t THHUL_qpm_post_send_req( \r
2390    HHUL_hca_hndl_t hca, \r
2391    HHUL_qp_hndl_t hhul_qp, \r
2392    VAPI_sr_desc_t *send_req_p \r
2393\r
2394\r
2395   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2396   u_int32_t* wqe_draft= qp->sq_res.wqe_draft;\r
2397   u_int32_t wqe_sz_dwords;\r
2398   HH_hca_hndl_t hca_ul_res_handle;\r
2399   HH_ret_t rc;\r
2400 \r
2401   if (!is_qpstate_valid_2send(qp->sq_res.qp_state)) {\r
2402     MTL_ERROR1(MT_FLFMT("%s failed: qp state %d not valid to send \n"),__func__,qp->sq_res.qp_state);\r
2403     return HH_EINVAL_QP_STATE;\r
2404   }\r
2405   \r
2406   if (qp->sq_res.max_sg_sz < send_req_p->sg_lst_len) {\r
2407     MTL_ERROR2(\r
2408       "THHUL_qpm_post_send_req: Scatter/Gather list is too large (%d entries > max_sg_sz=%d)\n",\r
2409       send_req_p->sg_lst_len,qp->sq_res.max_sg_sz);\r
2410     return HH_EINVAL_SG_NUM;\r
2411   }\r
2412    \r
2413 #ifdef DUMP_SEND_REQ \r
2414   dump_send_req(qp,send_req_p);\r
2415 #endif\r
2416   \r
2417   MOSAL_spinlock_dpc_lock(&(qp->sq_res.q_lock)); /* protect wqe_draft and WQE allocation/link */\r
2418   \r
2419   if (qp->sqp_type == VAPI_REGULAR_QP)  {\r
2420     MTPERF_TIME_START(WQE_build_send);\r
2421     wqe_sz_dwords= (WQE_build_send(qp,send_req_p,wqe_draft) >> 2);\r
2422     MTPERF_TIME_END(WQE_build_send);\r
2423 #ifdef MAX_DEBUG\r
2424     if ((wqe_sz_dwords<<2) > (1U << qp->sq_res.log2_max_wqe_sz)) {\r
2425       MTL_ERROR1(MT_FLFMT("QP 0x%X: Send WQE too large (%d > max=%d)"),\r
2426         qp->qpn,(wqe_sz_dwords<<2),(1U << qp->sq_res.log2_max_wqe_sz));\r
2427         }\r
2428 #endif\r
2429   } else { /* special QP */\r
2430     if (send_req_p->opcode != VAPI_SEND)  {\r
2431       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2432       return HH_EINVAL_OPCODE;\r
2433     }\r
2434     send_req_p->fence= FALSE; /* required for MLX requests */\r
2435     rc= THHUL_hob_get_hca_ul_res_handle(hca,&hca_ul_res_handle);\r
2436     if (rc != HH_OK) {\r
2437       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2438       return HH_EINVAL_HCA_HNDL;\r
2439     }\r
2440     wqe_sz_dwords= \r
2441       (WQE_build_send_mlx(hca_ul_res_handle, qp,send_req_p,QP1_PKEY_INDEX,wqe_draft) >> 2);\r
2442     if (wqe_sz_dwords == 0) {\r
2443       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2444       MTL_ERROR1(MT_FLFMT("Failed building MLX headers for special QP.\n"));\r
2445       return HH_EINVAL_WQE;\r
2446     }\r
2447   }\r
2448 \r
2449   rc= sq_alloc_wqe_link_and_ring(qp,wqe_draft,wqe_sz_dwords,\r
2450 #ifdef MT_LITTLE_ENDIAN\r
2451            wqe_sz_dwords,\r
2452 #endif\r
2453            send_req_p,encode_nopcode(send_req_p->opcode)); \r
2454   MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2455   return rc;\r
2456 }\r
2457 \r
2458 #else  /* USE_FAST_POST == 1 */\r
2459 /* Optimized version of post_send_req\r
2460  * Remove double copy of building wqe from wqe_draft to wqe_buf, instead\r
2461  * write driectly to wqe_buf. Conversion to be was done when copy to wqe_buf from\r
2462  * wqe_draft, now ew have to build big endian version directly. All the function\r
2463  * with ***_be extention build big_endian version of WQE.\r
2464  */ \r
2465 HH_ret_t THHUL_qpm_post_send_req( \r
2466    HHUL_hca_hndl_t hca, \r
2467    HHUL_qp_hndl_t hhul_qp, \r
2468    VAPI_sr_desc_t *send_req_p \r
2469\r
2470\r
2471   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2472   u_int32_t wqe_sz_dwords;\r
2473   THH_hca_ul_resources_t hca_ul_res;\r
2474   HH_ret_t rc;\r
2475   volatile u_int32_t* next_wqe; /* Actual WQE pointer */\r
2476 \r
2477         \r
2478   if(MOSAL_EXPECT_FALSE(qp->sq_res.qp_state < VAPI_RTS)) {\r
2479     MTL_ERROR1(MT_FLFMT("%s failed: qp state %d not valid to send \n"),__func__,qp->sq_res.qp_state);\r
2480     return HH_EINVAL_QP_STATE;\r
2481   }\r
2482           \r
2483   if (MOSAL_EXPECT_FALSE(qp->sq_res.max_sg_sz < send_req_p->sg_lst_len)) {\r
2484     MTL_ERROR2(\r
2485       "THHUL_qpm_post_send_req: Scatter/Gather list is too large (%d entries > max_sg_sz=%d)\n",\r
2486       send_req_p->sg_lst_len,qp->sq_res.max_sg_sz);\r
2487     return HH_EINVAL_SG_NUM;\r
2488   }\r
2489 \r
2490 #ifdef DUMP_SEND_REQ \r
2491   dump_send_req(qp,send_req_p);\r
2492 #endif\r
2493  \r
2494   MOSAL_spinlock_dpc_lock(&(qp->sq_res.q_lock)); /* protect wqe_draft and WQE allocation/link */\r
2495 \r
2496   /* Check if any WQEs are free to be consumed */\r
2497   if (MOSAL_EXPECT_FALSE(qp->sq_res.max_outs == qp->sq_res.cur_outs)) {\r
2498     MTL_ERROR4("THHUL_qpm_post_send_req: Send queue is full (%u requests outstanding).\n",\r
2499       qp->sq_res.cur_outs);\r
2500     return HH_E2BIG_WR_NUM;\r
2501   }\r
2502 \r
2503   /* Allocate next WQE */\r
2504   /* WQE build directly to wqe_buf, instead of draft, so should call big\r
2505    * endian version of WQE_build_send \r
2506    */ \r
2507   next_wqe= (u_int32_t*)(qp->sq_res.wqe_buf + \r
2508                         (qp->sq_res.next2post_index << qp->sq_res.log2_max_wqe_sz) );\r
2509 \r
2510   \r
2511   if (MOSAL_EXPECT_TRUE(qp->sqp_type == VAPI_REGULAR_QP))  {\r
2512     /* call big_endian version of WQE_build_send */       \r
2513     wqe_sz_dwords= (WQE_build_send_be(qp,send_req_p,(u_int32_t*)next_wqe) >> 2);\r
2514 #ifdef MAX_DEBUG\r
2515     if ((wqe_sz_dwords<<2) > (1 << qp->sq_res.log2_max_wqe_sz))\r
2516       MTL_ERROR1(MT_FLFMT("QP 0x%X: Send WQE too large (%d > max=%d)"),\r
2517         qp->qpn,(wqe_sz_dwords<<2),(1 << qp->sq_res.log2_max_wqe_sz));\r
2518 #endif\r
2519   } else { /* special QP */\r
2520 \r
2521     u_int32_t* wqe_draft= qp->sq_res.wqe_draft;\r
2522     unsigned int i; \r
2523           \r
2524     if (MOSAL_EXPECT_FALSE(send_req_p->opcode != VAPI_SEND))  {\r
2525       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2526       return HH_EINVAL_WQE;\r
2527     }\r
2528     send_req_p->fence= FALSE; /* required for MLX requests */\r
2529     if(MOSAL_EXPECT_FALSE(THHUL_hob_get_hca_ul_res(hca,&hca_ul_res) != HH_OK))\r
2530     {\r
2531       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2532       return HH_EINVAL_HCA_HNDL;\r
2533     }\r
2534     wqe_sz_dwords= (WQE_build_send_mlx(hca_ul_res.hh_hca_hndl,qp,send_req_p,QP1_PKEY_INDEX,wqe_draft) >> 2);\r
2535     if (MOSAL_EXPECT_FALSE(wqe_sz_dwords == 0)) {\r
2536       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2537       MTL_ERROR1(MT_FLFMT("Failed building MLX headers for special QP.\n"));\r
2538       return HH_EINVAL_WQE;\r
2539     }\r
2540                 \r
2541     /* we used a temporary (draft) memory space, so move it do destination, also\r
2542     we used the standard routines that don't byte swap each word so byte swap             \r
2543     each word if we are on a little endian cpu */               \r
2544     for(i = 0; i < wqe_sz_dwords; ++i) {                        \r
2545             next_wqe[i] = MOSAL_cpu_to_be32(wqe_draft[i]);              \r
2546     }\r
2547 \r
2548   }\r
2549 \r
2550   rc= sq_alloc_wqe_link_and_ring_be(qp,(u_int32_t*)next_wqe,wqe_sz_dwords,\r
2551 #ifdef MT_LITTLE_ENDIAN\r
2552            wqe_sz_dwords,\r
2553 #endif\r
2554            send_req_p,encode_nopcode(send_req_p->opcode)); \r
2555   MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2556   return rc;\r
2557 }\r
2558 #endif //USE_FAST_POST == 0\r
2559 \r
2560 \r
2561 #if USE_FAST_POST == 0\r
2562 /* Orignal version of THHUL_qpm_post_inline_send_req */\r
2563 HH_ret_t THHUL_qpm_post_inline_send_req( \r
2564    HHUL_hca_hndl_t hca, \r
2565    HHUL_qp_hndl_t hhul_qp, \r
2566    VAPI_sr_desc_t *send_req_p \r
2567\r
2568\r
2569   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2570   u_int32_t* wqe_draft= qp->sq_res.wqe_draft;\r
2571   u_int8_t *cur_loc_p= (u_int8_t*)wqe_draft; /* Current location in the WQE */\r
2572   u_int8_t *wqe_edge_p= ((u_int8_t*)wqe_draft)+(1<<qp->sq_res.log2_max_wqe_sz);\r
2573   u_int32_t wqe_sz_dwords;\r
2574   u_int32_t* inline_p; /* inline control word */\r
2575   u_int32_t i;  \r
2576   HH_ret_t rc;\r
2577 \r
2578 #ifdef DUMP_SEND_REQ \r
2579   dump_send_req(qp,send_req_p);\r
2580 #endif\r
2581   \r
2582   if (!is_qpstate_valid_2send(qp->sq_res.qp_state)) {\r
2583    MTL_ERROR1(MT_FLFMT("%s failed: qp state %d not valid to send \n"),__func__,qp->sq_res.qp_state);\r
2584    return HH_EINVAL_QP_STATE;\r
2585  }\r
2586 \r
2587   MOSAL_spinlock_dpc_lock(&(qp->sq_res.q_lock)); /* protect wqe_draft and WQE allocation/link */\r
2588   \r
2589   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
2590   cur_loc_p+= WQE_pack_ctrl_send((u_int32_t*)cur_loc_p,  /* Pack Control segment */\r
2591     send_req_p->comp_type, send_req_p->set_se, 0/*event bit*/,\r
2592     ((send_req_p->opcode == VAPI_RDMA_WRITE_WITH_IMM) ||\r
2593      (send_req_p->opcode == VAPI_SEND_WITH_IMM) ) ? send_req_p->imm_data : 0);\r
2594 \r
2595   /* Transport type checks: Datagram segment */\r
2596   switch (qp->ts_type) {\r
2597     case VAPI_TS_UD:  /* Check if UD (UD datagram segment) */\r
2598       cur_loc_p+= WQE_pack_ud((u_int32_t*)cur_loc_p,\r
2599         qp->ud_av_memkey,translate_av(qp, (u_int64_t)send_req_p->remote_ah),\r
2600         send_req_p->remote_qp,send_req_p->remote_qkey);\r
2601       break;\r
2602     case VAPI_TS_RD:  /* Check if RD (RD datagram segment) */\r
2603       cur_loc_p+= WQE_pack_rd((u_int32_t*)cur_loc_p,\r
2604         send_req_p->remote_qp,send_req_p->remote_qkey);\r
2605       break;\r
2606     default:\r
2607       break;\r
2608   }\r
2609   \r
2610   /* Opcode checks + Remote-address/Atomic segments */\r
2611   switch (send_req_p->opcode) {\r
2612     /* For RDMA operations: only Remote-address segment */\r
2613     case VAPI_RDMA_WRITE:\r
2614     case VAPI_RDMA_WRITE_WITH_IMM:\r
2615       cur_loc_p+= WQE_pack_remote_addr((u_int32_t*)cur_loc_p,\r
2616         send_req_p->remote_addr,send_req_p->r_key);\r
2617       break;\r
2618     \r
2619     case VAPI_SEND:\r
2620     case VAPI_SEND_WITH_IMM:\r
2621       break; /* Valid opcodes for "inline" but no extra WQE segment */\r
2622     default: \r
2623       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2624       return HH_EINVAL_OPCODE; /* Invalid opcode */\r
2625   }\r
2626   \r
2627   inline_p= (u_int32_t*)cur_loc_p;\r
2628   cur_loc_p+= WQE_INLINE_SZ_BCOUNT;\r
2629   /* copy inline data to WQE */\r
2630   for (i= 0; i < send_req_p->sg_lst_len; i++) {\r
2631     if ((cur_loc_p+send_req_p->sg_lst_p[i].len) > wqe_edge_p) {\r
2632       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2633       MTL_ERROR2(MT_FLFMT("too much inline data for inline send request (qpn=0x%X)"),qp->qpn);\r
2634       return HH_EINVAL_SG_NUM;\r
2635     }\r
2636     if (send_req_p->sg_lst_p[i].addr > (MT_virt_addr_t)MAKE_ULONGLONG(0xFFFFFFFFFFFFFFFF)) {\r
2637         MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2638         MTL_ERROR2(MT_FLFMT("sg list addr %d has non-zero upper bits (qpn=0x%X, addr="U64_FMT") \n"),\r
2639                i,qp->qpn,send_req_p->sg_lst_p[i].addr );\r
2640        return HH_EINVAL_SG_FMT;\r
2641     }\r
2642     memcpy(cur_loc_p, (void*)(MT_virt_addr_t)(send_req_p->sg_lst_p[i].addr),\r
2643            send_req_p->sg_lst_p[i].len); \r
2644     cur_loc_p+= send_req_p->sg_lst_p[i].len;\r
2645   }\r
2646   *inline_p= \r
2647     (u_int32_t)(0x80000000 | (((MT_virt_addr_t)cur_loc_p) - ((MT_virt_addr_t)inline_p) - 4)); /*inline:size*/\r
2648 \r
2649   wqe_sz_dwords= (MT_UP_ALIGNX_U32( (u_int32_t)(((MT_virt_addr_t)cur_loc_p) - ((MT_virt_addr_t)wqe_draft)),\r
2650                                 WQE_SZ_MULTIPLE_SHIFT) >> 2); \r
2651 #ifdef MAX_DEBUG\r
2652   if ((wqe_sz_dwords<<2) > (1U << qp->sq_res.log2_max_wqe_sz)) {\r
2653     MTL_ERROR1(MT_FLFMT("QP 0x%X: Send WQE too large (%d > max=%d) !!!!!!!!!"),\r
2654       qp->qpn,(wqe_sz_dwords<<2),(1U << qp->sq_res.log2_max_wqe_sz));\r
2655         }\r
2656 #endif\r
2657 \r
2658   rc= sq_alloc_wqe_link_and_ring(qp,wqe_draft,wqe_sz_dwords,\r
2659 #ifdef MT_LITTLE_ENDIAN\r
2660            (u_int32_t)(inline_p - wqe_draft + 1), /* swap all up to data */\r
2661 #endif\r
2662            send_req_p,encode_nopcode(send_req_p->opcode)); \r
2663   MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2664   return rc;\r
2665 }\r
2666 #else\r
2667 /* Optimized version of THHUL_qpm_post_inline_send_req.\r
2668  * Remove extra copy from wqe_draft to wqe, instead driect write to\r
2669  * Wqe buffer.\r
2670  */\r
2671 HH_ret_t THHUL_qpm_post_inline_send_req( \r
2672    HHUL_hca_hndl_t hca, \r
2673    HHUL_qp_hndl_t hhul_qp, \r
2674    VAPI_sr_desc_t *send_req_p \r
2675\r
2676\r
2677   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2678   volatile u_int32_t* next_wqe; /* Actual WQE pointer */  \r
2679   u_int8_t *cur_loc_p; /*   Current location in the WQE */\r
2680   u_int8_t *wqe_edge_p;/* End of Wqe buffer */\r
2681   u_int32_t wqe_sz_dwords;\r
2682   u_int32_t* inline_p; /* inline control word */\r
2683   u_int32_t i;  \r
2684   HH_ret_t rc;\r
2685 \r
2686 #ifdef DUMP_SEND_REQ \r
2687   dump_send_req(qp,send_req_p);\r
2688 #endif\r
2689   \r
2690    if(MOSAL_EXPECT_FALSE(qp->sq_res.qp_state < VAPI_RTS)) {\r
2691    MTL_ERROR1(MT_FLFMT("%s failed: qp state %d not valid to send \n"),__func__,qp->sq_res.qp_state);\r
2692    return HH_EINVAL_QP_STATE;\r
2693  }\r
2694 \r
2695   MOSAL_spinlock_dpc_lock(&(qp->sq_res.q_lock)); /* protect wqe_draft and WQE allocation/link */\r
2696    \r
2697   /* Allocate next WQE */\r
2698   /* WQE build directly to wqe_buf, instead of draft, so should call big\r
2699    * endian version of WQE_build_send \r
2700    */ \r
2701   next_wqe= (u_int32_t*)(qp->sq_res.wqe_buf + \r
2702                         (qp->sq_res.next2post_index << qp->sq_res.log2_max_wqe_sz) );\r
2703   \r
2704   cur_loc_p =  (u_int8_t *)next_wqe; \r
2705   wqe_edge_p = ((u_int8_t*)next_wqe)+(1<<qp->sq_res.log2_max_wqe_sz); \r
2706   \r
2707   cur_loc_p+= qpm_WQE_init_next((u_int32_t*)cur_loc_p); /* Make "unlinked" "next" segment */\r
2708   cur_loc_p+= WQE_pack_ctrl_send_be((u_int32_t*)cur_loc_p,  /* Pack Control segment */\r
2709     send_req_p->comp_type, send_req_p->set_se, 0/*event bit*/,\r
2710     ((send_req_p->opcode == VAPI_RDMA_WRITE_WITH_IMM) ||\r
2711      (send_req_p->opcode == VAPI_SEND_WITH_IMM) ) ? send_req_p->imm_data : 0);\r
2712 \r
2713   /* Transport type checks: Datagram segment */\r
2714   switch (qp->ts_type) {\r
2715     case VAPI_TS_UD:  /* Check if UD (UD datagram segment) */\r
2716       cur_loc_p+= WQE_pack_ud_be((u_int32_t*)cur_loc_p,\r
2717         qp->ud_av_memkey,translate_av(qp, (u_int64_t)send_req_p->remote_ah),\r
2718         send_req_p->remote_qp,send_req_p->remote_qkey);\r
2719       break;\r
2720     case VAPI_TS_RD:  /* Check if RD (RD datagram segment) */\r
2721       cur_loc_p+= WQE_pack_rd_be((u_int32_t*)cur_loc_p,\r
2722         send_req_p->remote_qp,send_req_p->remote_qkey);\r
2723       break;\r
2724     default:\r
2725       break;\r
2726   }\r
2727   \r
2728   /* Opcode checks + Remote-address/Atomic segments */\r
2729   switch (send_req_p->opcode) {\r
2730     /* For RDMA operations: only Remote-address segment */\r
2731     case VAPI_RDMA_WRITE:\r
2732     case VAPI_RDMA_WRITE_WITH_IMM:\r
2733       cur_loc_p+= WQE_pack_remote_addr_be((u_int32_t*)cur_loc_p,\r
2734         send_req_p->remote_addr,send_req_p->r_key);\r
2735       break;\r
2736     \r
2737     case VAPI_SEND:\r
2738     case VAPI_SEND_WITH_IMM:\r
2739       break; /* Valid opcodes for "inline" but no extra WQE segment */\r
2740     default: \r
2741       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2742       return HH_EINVAL_OPCODE; /* Invalid opcode */\r
2743   }\r
2744   \r
2745   inline_p= (u_int32_t*)cur_loc_p;   \r
2746   cur_loc_p+= WQE_INLINE_SZ_BCOUNT;\r
2747   /* copy inline data to WQE */\r
2748   for (i= 0; i < send_req_p->sg_lst_len; i++) {         \r
2749         if (MOSAL_EXPECT_FALSE((cur_loc_p+send_req_p->sg_lst_p[i].len) > wqe_edge_p)) {\r
2750                 MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2751                 MTL_ERROR2(MT_FLFMT("too much inline data for inline send request (qpn=0x%X)"),qp->qpn);\r
2752                 return HH_EINVAL_SG_NUM;\r
2753         }\r
2754 //#ifdef MT_64BIT               \r
2755 #if 0   /* TBD: It this needed? */\r
2756         if (MOSAL_EXPECT_FALSE(send_req_p->sg_lst_p[i].addr > (MT_virt_addr_t)0xFFFFFFFFFFFFFFFF)) {\r
2757                 MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2758                 MTL_ERROR2(MT_FLFMT("sg list addr %d has non-zero upper bits (qpn=0x%X, addr="U64_FMT") \n"),\r
2759                         i,qp->qpn,send_req_p->sg_lst_p[i].addr );\r
2760                 return HH_EINVAL_SG_FMT;        \r
2761         }\r
2762 #endif  \r
2763         memcpy(cur_loc_p, (void*)(MT_virt_addr_t)(send_req_p->sg_lst_p[i].addr),\r
2764                         send_req_p->sg_lst_p[i].len); \r
2765         cur_loc_p+= send_req_p->sg_lst_p[i].len;  \r
2766   }     \r
2767   *inline_p= \r
2768      MOSAL_cpu_to_be32(0x80000000 | (u_int32_t)(((MT_ulong_ptr_t)cur_loc_p) - ((MT_ulong_ptr_t)inline_p) - 4)); /*inline:size*/\r
2769   \r
2770   wqe_sz_dwords= (MT_UP_ALIGNX( (((MT_virt_addr_t)cur_loc_p) - ((MT_virt_addr_t)next_wqe)),\r
2771                                 WQE_SZ_MULTIPLE_SHIFT) >> 2); \r
2772 \r
2773 #ifdef MAX_DEBUG\r
2774   if ((wqe_sz_dwords<<2) > (1 << qp->sq_res.log2_max_wqe_sz)) {\r
2775     MTL_ERROR1(MT_FLFMT("QP 0x%X: Send WQE too large (%d > max=%d) !!!!!!!!!"),\r
2776       qp->qpn,(wqe_sz_dwords<<2),(1 << qp->sq_res.log2_max_wqe_sz));\r
2777         }\r
2778 #endif\r
2779 \r
2780   rc= sq_alloc_wqe_link_and_ring_be(qp,(u_int32_t*)next_wqe,wqe_sz_dwords,\r
2781 #ifdef MT_LITTLE_ENDIAN\r
2782            (u_int32_t)(inline_p - next_wqe + 1), /* swap all up to data */\r
2783 #endif\r
2784            send_req_p,encode_nopcode(send_req_p->opcode)); \r
2785   MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2786   return rc;\r
2787 }\r
2788 #endif /* USE_FAST_POST == 0 */\r
2789 \r
2790 \r
2791 HH_ret_t THHUL_qpm_post_send_reqs( \r
2792   /*IN*/ HHUL_hca_hndl_t hca, \r
2793   /*IN*/ HHUL_qp_hndl_t hhul_qp, \r
2794   /*IN*/ u_int32_t num_of_requests,\r
2795   /*IN*/ VAPI_sr_desc_t *send_req_array \r
2796 )\r
2797 {\r
2798   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2799   u_int32_t* wqe_draft= qp->sq_res.wqe_draft;\r
2800   u_int32_t next_draft[WQE_SEG_SZ_NEXT>>2]; /* Build "next" segment here */\r
2801   volatile u_int32_t* next_wqe= NULL;\r
2802   volatile u_int32_t* prev_wqe_p= NULL; \r
2803   MT_virt_addr_t first_wqe_nda= 0;\r
2804   u_int32_t first_wqe_nds= 0;\r
2805   u_int32_t wqe_sz_dwords,i;\r
2806   u_int32_t next2post_index,reqi;\r
2807   THH_uar_sendq_dbell_t sq_dbell;\r
2808 \r
2809   if (qp->sqp_type != VAPI_REGULAR_QP) {\r
2810     MTL_ERROR4(MT_FLFMT("THHUL_qpm_post_send_reqs is not supporeted for special QPs"));\r
2811     return HH_ENOSYS;\r
2812   }\r
2813   \r
2814   if (num_of_requests == 0) {\r
2815     MTL_ERROR4(MT_FLFMT("THHUL_qpm_post_send_reqs: num_of_requeusts=0 !"));\r
2816     return HH_EINVAL_PARAM;\r
2817   }\r
2818   \r
2819   if (!is_qpstate_valid_2send(qp->sq_res.qp_state)) {\r
2820    MTL_ERROR1(MT_FLFMT("%s failed: qp state %d not valid to send \n"),__func__,qp->sq_res.qp_state);\r
2821    return HH_EINVAL_QP_STATE;\r
2822  }\r
2823 \r
2824   MOSAL_spinlock_dpc_lock(&(qp->sq_res.q_lock)); /* protect wqe_draft as well as WQE allocation/link */\r
2825   \r
2826   /* Check for available WQEs */\r
2827   if (qp->sq_res.max_outs < (qp->sq_res.cur_outs + num_of_requests)) {\r
2828     MTL_ERROR4("THHUL_qpm_post_send_reqs: Not enough WQEs for %u requests (%u requests outstanding).\n",\r
2829                num_of_requests,qp->sq_res.cur_outs);\r
2830     MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2831     return HH_E2BIG_WR_NUM;\r
2832   }\r
2833 \r
2834   /* We hold this value on a seperate var. for easy rollback in case of an error */\r
2835   next2post_index= qp->sq_res.next2post_index;\r
2836 \r
2837   /* Build and link all WQEs */\r
2838   for (reqi= 0; reqi < num_of_requests; reqi++) {\r
2839     if (qp->sq_res.max_sg_sz < send_req_array[reqi].sg_lst_len) {\r
2840       MTL_ERROR2(\r
2841                 "THHUL_qpm_post_send_req: S/G list of request %d is too large (%d entries > max_sg_sz=%d)\n",\r
2842                 reqi,send_req_array[reqi].sg_lst_len,qp->sq_res.max_sg_sz);\r
2843       MOSAL_spinlock_unlock(&(qp->sq_res.q_lock));\r
2844       return HH_EINVAL_SG_NUM;\r
2845     }\r
2846 \r
2847     MTPERF_TIME_START(WQE_build_send);\r
2848     wqe_sz_dwords= (WQE_build_send(qp,send_req_array+reqi,wqe_draft) >> 2);\r
2849     MTPERF_TIME_END(WQE_build_send);\r
2850 #ifdef MAX_DEBUG\r
2851     if ((wqe_sz_dwords<<2) > (1U << qp->sq_res.log2_max_wqe_sz)) {\r
2852       MTL_ERROR1(MT_FLFMT("QP 0x%X: Send WQE too large (%d > max=%d)"),\r
2853                  qp->qpn,(wqe_sz_dwords<<2),(1U << qp->sq_res.log2_max_wqe_sz));\r
2854         }\r
2855 #endif\r
2856     /* Allocate next WQE */\r
2857     next_wqe= (u_int32_t*)(qp->sq_res.wqe_buf + \r
2858                           (next2post_index << qp->sq_res.log2_max_wqe_sz) );\r
2859     qp->sq_res.wqe_id[next2post_index]= send_req_array[reqi].id;  /* Save WQE ID */\r
2860 //    next2post_index = (next2post_index + 1) % qp->sq_res.max_outs ;\r
2861         if (++next2post_index >= qp->sq_res.max_outs) {\r
2862                 next2post_index = 0;\r
2863         }\r
2864     /* copy (while swapping,if needed) the wqe_draft to the actual WQE */\r
2865     /* TBD: for big-endian machines we can optimize here and use memcpy */\r
2866     MTPERF_TIME_START(SQ_WQE_copy);\r
2867     for (i= 0; i < wqe_sz_dwords; i++) {\r
2868       next_wqe[i]= MOSAL_cpu_to_be32(wqe_draft[i]);\r
2869     }\r
2870 \r
2871     if (reqi == 0) { /* For the first WQE save info for linking it later */\r
2872       first_wqe_nda= (MT_virt_addr_t)next_wqe;\r
2873       first_wqe_nds= (wqe_sz_dwords>>2);\r
2874     \r
2875     } else { /* Not first - link to previous with DBD=0 */\r
2876       /* Build linking "next" segment in last posted WQE*/\r
2877       qpm_WQE_pack_send_next(next_draft, encode_nopcode(send_req_array[reqi].opcode), \r
2878         send_req_array[reqi].fence,0/*DBD*/, (u_int32_t)(MT_ulong_ptr_t)next_wqe, wqe_sz_dwords>>2, \r
2879         (qp->ts_type==VAPI_TS_RD) ? send_req_array[reqi].eecn : 0 );\r
2880       for (i= 0;i < (WQE_SEG_SZ_NEXT>>2) ;i++) {  \r
2881         /* This copy assures big-endian as well as that NDS is written last */\r
2882         prev_wqe_p[i]= MOSAL_cpu_to_be32(next_draft[i]);\r
2883       }\r
2884     }\r
2885     prev_wqe_p= next_wqe;\r
2886 \r
2887   }\r
2888   \r
2889   if (qp->sq_res.last_posted_p != NULL) { /* link chain to previous WQE */\r
2890     /* Build linking "next" segment with DBD set */\r
2891     qpm_WQE_pack_send_next(next_draft, encode_nopcode(send_req_array[0].opcode), \r
2892       send_req_array[0].fence,1/*DBD*/, (u_int32_t)first_wqe_nda, first_wqe_nds, \r
2893       (qp->ts_type==VAPI_TS_RD) ? send_req_array[0].eecn : 0 );\r
2894     for (i= 0;i < (WQE_SEG_SZ_NEXT>>2) ;i++) {  \r
2895       /* This copy assures big-endian as well as that NDS is written last */\r
2896       qp->sq_res.last_posted_p[i]= MOSAL_cpu_to_be32(next_draft[i]);\r
2897     }\r
2898   }\r
2899   \r
2900   /* Update QP status */\r
2901   qp->sq_res.last_posted_p= next_wqe; \r
2902   qp->sq_res.next2post_index= next2post_index;\r
2903   qp->sq_res.cur_outs+= num_of_requests;\r
2904 \r
2905   /* Ring doorbell (send or rd-send) */\r
2906   sq_dbell.qpn= qp->qpn;\r
2907   sq_dbell.nopcode= encode_nopcode(send_req_array[0].opcode);\r
2908   sq_dbell.fence= send_req_array[0].fence;\r
2909   sq_dbell.next_addr_32lsb= (u_int32_t)(first_wqe_nda & 0xFFFFFFFF);\r
2910   sq_dbell.next_size= first_wqe_nds;\r
2911   if (qp->ts_type == VAPI_TS_RD) {\r
2912     THH_uar_sendq_rd_dbell(qp->uar,&sq_dbell,send_req_array[0].eecn);\r
2913   } else {  /* non-RD send request */\r
2914     MTPERF_TIME_START(THH_uar_sendq_dbell);\r
2915     THH_uar_sendq_dbell(qp->uar,&sq_dbell);\r
2916     MTPERF_TIME_END(THH_uar_sendq_dbell);\r
2917   }\r
2918 \r
2919   MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2920   return HH_OK;\r
2921 }\r
2922 \r
2923 HH_ret_t THHUL_qpm_post_gsi_send_req( \r
2924    HHUL_hca_hndl_t hca, \r
2925    HHUL_qp_hndl_t hhul_qp, \r
2926    VAPI_sr_desc_t *send_req_p,\r
2927    VAPI_pkey_ix_t pkey_index\r
2928\r
2929\r
2930   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2931   u_int32_t* wqe_draft= qp->sq_res.wqe_draft;\r
2932   u_int32_t wqe_sz_dwords;\r
2933   HH_hca_hndl_t hca_ul_res_handle;\r
2934   HH_ret_t rc;\r
2935 \r
2936   if (MOSAL_EXPECT_FALSE(qp->sqp_type != VAPI_GSI_QP))  {\r
2937     MTL_ERROR2(MT_FLFMT("Invoked for non-GSI QP (qpn=0x%X)"),qp->qpn);\r
2938     return HH_EINVAL_QP_NUM;\r
2939   }\r
2940   \r
2941   if (MOSAL_EXPECT_FALSE(qp->sq_res.max_sg_sz < send_req_p->sg_lst_len)) {\r
2942     MTL_ERROR2(\r
2943       "%s: Scatter/Gather list is too large (%d entries > max_sg_sz=%d)\n",__func__,\r
2944       send_req_p->sg_lst_len,qp->sq_res.max_sg_sz);\r
2945     return HH_EINVAL_SG_NUM;\r
2946   }\r
2947    \r
2948   if (MOSAL_EXPECT_FALSE(!is_qpstate_valid_2send(qp->sq_res.qp_state))) {\r
2949    MTL_ERROR1(MT_FLFMT("%s failed: qp state %d not valid to send \n"),__func__,qp->sq_res.qp_state);\r
2950    return HH_EINVAL_QP_STATE;\r
2951  }\r
2952 \r
2953 #ifdef DUMP_SEND_REQ \r
2954   dump_send_req(qp,send_req_p);\r
2955 #endif\r
2956   \r
2957   send_req_p->fence= FALSE; /* required for MLX requests */\r
2958   rc= THHUL_hob_get_hca_ul_res_handle(hca,&hca_ul_res_handle);\r
2959   if (rc != HH_OK) {\r
2960     return HH_EINVAL_HCA_HNDL;\r
2961   }\r
2962 \r
2963   MOSAL_spinlock_dpc_lock(&(qp->sq_res.q_lock)); /* protect wqe_draft and WQE allocation/link */\r
2964   \r
2965   wqe_sz_dwords= \r
2966     (WQE_build_send_mlx(hca_ul_res_handle,qp,send_req_p,pkey_index,wqe_draft) >> 2);\r
2967   if (wqe_sz_dwords == 0) {\r
2968     MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2969     MTL_ERROR1(MT_FLFMT("Failed building MLX headers for special QP.\n"));\r
2970     return HH_EINVAL_WQE;\r
2971   }\r
2972 \r
2973   rc= sq_alloc_wqe_link_and_ring(qp,wqe_draft,wqe_sz_dwords,\r
2974 #ifdef MT_LITTLE_ENDIAN\r
2975            wqe_sz_dwords,\r
2976 #endif\r
2977            send_req_p,encode_nopcode(send_req_p->opcode)); \r
2978   \r
2979   MOSAL_spinlock_unlock(&(qp->sq_res.q_lock)); \r
2980   return rc;\r
2981 }\r
2982 \r
2983 \r
2984 /* Orignal version of THHUL_qpm_post_recv_req */\r
2985 #if !(USE_FAST_POST)\r
2986 HH_ret_t THHUL_qpm_post_recv_req( \r
2987    HHUL_hca_hndl_t hca, \r
2988    HHUL_qp_hndl_t hhul_qp, \r
2989    VAPI_rr_desc_t *recv_req_p \r
2990\r
2991\r
2992   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
2993   u_int32_t* wqe_draft= qp->rq_res.wqe_draft;\r
2994   u_int32_t next_draft[WQE_SEG_SZ_NEXT>>2]; /* Build "next" segment here */\r
2995   volatile u_int32_t* next_wqe; /* Actual WQE pointer */\r
2996   u_int32_t i, wqe_sz_dwords;\r
2997   THH_uar_recvq_dbell_t rq_dbell;\r
2998 \r
2999   if (qp->srq != HHUL_INVAL_SRQ_HNDL) {\r
3000     MTL_ERROR1(MT_FLFMT("%s: Used for QP 0x%X which is associated with SRQ handle 0x%p"), __func__,\r
3001                qp->qpn, qp->srq);\r
3002     return HH_EINVAL_SRQ_HNDL;\r
3003   }\r
3004 \r
3005   if (!is_qpstate_valid_2recv(qp->rq_res.qp_state)) {\r
3006    MTL_ERROR1(MT_FLFMT("%s failed: qp state %d not valid to recv \n"),__func__,qp->rq_res.qp_state);\r
3007    return HH_EINVAL_QP_STATE;\r
3008  }\r
3009 \r
3010   if (qp->rq_res.max_sg_sz < recv_req_p->sg_lst_len) {\r
3011     MTL_ERROR2(\r
3012       "THHUL_qpm_post_recv_req: Scatter/Gather list is too large (%d entries > max_sg_sz=%d)\n",\r
3013       recv_req_p->sg_lst_len,qp->rq_res.max_sg_sz);\r
3014     return HH_EINVAL_SG_NUM;\r
3015   }\r
3016    \r
3017   MOSAL_spinlock_dpc_lock(&(qp->rq_res.q_lock)); /* protect wqe_draft as well as WQE allocation/link */\r
3018   \r
3019   /* Build WQE */\r
3020   wqe_sz_dwords= (qpm_WQE_build_recv(qp,recv_req_p,wqe_draft) >> 2);\r
3021 #ifdef MAX_DEBUG\r
3022     if ((wqe_sz_dwords<<2) > (1U << qp->rq_res.log2_max_wqe_sz)) {\r
3023       MTL_ERROR1(MT_FLFMT("QP 0x%X: Receive WQE too large (%d > max=%d)"),\r
3024         qp->qpn,(wqe_sz_dwords<<2),(1U << qp->rq_res.log2_max_wqe_sz));\r
3025         }\r
3026 #endif\r
3027 \r
3028   /* Check if any WQEs are free to be consumed */\r
3029   if (qp->rq_res.max_outs == qp->rq_res.cur_outs) {\r
3030     MOSAL_spinlock_unlock(&(qp->rq_res.q_lock));\r
3031     MTL_ERROR4("THHUL_qpm_post_recv_req: Receive queue is full (%d requests outstanding).\n",\r
3032       qp->rq_res.cur_outs);\r
3033     return HH_E2BIG_WR_NUM;\r
3034   }\r
3035   /* Allocate next WQE */\r
3036   next_wqe= (u_int32_t*) (qp->rq_res.wqe_buf + \r
3037                           (qp->rq_res.next2post_index << qp->rq_res.log2_max_wqe_sz) );\r
3038   qp->rq_res.wqe_id[qp->rq_res.next2post_index]= recv_req_p->id;  /* Save WQE ID */\r
3039   qp->rq_res.next2post_index = (qp->rq_res.next2post_index + 1) % qp->rq_res.max_outs ;\r
3040   qp->rq_res.cur_outs++;\r
3041   \r
3042   /* copy (while swapping,if needed) the wqe_draft to the actual WQE */\r
3043   /* TBD: for big-endian machines we can optimize here and use memcpy */\r
3044   for (i= 0; i < wqe_sz_dwords; i++) {\r
3045     next_wqe[i]= MOSAL_cpu_to_be32(wqe_draft[i]);\r
3046   }\r
3047 \r
3048   /* Update "next" segment of previous WQE (if any) */\r
3049   if (qp->rq_res.last_posted_p != NULL) {\r
3050     /* Build linking "next" segment in last posted WQE */\r
3051     qpm_WQE_pack_recv_next(next_draft, (u_int32_t)(MT_ulong_ptr_t) next_wqe, wqe_sz_dwords>>2);\r
3052     for (i= 0;i < (WQE_SEG_SZ_NEXT>>2) ;i++) {  \r
3053       /* This copy assures big-endian as well as that NDS is written last */\r
3054       qp->rq_res.last_posted_p[i]= MOSAL_cpu_to_be32(next_draft[i]);\r
3055     }\r
3056   }\r
3057   qp->rq_res.last_posted_p= next_wqe;\r
3058   \r
3059   /* Ring doorbell */\r
3060   rq_dbell.qpn= qp->qpn;\r
3061   rq_dbell.next_addr_32lsb= (u_int32_t)((MT_virt_addr_t)next_wqe & 0xFFFFFFFF);\r
3062   rq_dbell.next_size= wqe_sz_dwords>>2;\r
3063   rq_dbell.credits= 1;\r
3064   THH_uar_recvq_dbell(qp->uar,&rq_dbell);\r
3065 \r
3066   MOSAL_spinlock_unlock(&(qp->rq_res.q_lock));\r
3067   return HH_OK;\r
3068   \r
3069 }\r
3070 #else /* USE_FAST_POST == 1 */\r
3071 /* Optimized version of post_recv_reqs \r
3072  * Remove double copy of building wqe from wqe_draft to wqe_buf, instead\r
3073  * write driectly to wqe_buf. Conversion to be was done when copy to wqe_buf from\r
3074  * wqe_draft, now ew have to build big endian version directly. All the function\r
3075  * with ***_be extention build big_endian version of WQE.\r
3076  */ \r
3077 HH_ret_t THHUL_qpm_post_recv_req( \r
3078    HHUL_hca_hndl_t hca, \r
3079    HHUL_qp_hndl_t hhul_qp, \r
3080    VAPI_rr_desc_t *recv_req_p \r
3081\r
3082\r
3083   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
3084   volatile u_int32_t* next_wqe; /* Actual WQE pointer */\r
3085   u_int32_t wqe_sz_dwords;\r
3086   CHIME_WORDS_PREFIX u_int32_t chimeWords[2];\r
3087   THH_uar_t uar;\r
3088 \r
3089   if (MOSAL_EXPECT_FALSE(qp->srq != HHUL_INVAL_SRQ_HNDL)) {\r
3090     MTL_ERROR1(MT_FLFMT("%s: Used for QP 0x%X which is associated with SRQ handle 0x%p"), __func__,\r
3091                qp->qpn, qp->srq);\r
3092     return HH_EINVAL_SRQ_HNDL;\r
3093   }\r
3094   \r
3095   if (MOSAL_EXPECT_FALSE(qp->rq_res.qp_state < VAPI_INIT )) {\r
3096    MTL_ERROR1(MT_FLFMT("%s failed: qp state %d not valid to recv \n"),__func__,qp->rq_res.qp_state);\r
3097    return HH_EINVAL_QP_STATE;\r
3098   }\r
3099 \r
3100   if (MOSAL_EXPECT_FALSE(qp->rq_res.max_sg_sz < recv_req_p->sg_lst_len)) {\r
3101     MTL_ERROR2(\r
3102       "THHUL_qpm_post_recv_req: Scatter/Gather list is too large (%d entries > max_sg_sz=%d)\n",\r
3103       recv_req_p->sg_lst_len,qp->rq_res.max_sg_sz);\r
3104     return HH_EINVAL_SG_NUM;\r
3105   }\r
3106    \r
3107   MOSAL_spinlock_dpc_lock(&(qp->rq_res.q_lock)); /* protect wqe_draft as well as WQE allocation/link */\r
3108   \r
3109   /* Check if any WQEs are free to be consumed */\r
3110   if (MOSAL_EXPECT_FALSE(qp->rq_res.max_outs == qp->rq_res.cur_outs)) {\r
3111     MOSAL_spinlock_unlock(&(qp->rq_res.q_lock));\r
3112     MTL_ERROR4("THHUL_qpm_post_recv_req: Receive queue is full (%d requests outstanding).\n",\r
3113       qp->rq_res.cur_outs);\r
3114     return HH_E2BIG_WR_NUM;\r
3115   }\r
3116   /* Allocate next WQE */\r
3117   /* Build WQE directly to wqe_buf, instead of draft. This will eliminate extra copy, but\r
3118    * shuold build big endian version */\r
3119   next_wqe= (u_int32_t*) (qp->rq_res.wqe_buf + \r
3120                           (qp->rq_res.next2post_index << qp->rq_res.log2_max_wqe_sz) );\r
3121   \r
3122   /* Build WQE */\r
3123   /* Call big Endian version of WQE_build_recv */\r
3124   wqe_sz_dwords= (WQE_build_recv_be(qp,recv_req_p,(u_int32_t*)next_wqe) >> 2);\r
3125 #ifdef MAX_DEBUG\r
3126     if ((wqe_sz_dwords<<2) > (1 << qp->rq_res.log2_max_wqe_sz)) {\r
3127       MTL_ERROR1(MT_FLFMT("QP 0x%X: Receive WQE too large (%d > max=%d)"),\r
3128         qp->qpn,(wqe_sz_dwords<<2),(1 << qp->rq_res.log2_max_wqe_sz));\r
3129         }\r
3130 #endif\r
3131 \r
3132   qp->rq_res.wqe_id[qp->rq_res.next2post_index]= recv_req_p->id;  /* Save WQE ID */\r
3133   ++qp->rq_res.next2post_index;\r
3134   if(MOSAL_EXPECT_FALSE(qp->rq_res.next2post_index >= qp->rq_res.max_outs))\r
3135           qp->rq_res.next2post_index = 0;\r
3136   \r
3137   qp->rq_res.cur_outs++;\r
3138   \r
3139    /* Update "next" segment of previous WQE (if any) */\r
3140    /* Build linking "next" segment in last posted WQE */\r
3141    WQE_pack_recv_next_be((u_int32_t*)qp->rq_res.last_posted_p, \r
3142                    (u_int32_t)(MT_ulong_ptr_t) next_wqe, wqe_sz_dwords>>2);\r
3143 \r
3144    qp->rq_res.last_posted_p= next_wqe;\r
3145   \r
3146   /* Ring doorbell */   \r
3147    uar = qp->uar;\r
3148 \r
3149    chimeWords[0] = MOSAL_cpu_to_be32(0\r
3150                 | (u_int32_t)((MT_ulong_ptr_t)next_wqe & 0xFFFFFFFF)\r
3151                 | ((wqe_sz_dwords + 3) >> 2) // specify in 16 byte chunks\r
3152                 );\r
3153         \r
3154    chimeWords[1] = MOSAL_cpu_to_be32(0\r
3155                 | 1 // credits\r
3156                 | ((u_int32_t)(qp->qpn) << 8)\r
3157                 );\r
3158 \r
3159 #ifdef __MOSAL_MMAP_IO_WRITE_QWORD_ATOMIC__\r
3160         MOSAL_MMAP_IO_WRITE_QWORD(((u_int32_t *)&uar->uar_base[UAR_RECV_DBELL_OFFSET]),*(volatile u_int64_t*)chimeWords);\r
3161 #else\r
3162         MOSAL_spinlock_dpc_lock(&(uar->uar_lock));\r
3163         MOSAL_MMAP_IO_WRITE_QWORD(((u_int32_t *)&uar->uar_base[UAR_RECV_DBELL_OFFSET]),*(volatile u_int64_t*)chimeWords);\r
3164         MOSAL_spinlock_unlock(&(uar->uar_lock));\r
3165 #endif\r
3166  \r
3167   MOSAL_spinlock_unlock(&(qp->rq_res.q_lock));\r
3168   \r
3169   return HH_OK;\r
3170\r
3171 #endif\r
3172 \r
3173 \r
3174 HH_ret_t THHUL_qpm_post_recv_reqs(\r
3175                                  /*IN*/ HHUL_hca_hndl_t hca, \r
3176                                  /*IN*/ HHUL_qp_hndl_t hhul_qp, \r
3177                                  /*IN*/ u_int32_t num_of_requests,\r
3178                                  /*IN*/ VAPI_rr_desc_t *recv_req_array \r
3179                                  )\r
3180 {\r
3181   THHUL_qp_t qp= (THHUL_qp_t)hhul_qp;\r
3182   u_int32_t* wqe_draft= qp->rq_res.wqe_draft;\r
3183   u_int32_t next_draft[WQE_SEG_SZ_NEXT>>2]; /* Build "next" segment here */\r
3184   volatile u_int32_t* next_wqe= NULL; /* Actual WQE pointer */\r
3185   volatile u_int32_t* prev_wqe_p= qp->rq_res.last_posted_p; \r
3186   u_int32_t wqe_sz_dwords= 0;\r
3187   u_int32_t i,reqi,next2post_index;\r
3188   THH_uar_recvq_dbell_t rq_dbell;\r
3189   u_int32_t remaining_reqs;\r
3190 \r
3191   if (qp->srq != HHUL_INVAL_SRQ_HNDL) {\r
3192     MTL_ERROR1(MT_FLFMT("%s: Used for QP 0x%X which is associated with SRQ 0x%p"), __func__,\r
3193                qp->qpn, qp->srq);\r
3194     return HH_EINVAL_SRQ_HNDL;\r
3195   }\r
3196 \r
3197   if (!is_qpstate_valid_2recv(qp->rq_res.qp_state)) {\r
3198     MTL_ERROR1(MT_FLFMT("%s failed: qp state %d not valid to recv \n"),__func__,qp->rq_res.qp_state);\r
3199     return HH_EINVAL_QP_STATE;\r
3200   }\r
3201 \r
3202   if (num_of_requests == 0) {\r
3203     MTL_ERROR4(MT_FLFMT("THHUL_qpm_post_recv_reqs: num_of_requeusts=0 !"));\r
3204     return HH_EINVAL_PARAM;\r
3205   }\r
3206 \r
3207   /* Check parameters of all WQEs first - must assure all posted successfully */\r
3208   for (reqi= 0; reqi < num_of_requests; reqi++) {\r
3209     if (qp->rq_res.max_sg_sz < recv_req_array[reqi].sg_lst_len) {\r
3210       MTL_ERROR2(\r
3211         "THHUL_qpm_post_recv_reqs: S/G list of req. #%d is too large (%d entries > max_sg_sz=%d)\n",\r
3212                 reqi,recv_req_array[reqi].sg_lst_len,qp->rq_res.max_sg_sz);\r
3213       return HH_EINVAL_SG_NUM;\r
3214     }\r
3215   }\r
3216 \r
3217   MOSAL_spinlock_dpc_lock(&(qp->rq_res.q_lock)); /* protect wqe_draft as well as WQE allocation/link */\r
3218   \r
3219   /* Check for available WQEs */\r
3220   if (qp->rq_res.max_outs < (qp->rq_res.cur_outs + num_of_requests)) {\r
3221     MTL_ERROR4("THHUL_qpm_post_recv_reqs: Not enough WQEs for %d requests (%d requests outstanding).\n",\r
3222                num_of_requests,qp->rq_res.cur_outs);\r
3223     MOSAL_spinlock_unlock(&(qp->rq_res.q_lock));\r
3224     return HH_E2BIG_WR_NUM;\r
3225   }\r
3226 \r
3227   rq_dbell.qpn= qp->qpn; /* Fixed for all doorbells */\r
3228   rq_dbell.credits= 0; /* During the loop, doorbell is rung every 256 WQEs */\r
3229   \r
3230   /* We hold this value on a seperate var. for easy rollback in case of an error */\r
3231   next2post_index= qp->rq_res.next2post_index;\r
3232 \r
3233   /* Build and link and ring all WQEs */\r
3234   for (reqi= 0; reqi < num_of_requests; reqi++) {\r
3235     \r
3236     /* Build WQE */\r
3237     wqe_sz_dwords= (qpm_WQE_build_recv(qp,recv_req_array+reqi,wqe_draft) >> 2);\r
3238   #ifdef MAX_DEBUG\r
3239     if ((wqe_sz_dwords<<2) > (1U << qp->rq_res.log2_max_wqe_sz)) {\r
3240       MTL_ERROR1(MT_FLFMT("QP 0x%X: Receive WQE too large (%d > max=%d)"),