Merge nommu branch
[linux-2.6] / drivers / infiniband / hw / ehca / hcp_if.c
1 /*
2  *  IBM eServer eHCA Infiniband device driver for Linux on POWER
3  *
4  *  Firmware Infiniband Interface code for POWER
5  *
6  *  Authors: Christoph Raisch <raisch@de.ibm.com>
7  *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
8  *           Gerd Bayer <gerd.bayer@de.ibm.com>
9  *           Waleri Fomin <fomin@de.ibm.com>
10  *
11  *  Copyright (c) 2005 IBM Corporation
12  *
13  *  All rights reserved.
14  *
15  *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
16  *  BSD.
17  *
18  * OpenIB BSD License
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions are met:
22  *
23  * Redistributions of source code must retain the above copyright notice, this
24  * list of conditions and the following disclaimer.
25  *
26  * Redistributions in binary form must reproduce the above copyright notice,
27  * this list of conditions and the following disclaimer in the documentation
28  * and/or other materials
29  * provided with the distribution.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
32  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
35  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
38  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
39  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGE.
42  */
43
44 #include <asm/hvcall.h>
45 #include "ehca_tools.h"
46 #include "hcp_if.h"
47 #include "hcp_phyp.h"
48 #include "hipz_fns.h"
49 #include "ipz_pt_fn.h"
50
51 #define H_ALL_RES_QP_ENHANCED_OPS       EHCA_BMASK_IBM(9, 11)
52 #define H_ALL_RES_QP_PTE_PIN            EHCA_BMASK_IBM(12, 12)
53 #define H_ALL_RES_QP_SERVICE_TYPE       EHCA_BMASK_IBM(13, 15)
54 #define H_ALL_RES_QP_LL_RQ_CQE_POSTING  EHCA_BMASK_IBM(18, 18)
55 #define H_ALL_RES_QP_LL_SQ_CQE_POSTING  EHCA_BMASK_IBM(19, 21)
56 #define H_ALL_RES_QP_SIGNALING_TYPE     EHCA_BMASK_IBM(22, 23)
57 #define H_ALL_RES_QP_UD_AV_LKEY_CTRL    EHCA_BMASK_IBM(31, 31)
58 #define H_ALL_RES_QP_RESOURCE_TYPE      EHCA_BMASK_IBM(56, 63)
59
60 #define H_ALL_RES_QP_MAX_OUTST_SEND_WR  EHCA_BMASK_IBM(0, 15)
61 #define H_ALL_RES_QP_MAX_OUTST_RECV_WR  EHCA_BMASK_IBM(16, 31)
62 #define H_ALL_RES_QP_MAX_SEND_SGE       EHCA_BMASK_IBM(32, 39)
63 #define H_ALL_RES_QP_MAX_RECV_SGE       EHCA_BMASK_IBM(40, 47)
64
65 #define H_ALL_RES_QP_ACT_OUTST_SEND_WR  EHCA_BMASK_IBM(16, 31)
66 #define H_ALL_RES_QP_ACT_OUTST_RECV_WR  EHCA_BMASK_IBM(48, 63)
67 #define H_ALL_RES_QP_ACT_SEND_SGE       EHCA_BMASK_IBM(8, 15)
68 #define H_ALL_RES_QP_ACT_RECV_SGE       EHCA_BMASK_IBM(24, 31)
69
70 #define H_ALL_RES_QP_SQUEUE_SIZE_PAGES  EHCA_BMASK_IBM(0, 31)
71 #define H_ALL_RES_QP_RQUEUE_SIZE_PAGES  EHCA_BMASK_IBM(32, 63)
72
73 /* direct access qp controls */
74 #define DAQP_CTRL_ENABLE    0x01
75 #define DAQP_CTRL_SEND_COMP 0x20
76 #define DAQP_CTRL_RECV_COMP 0x40
77
78 static u32 get_longbusy_msecs(int longbusy_rc)
79 {
80         switch (longbusy_rc) {
81         case H_LONG_BUSY_ORDER_1_MSEC:
82                 return 1;
83         case H_LONG_BUSY_ORDER_10_MSEC:
84                 return 10;
85         case H_LONG_BUSY_ORDER_100_MSEC:
86                 return 100;
87         case H_LONG_BUSY_ORDER_1_SEC:
88                 return 1000;
89         case H_LONG_BUSY_ORDER_10_SEC:
90                 return 10000;
91         case H_LONG_BUSY_ORDER_100_SEC:
92                 return 100000;
93         default:
94                 return 1;
95         }
96 }
97
98 static long ehca_plpar_hcall_norets(unsigned long opcode,
99                                     unsigned long arg1,
100                                     unsigned long arg2,
101                                     unsigned long arg3,
102                                     unsigned long arg4,
103                                     unsigned long arg5,
104                                     unsigned long arg6,
105                                     unsigned long arg7)
106 {
107         long ret;
108         int i, sleep_msecs;
109
110         ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
111                      "arg5=%lx arg6=%lx arg7=%lx",
112                      opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
113
114         for (i = 0; i < 5; i++) {
115                 ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
116                                          arg5, arg6, arg7);
117
118                 if (H_IS_LONG_BUSY(ret)) {
119                         sleep_msecs = get_longbusy_msecs(ret);
120                         msleep_interruptible(sleep_msecs);
121                         continue;
122                 }
123
124                 if (ret < H_SUCCESS)
125                         ehca_gen_err("opcode=%lx ret=%lx"
126                                      " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
127                                      " arg5=%lx arg6=%lx arg7=%lx ",
128                                      opcode, ret,
129                                      arg1, arg2, arg3, arg4, arg5,
130                                      arg6, arg7);
131
132                 ehca_gen_dbg("opcode=%lx ret=%lx", opcode, ret);
133                 return ret;
134
135         }
136
137         return H_BUSY;
138 }
139
140 static long ehca_plpar_hcall9(unsigned long opcode,
141                               unsigned long *outs, /* array of 9 outputs */
142                               unsigned long arg1,
143                               unsigned long arg2,
144                               unsigned long arg3,
145                               unsigned long arg4,
146                               unsigned long arg5,
147                               unsigned long arg6,
148                               unsigned long arg7,
149                               unsigned long arg8,
150                               unsigned long arg9)
151 {
152         long ret;
153         int i, sleep_msecs;
154
155         ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
156                      "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
157                      opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
158                      arg8, arg9);
159
160         for (i = 0; i < 5; i++) {
161                 ret = plpar_hcall9(opcode, outs,
162                                    arg1, arg2, arg3, arg4, arg5,
163                                    arg6, arg7, arg8, arg9);
164
165                 if (H_IS_LONG_BUSY(ret)) {
166                         sleep_msecs = get_longbusy_msecs(ret);
167                         msleep_interruptible(sleep_msecs);
168                         continue;
169                 }
170
171                 if (ret < H_SUCCESS)
172                         ehca_gen_err("opcode=%lx ret=%lx"
173                                      " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
174                                      " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
175                                      " arg9=%lx"
176                                      " out1=%lx out2=%lx out3=%lx out4=%lx"
177                                      " out5=%lx out6=%lx out7=%lx out8=%lx"
178                                      " out9=%lx",
179                                      opcode, ret,
180                                      arg1, arg2, arg3, arg4, arg5,
181                                      arg6, arg7, arg8, arg9,
182                                      outs[0], outs[1], outs[2], outs[3],
183                                      outs[4], outs[5], outs[6], outs[7],
184                                      outs[8]);
185
186                 ehca_gen_dbg("opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx "
187                              "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx "
188                              "out9=%lx",
189                              opcode, ret, outs[0], outs[1], outs[2], outs[3],
190                              outs[4], outs[5], outs[6], outs[7], outs[8]);
191                 return ret;
192
193         }
194
195         return H_BUSY;
196 }
197 u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
198                              struct ehca_pfeq *pfeq,
199                              const u32 neq_control,
200                              const u32 number_of_entries,
201                              struct ipz_eq_handle *eq_handle,
202                              u32 *act_nr_of_entries,
203                              u32 *act_pages,
204                              u32 *eq_ist)
205 {
206         u64 ret;
207         u64 outs[PLPAR_HCALL9_BUFSIZE];
208         u64 allocate_controls;
209
210         /* resource type */
211         allocate_controls = 3ULL;
212
213         /* ISN is associated */
214         if (neq_control != 1)
215                 allocate_controls = (1ULL << (63 - 7)) | allocate_controls;
216         else /* notification event queue */
217                 allocate_controls = (1ULL << 63) | allocate_controls;
218
219         ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
220                                 adapter_handle.handle,  /* r4 */
221                                 allocate_controls,      /* r5 */
222                                 number_of_entries,      /* r6 */
223                                 0, 0, 0, 0, 0, 0);
224         eq_handle->handle = outs[0];
225         *act_nr_of_entries = (u32)outs[3];
226         *act_pages = (u32)outs[4];
227         *eq_ist = (u32)outs[5];
228
229         if (ret == H_NOT_ENOUGH_RESOURCES)
230                 ehca_gen_err("Not enough resource - ret=%lx ", ret);
231
232         return ret;
233 }
234
235 u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle,
236                        struct ipz_eq_handle eq_handle,
237                        const u64 event_mask)
238 {
239         return ehca_plpar_hcall_norets(H_RESET_EVENTS,
240                                        adapter_handle.handle, /* r4 */
241                                        eq_handle.handle,      /* r5 */
242                                        event_mask,            /* r6 */
243                                        0, 0, 0, 0);
244 }
245
246 u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
247                              struct ehca_cq *cq,
248                              struct ehca_alloc_cq_parms *param)
249 {
250         u64 ret;
251         u64 outs[PLPAR_HCALL9_BUFSIZE];
252
253         ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
254                                 adapter_handle.handle,   /* r4  */
255                                 2,                       /* r5  */
256                                 param->eq_handle.handle, /* r6  */
257                                 cq->token,               /* r7  */
258                                 param->nr_cqe,           /* r8  */
259                                 0, 0, 0, 0);
260         cq->ipz_cq_handle.handle = outs[0];
261         param->act_nr_of_entries = (u32)outs[3];
262         param->act_pages = (u32)outs[4];
263
264         if (ret == H_SUCCESS)
265                 hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]);
266
267         if (ret == H_NOT_ENOUGH_RESOURCES)
268                 ehca_gen_err("Not enough resources. ret=%lx", ret);
269
270         return ret;
271 }
272
273 u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
274                              struct ehca_qp *qp,
275                              struct ehca_alloc_qp_parms *parms)
276 {
277         u64 ret;
278         u64 allocate_controls;
279         u64 max_r10_reg;
280         u64 outs[PLPAR_HCALL9_BUFSIZE];
281         u16 max_nr_receive_wqes = qp->init_attr.cap.max_recv_wr + 1;
282         u16 max_nr_send_wqes = qp->init_attr.cap.max_send_wr + 1;
283         int daqp_ctrl = parms->daqp_ctrl;
284
285         allocate_controls =
286                 EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS,
287                                (daqp_ctrl & DAQP_CTRL_ENABLE) ? 1 : 0)
288                 | EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0)
289                 | EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype)
290                 | EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype)
291                 | EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING,
292                                  (daqp_ctrl & DAQP_CTRL_RECV_COMP) ? 1 : 0)
293                 | EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING,
294                                  (daqp_ctrl & DAQP_CTRL_SEND_COMP) ? 1 : 0)
295                 | EHCA_BMASK_SET(H_ALL_RES_QP_UD_AV_LKEY_CTRL,
296                                  parms->ud_av_l_key_ctl)
297                 | EHCA_BMASK_SET(H_ALL_RES_QP_RESOURCE_TYPE, 1);
298
299         max_r10_reg =
300                 EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR,
301                                max_nr_send_wqes)
302                 | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR,
303                                  max_nr_receive_wqes)
304                 | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE,
305                                  parms->max_send_sge)
306                 | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE,
307                                  parms->max_recv_sge);
308
309         ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
310                                 adapter_handle.handle,             /* r4  */
311                                 allocate_controls,                 /* r5  */
312                                 qp->send_cq->ipz_cq_handle.handle,
313                                 qp->recv_cq->ipz_cq_handle.handle,
314                                 parms->ipz_eq_handle.handle,
315                                 ((u64)qp->token << 32) | parms->pd.value,
316                                 max_r10_reg,                       /* r10 */
317                                 parms->ud_av_l_key_ctl,            /* r11 */
318                                 0);
319         qp->ipz_qp_handle.handle = outs[0];
320         qp->real_qp_num = (u32)outs[1];
321         parms->act_nr_send_sges =
322                 (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]);
323         parms->act_nr_recv_wqes =
324                 (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]);
325         parms->act_nr_send_sges =
326                 (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]);
327         parms->act_nr_recv_sges =
328                 (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]);
329         parms->nr_sq_pages =
330                 (u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]);
331         parms->nr_rq_pages =
332                 (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
333
334         if (ret == H_SUCCESS)
335                 hcp_galpas_ctor(&qp->galpas, outs[6], outs[6]);
336
337         if (ret == H_NOT_ENOUGH_RESOURCES)
338                 ehca_gen_err("Not enough resources. ret=%lx", ret);
339
340         return ret;
341 }
342
343 u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
344                       const u8 port_id,
345                       struct hipz_query_port *query_port_response_block)
346 {
347         u64 ret;
348         u64 r_cb = virt_to_abs(query_port_response_block);
349
350         if (r_cb & (EHCA_PAGESIZE-1)) {
351                 ehca_gen_err("response block not page aligned");
352                 return H_PARAMETER;
353         }
354
355         ret = ehca_plpar_hcall_norets(H_QUERY_PORT,
356                                       adapter_handle.handle, /* r4 */
357                                       port_id,               /* r5 */
358                                       r_cb,                  /* r6 */
359                                       0, 0, 0, 0);
360
361         if (ehca_debug_level)
362                 ehca_dmp(query_port_response_block, 64, "response_block");
363
364         return ret;
365 }
366
367 u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
368                      struct hipz_query_hca *query_hca_rblock)
369 {
370         u64 r_cb = virt_to_abs(query_hca_rblock);
371
372         if (r_cb & (EHCA_PAGESIZE-1)) {
373                 ehca_gen_err("response_block=%p not page aligned",
374                              query_hca_rblock);
375                 return H_PARAMETER;
376         }
377
378         return ehca_plpar_hcall_norets(H_QUERY_HCA,
379                                        adapter_handle.handle, /* r4 */
380                                        r_cb,                  /* r5 */
381                                        0, 0, 0, 0, 0);
382 }
383
384 u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
385                           const u8 pagesize,
386                           const u8 queue_type,
387                           const u64 resource_handle,
388                           const u64 logical_address_of_page,
389                           u64 count)
390 {
391         return ehca_plpar_hcall_norets(H_REGISTER_RPAGES,
392                                        adapter_handle.handle,      /* r4  */
393                                        queue_type | pagesize << 8, /* r5  */
394                                        resource_handle,            /* r6  */
395                                        logical_address_of_page,    /* r7  */
396                                        count,                      /* r8  */
397                                        0, 0);
398 }
399
400 u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
401                              const struct ipz_eq_handle eq_handle,
402                              struct ehca_pfeq *pfeq,
403                              const u8 pagesize,
404                              const u8 queue_type,
405                              const u64 logical_address_of_page,
406                              const u64 count)
407 {
408         if (count != 1) {
409                 ehca_gen_err("Ppage counter=%lx", count);
410                 return H_PARAMETER;
411         }
412         return hipz_h_register_rpage(adapter_handle,
413                                      pagesize,
414                                      queue_type,
415                                      eq_handle.handle,
416                                      logical_address_of_page, count);
417 }
418
419 u64 hipz_h_query_int_state(const struct ipz_adapter_handle adapter_handle,
420                            u32 ist)
421 {
422         u64 ret;
423         ret = ehca_plpar_hcall_norets(H_QUERY_INT_STATE,
424                                       adapter_handle.handle, /* r4 */
425                                       ist,                   /* r5 */
426                                       0, 0, 0, 0, 0);
427
428         if (ret != H_SUCCESS && ret != H_BUSY)
429                 ehca_gen_err("Could not query interrupt state.");
430
431         return ret;
432 }
433
434 u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
435                              const struct ipz_cq_handle cq_handle,
436                              struct ehca_pfcq *pfcq,
437                              const u8 pagesize,
438                              const u8 queue_type,
439                              const u64 logical_address_of_page,
440                              const u64 count,
441                              const struct h_galpa gal)
442 {
443         if (count != 1) {
444                 ehca_gen_err("Page counter=%lx", count);
445                 return H_PARAMETER;
446         }
447
448         return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
449                                      cq_handle.handle, logical_address_of_page,
450                                      count);
451 }
452
453 u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
454                              const struct ipz_qp_handle qp_handle,
455                              struct ehca_pfqp *pfqp,
456                              const u8 pagesize,
457                              const u8 queue_type,
458                              const u64 logical_address_of_page,
459                              const u64 count,
460                              const struct h_galpa galpa)
461 {
462         if (count != 1) {
463                 ehca_gen_err("Page counter=%lx", count);
464                 return H_PARAMETER;
465         }
466
467         return hipz_h_register_rpage(adapter_handle,pagesize,queue_type,
468                                      qp_handle.handle,logical_address_of_page,
469                                      count);
470 }
471
472 u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
473                                const struct ipz_qp_handle qp_handle,
474                                struct ehca_pfqp *pfqp,
475                                void **log_addr_next_sq_wqe2processed,
476                                void **log_addr_next_rq_wqe2processed,
477                                int dis_and_get_function_code)
478 {
479         u64 ret;
480         u64 outs[PLPAR_HCALL9_BUFSIZE];
481
482         ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs,
483                                 adapter_handle.handle,     /* r4 */
484                                 dis_and_get_function_code, /* r5 */
485                                 qp_handle.handle,          /* r6 */
486                                 0, 0, 0, 0, 0, 0);
487         if (log_addr_next_sq_wqe2processed)
488                 *log_addr_next_sq_wqe2processed = (void*)outs[0];
489         if (log_addr_next_rq_wqe2processed)
490                 *log_addr_next_rq_wqe2processed = (void*)outs[1];
491
492         return ret;
493 }
494
495 u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
496                      const struct ipz_qp_handle qp_handle,
497                      struct ehca_pfqp *pfqp,
498                      const u64 update_mask,
499                      struct hcp_modify_qp_control_block *mqpcb,
500                      struct h_galpa gal)
501 {
502         u64 ret;
503         u64 outs[PLPAR_HCALL9_BUFSIZE];
504         ret = ehca_plpar_hcall9(H_MODIFY_QP, outs,
505                                 adapter_handle.handle, /* r4 */
506                                 qp_handle.handle,      /* r5 */
507                                 update_mask,           /* r6 */
508                                 virt_to_abs(mqpcb),    /* r7 */
509                                 0, 0, 0, 0, 0);
510
511         if (ret == H_NOT_ENOUGH_RESOURCES)
512                 ehca_gen_err("Insufficient resources ret=%lx", ret);
513
514         return ret;
515 }
516
517 u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle,
518                     const struct ipz_qp_handle qp_handle,
519                     struct ehca_pfqp *pfqp,
520                     struct hcp_modify_qp_control_block *qqpcb,
521                     struct h_galpa gal)
522 {
523         return ehca_plpar_hcall_norets(H_QUERY_QP,
524                                        adapter_handle.handle, /* r4 */
525                                        qp_handle.handle,      /* r5 */
526                                        virt_to_abs(qqpcb),    /* r6 */
527                                        0, 0, 0, 0);
528 }
529
530 u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
531                       struct ehca_qp *qp)
532 {
533         u64 ret;
534         u64 outs[PLPAR_HCALL9_BUFSIZE];
535
536         ret = hcp_galpas_dtor(&qp->galpas);
537         if (ret) {
538                 ehca_gen_err("Could not destruct qp->galpas");
539                 return H_RESOURCE;
540         }
541         ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs,
542                                 adapter_handle.handle,     /* r4 */
543                                 /* function code */
544                                 1,                         /* r5 */
545                                 qp->ipz_qp_handle.handle,  /* r6 */
546                                 0, 0, 0, 0, 0, 0);
547         if (ret == H_HARDWARE)
548                 ehca_gen_err("HCA not operational. ret=%lx", ret);
549
550         ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
551                                       adapter_handle.handle,     /* r4 */
552                                       qp->ipz_qp_handle.handle,  /* r5 */
553                                       0, 0, 0, 0, 0);
554
555         if (ret == H_RESOURCE)
556                 ehca_gen_err("Resource still in use. ret=%lx", ret);
557
558         return ret;
559 }
560
561 u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle,
562                        const struct ipz_qp_handle qp_handle,
563                        struct h_galpa gal,
564                        u32 port)
565 {
566         return ehca_plpar_hcall_norets(H_DEFINE_AQP0,
567                                        adapter_handle.handle, /* r4 */
568                                        qp_handle.handle,      /* r5 */
569                                        port,                  /* r6 */
570                                        0, 0, 0, 0);
571 }
572
573 u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
574                        const struct ipz_qp_handle qp_handle,
575                        struct h_galpa gal,
576                        u32 port, u32 * pma_qp_nr,
577                        u32 * bma_qp_nr)
578 {
579         u64 ret;
580         u64 outs[PLPAR_HCALL9_BUFSIZE];
581
582         ret = ehca_plpar_hcall9(H_DEFINE_AQP1, outs,
583                                 adapter_handle.handle, /* r4 */
584                                 qp_handle.handle,      /* r5 */
585                                 port,                  /* r6 */
586                                 0, 0, 0, 0, 0, 0);
587         *pma_qp_nr = (u32)outs[0];
588         *bma_qp_nr = (u32)outs[1];
589
590         if (ret == H_ALIAS_EXIST)
591                 ehca_gen_err("AQP1 already exists. ret=%lx", ret);
592
593         return ret;
594 }
595
596 u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
597                        const struct ipz_qp_handle qp_handle,
598                        struct h_galpa gal,
599                        u16 mcg_dlid,
600                        u64 subnet_prefix, u64 interface_id)
601 {
602         u64 ret;
603
604         ret = ehca_plpar_hcall_norets(H_ATTACH_MCQP,
605                                       adapter_handle.handle,  /* r4 */
606                                       qp_handle.handle,       /* r5 */
607                                       mcg_dlid,               /* r6 */
608                                       interface_id,           /* r7 */
609                                       subnet_prefix,          /* r8 */
610                                       0, 0);
611
612         if (ret == H_NOT_ENOUGH_RESOURCES)
613                 ehca_gen_err("Not enough resources. ret=%lx", ret);
614
615         return ret;
616 }
617
618 u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle,
619                        const struct ipz_qp_handle qp_handle,
620                        struct h_galpa gal,
621                        u16 mcg_dlid,
622                        u64 subnet_prefix, u64 interface_id)
623 {
624         return ehca_plpar_hcall_norets(H_DETACH_MCQP,
625                                        adapter_handle.handle, /* r4 */
626                                        qp_handle.handle,      /* r5 */
627                                        mcg_dlid,              /* r6 */
628                                        interface_id,          /* r7 */
629                                        subnet_prefix,         /* r8 */
630                                        0, 0);
631 }
632
633 u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
634                       struct ehca_cq *cq,
635                       u8 force_flag)
636 {
637         u64 ret;
638
639         ret = hcp_galpas_dtor(&cq->galpas);
640         if (ret) {
641                 ehca_gen_err("Could not destruct cp->galpas");
642                 return H_RESOURCE;
643         }
644
645         ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
646                                       adapter_handle.handle,     /* r4 */
647                                       cq->ipz_cq_handle.handle,  /* r5 */
648                                       force_flag != 0 ? 1L : 0L, /* r6 */
649                                       0, 0, 0, 0);
650
651         if (ret == H_RESOURCE)
652                 ehca_gen_err("H_FREE_RESOURCE failed ret=%lx ", ret);
653
654         return ret;
655 }
656
657 u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
658                       struct ehca_eq *eq)
659 {
660         u64 ret;
661
662         ret = hcp_galpas_dtor(&eq->galpas);
663         if (ret) {
664                 ehca_gen_err("Could not destruct eq->galpas");
665                 return H_RESOURCE;
666         }
667
668         ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
669                                       adapter_handle.handle,     /* r4 */
670                                       eq->ipz_eq_handle.handle,  /* r5 */
671                                       0, 0, 0, 0, 0);
672
673         if (ret == H_RESOURCE)
674                 ehca_gen_err("Resource in use. ret=%lx ", ret);
675
676         return ret;
677 }
678
679 u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
680                              const struct ehca_mr *mr,
681                              const u64 vaddr,
682                              const u64 length,
683                              const u32 access_ctrl,
684                              const struct ipz_pd pd,
685                              struct ehca_mr_hipzout_parms *outparms)
686 {
687         u64 ret;
688         u64 outs[PLPAR_HCALL9_BUFSIZE];
689
690         ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
691                                 adapter_handle.handle,            /* r4 */
692                                 5,                                /* r5 */
693                                 vaddr,                            /* r6 */
694                                 length,                           /* r7 */
695                                 (((u64)access_ctrl) << 32ULL),    /* r8 */
696                                 pd.value,                         /* r9 */
697                                 0, 0, 0);
698         outparms->handle.handle = outs[0];
699         outparms->lkey = (u32)outs[2];
700         outparms->rkey = (u32)outs[3];
701
702         return ret;
703 }
704
705 u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
706                              const struct ehca_mr *mr,
707                              const u8 pagesize,
708                              const u8 queue_type,
709                              const u64 logical_address_of_page,
710                              const u64 count)
711 {
712         u64 ret;
713
714         if ((count > 1) && (logical_address_of_page & (EHCA_PAGESIZE-1))) {
715                 ehca_gen_err("logical_address_of_page not on a 4k boundary "
716                              "adapter_handle=%lx mr=%p mr_handle=%lx "
717                              "pagesize=%x queue_type=%x "
718                              "logical_address_of_page=%lx count=%lx",
719                              adapter_handle.handle, mr,
720                              mr->ipz_mr_handle.handle, pagesize, queue_type,
721                              logical_address_of_page, count);
722                 ret = H_PARAMETER;
723         } else
724                 ret = hipz_h_register_rpage(adapter_handle, pagesize,
725                                             queue_type,
726                                             mr->ipz_mr_handle.handle,
727                                             logical_address_of_page, count);
728         return ret;
729 }
730
731 u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
732                     const struct ehca_mr *mr,
733                     struct ehca_mr_hipzout_parms *outparms)
734 {
735         u64 ret;
736         u64 outs[PLPAR_HCALL9_BUFSIZE];
737
738         ret = ehca_plpar_hcall9(H_QUERY_MR, outs,
739                                 adapter_handle.handle,     /* r4 */
740                                 mr->ipz_mr_handle.handle,  /* r5 */
741                                 0, 0, 0, 0, 0, 0, 0);
742         outparms->len = outs[0];
743         outparms->vaddr = outs[1];
744         outparms->acl  = outs[4] >> 32;
745         outparms->lkey = (u32)(outs[5] >> 32);
746         outparms->rkey = (u32)(outs[5] & (0xffffffff));
747
748         return ret;
749 }
750
751 u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
752                             const struct ehca_mr *mr)
753 {
754         return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
755                                        adapter_handle.handle,    /* r4 */
756                                        mr->ipz_mr_handle.handle, /* r5 */
757                                        0, 0, 0, 0, 0);
758 }
759
760 u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
761                           const struct ehca_mr *mr,
762                           const u64 vaddr_in,
763                           const u64 length,
764                           const u32 access_ctrl,
765                           const struct ipz_pd pd,
766                           const u64 mr_addr_cb,
767                           struct ehca_mr_hipzout_parms *outparms)
768 {
769         u64 ret;
770         u64 outs[PLPAR_HCALL9_BUFSIZE];
771
772         ret = ehca_plpar_hcall9(H_REREGISTER_PMR, outs,
773                                 adapter_handle.handle,    /* r4 */
774                                 mr->ipz_mr_handle.handle, /* r5 */
775                                 vaddr_in,                 /* r6 */
776                                 length,                   /* r7 */
777                                 /* r8 */
778                                 ((((u64)access_ctrl) << 32ULL) | pd.value),
779                                 mr_addr_cb,               /* r9 */
780                                 0, 0, 0);
781         outparms->vaddr = outs[1];
782         outparms->lkey = (u32)outs[2];
783         outparms->rkey = (u32)outs[3];
784
785         return ret;
786 }
787
788 u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
789                         const struct ehca_mr *mr,
790                         const struct ehca_mr *orig_mr,
791                         const u64 vaddr_in,
792                         const u32 access_ctrl,
793                         const struct ipz_pd pd,
794                         struct ehca_mr_hipzout_parms *outparms)
795 {
796         u64 ret;
797         u64 outs[PLPAR_HCALL9_BUFSIZE];
798
799         ret = ehca_plpar_hcall9(H_REGISTER_SMR, outs,
800                                 adapter_handle.handle,            /* r4 */
801                                 orig_mr->ipz_mr_handle.handle,    /* r5 */
802                                 vaddr_in,                         /* r6 */
803                                 (((u64)access_ctrl) << 32ULL),    /* r7 */
804                                 pd.value,                         /* r8 */
805                                 0, 0, 0, 0);
806         outparms->handle.handle = outs[0];
807         outparms->lkey = (u32)outs[2];
808         outparms->rkey = (u32)outs[3];
809
810         return ret;
811 }
812
813 u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
814                              const struct ehca_mw *mw,
815                              const struct ipz_pd pd,
816                              struct ehca_mw_hipzout_parms *outparms)
817 {
818         u64 ret;
819         u64 outs[PLPAR_HCALL9_BUFSIZE];
820
821         ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
822                                 adapter_handle.handle,      /* r4 */
823                                 6,                          /* r5 */
824                                 pd.value,                   /* r6 */
825                                 0, 0, 0, 0, 0, 0);
826         outparms->handle.handle = outs[0];
827         outparms->rkey = (u32)outs[3];
828
829         return ret;
830 }
831
832 u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
833                     const struct ehca_mw *mw,
834                     struct ehca_mw_hipzout_parms *outparms)
835 {
836         u64 ret;
837         u64 outs[PLPAR_HCALL9_BUFSIZE];
838
839         ret = ehca_plpar_hcall9(H_QUERY_MW, outs,
840                                 adapter_handle.handle,    /* r4 */
841                                 mw->ipz_mw_handle.handle, /* r5 */
842                                 0, 0, 0, 0, 0, 0, 0);
843         outparms->rkey = (u32)outs[3];
844
845         return ret;
846 }
847
848 u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle,
849                             const struct ehca_mw *mw)
850 {
851         return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
852                                        adapter_handle.handle,    /* r4 */
853                                        mw->ipz_mw_handle.handle, /* r5 */
854                                        0, 0, 0, 0, 0);
855 }
856
857 u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle,
858                       const u64 ressource_handle,
859                       void *rblock,
860                       unsigned long *byte_count)
861 {
862         u64 r_cb = virt_to_abs(rblock);
863
864         if (r_cb & (EHCA_PAGESIZE-1)) {
865                 ehca_gen_err("rblock not page aligned.");
866                 return H_PARAMETER;
867         }
868
869         return ehca_plpar_hcall_norets(H_ERROR_DATA,
870                                        adapter_handle.handle,
871                                        ressource_handle,
872                                        r_cb,
873                                        0, 0, 0, 0);
874 }