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