f00f814f69786b3b35ebc5cfb85c39dd4b31d0ea
[mirror/winof/.git] / hw / mlx4 / kernel / hca / vp.c
1 /*
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.
3  * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. 
4  *
5  * This software is available to you under the OpenIB.org BSD license
6  * below:
7  *
8  *     Redistribution and use in source and binary forms, with or
9  *     without modification, are permitted provided that the following
10  *     conditions are met:
11  *
12  *      - Redistributions of source code must retain the above
13  *        copyright notice, this list of conditions and the following
14  *        disclaimer.
15  *
16  *      - Redistributions in binary form must reproduce the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer in the documentation and/or other materials
19  *        provided with the distribution.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28  * SOFTWARE.
29  *
30  * $Id: hca_verbs.c 2073 2007-11-13 11:38:40Z leonid $
31  */
32
33 #include "precomp.h"
34
35 #if defined(EVENT_TRACING)
36 #ifdef offsetof
37 #undef offsetof
38 #endif
39 #include "vp.tmh"
40 #endif
41
42 static ib_api_status_t
43 mlnx_um_open(
44         IN              const   ib_ca_handle_t                          h_ca,
45         IN      OUT                     ci_umv_buf_t* const                     p_umv_buf,
46                 OUT                     ib_ca_handle_t* const           ph_um_ca )
47 {
48         ib_api_status_t         status;
49         mlnx_hca_t                      *p_hca = (mlnx_hca_t *)h_ca;
50         PFDO_DEVICE_DATA p_fdo = hca2fdo(p_hca);
51         struct ib_device *p_ibdev = hca2ibdev(p_hca);
52         struct ib_ucontext *p_uctx;
53         struct ibv_get_context_resp *p_uresp;
54
55         HCA_ENTER(HCA_DBG_SHIM);
56
57         // sanity check
58         ASSERT( p_umv_buf );
59         if( !p_umv_buf->command )
60         { // no User Verb Provider
61                 p_uctx = cl_zalloc( sizeof(struct ib_ucontext) );
62                 if( !p_uctx )
63                 {
64                         status = IB_INSUFFICIENT_MEMORY;
65                         goto err_alloc_ucontext;
66                 }
67                 /* Copy the dev info. */
68                 p_uctx->device = p_ibdev;
69                 p_umv_buf->output_size = 0;
70                 status = IB_SUCCESS;
71                 goto done;
72         }
73
74         // sanity check
75         if ( p_umv_buf->output_size < sizeof(struct ibv_get_context_resp) ||
76                 !p_umv_buf->p_inout_buf) {
77                 status = IB_INVALID_PARAMETER;
78                 goto err_inval_params;
79         }
80
81         status = ibv_um_open( p_ibdev, p_umv_buf, &p_uctx );
82         if (!NT_SUCCESS(status)) {
83                 goto end;
84         }
85         
86         // fill more parameters for user (sanity checks are in mthca_alloc_ucontext) 
87         p_uresp = (struct ibv_get_context_resp *)(void*)p_umv_buf->p_inout_buf;
88         p_uresp->vend_id                 = (uint32_t)p_fdo->bus_ib_ifc.pdev->ven_id;
89         p_uresp->dev_id                  = (uint16_t)p_fdo->bus_ib_ifc.pdev->dev_id;
90         p_uresp->max_qp_wr               = hca2mdev(p_hca)->caps.max_wqes;
91         p_uresp->max_cqe                 = hca2mdev(p_hca)->caps.max_cqes;
92         p_uresp->max_sge                 = min( hca2mdev(p_hca)->caps.max_sq_sg,
93                 hca2mdev(p_hca)->caps.max_rq_sg );
94
95 done:
96         // fill the rest of ib_ucontext_ex fields 
97         atomic_set(&p_uctx->x.usecnt, 0);
98         p_uctx->x.va = p_uctx->x.p_mdl = NULL;
99         p_uctx->x.fw_if_open = FALSE;
100         mutex_init( &p_uctx->x.mutex );
101
102         // chain user context to the device
103         spin_lock( &p_fdo->uctx_lock );
104         cl_qlist_insert_tail( &p_fdo->uctx_list, &p_uctx->x.list_item );
105         cl_atomic_inc(&p_fdo->usecnt);
106         spin_unlock( &p_fdo->uctx_lock );
107         
108         // return the result
109         if (ph_um_ca) *ph_um_ca = (ib_ca_handle_t)p_uctx;
110
111         status = IB_SUCCESS;
112         goto end;
113
114 err_inval_params:
115 err_alloc_ucontext:
116 end:
117         if (p_umv_buf && p_umv_buf->command) 
118                 p_umv_buf->status = status;
119         if (status != IB_SUCCESS) 
120         {
121                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM,
122                         ("completes with ERROR status %x\n", status));
123         }
124         HCA_EXIT(HCA_DBG_SHIM);
125         return status;
126 }
127
128
129 static void
130 mlnx_um_close(
131         IN                              ib_ca_handle_t                          h_ca,
132         IN                              ib_ca_handle_t                          h_um_ca )
133 {
134         struct ib_ucontext *p_uctx = (struct ib_ucontext *)h_um_ca;
135         PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo;
136
137         UNUSED_PARAM(h_ca);
138         
139         if ( !hca_is_livefish(p_fdo))
140                 unmap_crspace_for_all(p_uctx);
141         spin_lock( &p_fdo->uctx_lock );
142         cl_qlist_remove_item( &p_fdo->uctx_list, &p_uctx->x.list_item );
143         cl_atomic_dec(&p_fdo->usecnt);
144         spin_unlock( &p_fdo->uctx_lock );
145         if( !p_uctx->x.uar.kva)
146                 cl_free( h_um_ca );             // no User Verb Provider
147         else 
148                 ibv_um_close(p_uctx);
149 #if 0
150         // TODO: replace where pa_cash.c is found
151         pa_cash_print();
152 #endif
153         return;
154 }
155
156
157 ib_api_status_t
158 mlnx_local_mad (
159         IN              const   ib_ca_handle_t                          h_ca,
160         IN              const   uint8_t                                         port_num,
161         IN              const   ib_av_attr_t*                                   p_av_attr,
162         IN              const   ib_mad_t                                        *p_mad_in,
163         OUT             ib_mad_t                                        *p_mad_out )
164 {
165         int err;
166         ib_api_status_t         status = IB_SUCCESS;
167         mlnx_hca_t                      *p_hca = (mlnx_hca_t *)h_ca;
168         PFDO_DEVICE_DATA p_fdo = hca2fdo(p_hca);
169         struct ib_device *p_ibdev = p_fdo->bus_ib_ifc.p_ibdev;
170         //TODO: do we need use flags (IB_MAD_IGNORE_MKEY, IB_MAD_IGNORE_BKEY) ?
171         int mad_flags = 0;  
172         //TODO: do we need use grh ?
173         struct ib_grh *p_grh = NULL;
174         ib_wc_t *p_wc = NULL;
175
176         HCA_ENTER(HCA_DBG_MAD);
177
178         // sanity checks
179         if (port_num > 2) {
180                 status = IB_INVALID_PARAMETER;
181                 goto err_port_num;
182         }
183
184         if (p_av_attr){
185                 p_wc = cl_zalloc(sizeof(ib_wc_t));
186                 if(!p_wc){
187                         status =  IB_INSUFFICIENT_MEMORY ;
188                         goto err_wc_alloc;
189                 }
190                 //Copy part of the attributes need to fill the mad extended fields in mellanox devices
191                 p_wc->recv.ud.remote_lid = p_av_attr->dlid;
192                 p_wc->recv.ud.remote_sl  = p_av_attr->sl;
193                 p_wc->recv.ud.path_bits  = p_av_attr->path_bits;
194                 p_wc->recv.ud.recv_opt = p_av_attr->grh_valid ? IB_RECV_OPT_GRH_VALID : 0;
195
196                 if(p_wc->recv.ud.recv_opt & IB_RECV_OPT_GRH_VALID){
197                         p_grh = cl_zalloc(sizeof(struct _ib_grh));
198                         if(!p_grh){
199                                 status =  IB_INSUFFICIENT_MEMORY ;
200                                 goto err_grh_alloc;
201                         }
202                         p_grh->version_tclass_flow      = p_av_attr->grh.ver_class_flow;
203                         p_grh->hop_limit                        = p_av_attr->grh.hop_limit;
204                         cl_memcpy( &p_grh->sgid, &p_av_attr->grh.src_gid, sizeof(p_grh->sgid) );
205                         cl_memcpy( &p_grh->dgid, &p_av_attr->grh.dest_gid, sizeof(p_grh->dgid) );
206                         // TODO: no direct analogue in IBAL (seems like it is from rmpp)
207                         p_grh->paylen                           = 0;
208                         p_grh->next_hdr                         = 0;
209                 }
210                         
211
212         }
213
214         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_MAD, 
215                 ("MAD: Class %02x, Method %02x, Attr %02x, HopPtr %d, HopCnt %d, \n",
216                 (uint32_t)((ib_smp_t *)p_mad_in)->mgmt_class, 
217                 (uint32_t)((ib_smp_t *)p_mad_in)->method, 
218                 (uint32_t)((ib_smp_t *)p_mad_in)->attr_id, 
219                 (uint32_t)((ib_smp_t *)p_mad_in)->hop_ptr,
220                 (uint32_t)((ib_smp_t *)p_mad_in)->hop_count));
221
222         // process mad
223         err = p_ibdev->process_mad( p_ibdev, mad_flags, (uint8_t)port_num, 
224                 p_wc, p_grh, (struct ib_mad*)p_mad_in, (struct ib_mad*)p_mad_out);
225         if (!err) {
226                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_MAD, 
227                         ("MAD failed:\n\tClass 0x%x\n\tMethod 0x%x\n\tAttr 0x%x",
228                         p_mad_in->mgmt_class, p_mad_in->method, p_mad_in->attr_id ));
229                 status = IB_ERROR;
230                 goto err_process_mad;
231         }
232         
233         if( (p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR ||
234                 p_mad_in->mgmt_class == IB_MCLASS_SUBN_LID) &&
235                 p_mad_in->attr_id == IB_MAD_ATTR_PORT_INFO )
236         {
237                 ib_port_info_t  *p_pi_in, *p_pi_out;
238
239                 if( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR )
240                 {
241                         p_pi_in = (ib_port_info_t*)
242                                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_in );
243                         p_pi_out = (ib_port_info_t*)
244                                 ib_smp_get_payload_ptr( (ib_smp_t*)p_mad_out );
245                 }
246                 else
247                 {
248                         p_pi_in = (ib_port_info_t*)(p_mad_in + 1);
249                         p_pi_out = (ib_port_info_t*)(p_mad_out + 1);
250                 }
251
252                 /* Work around FW bug 33958 */
253                 p_pi_out->subnet_timeout &= 0x7F;
254                 if( p_mad_in->method == IB_MAD_METHOD_SET )
255                         p_pi_out->subnet_timeout |= (p_pi_in->subnet_timeout & 0x80);
256         }
257
258         /* Modify direction for Direct MAD */
259         if ( p_mad_in->mgmt_class == IB_MCLASS_SUBN_DIR )
260                 p_mad_out->status |= IB_SMP_DIRECTION;
261
262
263 err_process_mad:
264         if(p_grh)
265                 cl_free(p_grh);
266 err_grh_alloc:
267         if(p_wc)
268                 cl_free(p_wc);
269 err_wc_alloc:
270 err_port_num:   
271         if (status != IB_SUCCESS)
272         {
273                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MAD,
274                         ("completes with ERROR status %x\n", status));
275         }
276         HCA_EXIT(HCA_DBG_MAD);
277         return status;
278 }
279         
280
281 void
282 setup_ci_interface(
283         IN              const   ib_net64_t                                      ca_guid,
284         IN              const   int                                                     is_livefish,
285         IN      OUT                     ci_interface_t                          *p_interface )
286 {
287         cl_memclr(p_interface, sizeof(*p_interface));
288
289         /* Guid of the CA. */
290         p_interface->guid = ca_guid;
291
292         /* Version of this interface. */
293         p_interface->version = VERBS_VERSION;
294
295         /* UVP name */
296         cl_memcpy( p_interface->libname, mlnx_uvp_lib_name, MAX_LIB_NAME);
297
298         HCA_PRINT(TRACE_LEVEL_VERBOSE  , HCA_DBG_SHIM  ,("UVP filename %s\n", p_interface->libname));
299
300         /* The real interface. */
301         mlnx_pd_if(p_interface);
302         p_interface->um_open_ca = mlnx_um_open;
303         p_interface->um_close_ca = mlnx_um_close;
304         p_interface->vendor_call = fw_access_ctrl;
305
306         if (is_livefish) {
307                 mlnx_ca_if_livefish(p_interface);
308                 mlnx_mr_if_livefish(p_interface);
309         }
310         else {  
311                 mlnx_ca_if(p_interface);
312                 mlnx_av_if(p_interface);
313                 mlnx_srq_if(p_interface);
314                 mlnx_qp_if(p_interface);
315                 mlnx_cq_if(p_interface);
316                 mlnx_mr_if(p_interface);
317                 mlnx_direct_if(p_interface);
318                 mlnx_mcast_if(p_interface);
319                 p_interface->local_mad = mlnx_local_mad;
320         }
321
322         return;
323 }
324
325