xref: /freebsd/contrib/ofed/opensm/opensm/osm_qos.c (revision 0957b409)
1 /*
2  * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2010-2015 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 2009 HNR Consulting. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35 
36 /*
37  * Abstract:
38  *    Implementation of OpenSM QoS infrastructure primitives
39  */
40 
41 #if HAVE_CONFIG_H
42 #  include <config.h>
43 #endif				/* HAVE_CONFIG_H */
44 
45 #include <stdlib.h>
46 #include <string.h>
47 
48 #include <iba/ib_types.h>
49 #include <complib/cl_qmap.h>
50 #include <complib/cl_debug.h>
51 #include <opensm/osm_file_ids.h>
52 #define FILE_ID OSM_FILE_QOS_C
53 #include <opensm/osm_opensm.h>
54 #include <opensm/osm_subnet.h>
55 #include <opensm/osm_qos_policy.h>
56 
57 struct qos_config {
58 	uint8_t max_vls;
59 	uint8_t vl_high_limit;
60 	ib_vl_arb_table_t vlarb_high[2];
61 	ib_vl_arb_table_t vlarb_low[2];
62 	ib_slvl_table_t sl2vl;
63 };
64 
65 typedef struct qos_mad_item {
66 	cl_list_item_t list_item;
67 	osm_madw_t *p_madw;
68 } qos_mad_item_t;
69 
70 typedef struct qos_mad_list {
71 	cl_list_item_t list_item;
72 	cl_qlist_t port_mad_list;
73 } qos_mad_list_t;
74 
75 static void qos_build_config(struct qos_config *cfg,
76 			     osm_qos_options_t * opt,
77 			     osm_qos_options_t * dflt);
78 
79 /*
80  * QoS primitives
81  */
82 
83 static qos_mad_item_t *osm_qos_mad_create(IN osm_sm_t * sm,
84 					  IN osm_physp_t * p,
85 					  IN uint32_t data_size,
86 					  IN uint8_t * p_data,
87 					  IN ib_net16_t attr_id,
88 					  IN uint32_t attr_mod)
89 
90 {
91 	qos_mad_item_t *p_mad;
92 	osm_madw_context_t context;
93 	osm_madw_t *p_madw;
94 	osm_node_t *p_node;
95 	osm_physp_t *physp0;
96 	ib_net64_t m_key;
97 
98 	p_node = osm_physp_get_node_ptr(p);
99 	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH &&
100 	    osm_physp_get_port_num(p) != 0) {
101 		physp0 = osm_node_get_physp_ptr(p_node, 0);
102 		m_key = ib_port_info_get_m_key(&physp0->port_info);
103 	} else
104 		m_key = ib_port_info_get_m_key(&p->port_info);
105 
106 	switch (attr_id){
107 	case IB_MAD_ATTR_SLVL_TABLE:
108 		context.slvl_context.node_guid = osm_node_get_node_guid(p_node);
109 		context.slvl_context.port_guid = osm_physp_get_port_guid(p);
110 		context.slvl_context.set_method = TRUE;
111 		break;
112 	case IB_MAD_ATTR_VL_ARBITRATION:
113 		context.vla_context.node_guid = osm_node_get_node_guid(p_node);
114 		context.vla_context.port_guid = osm_physp_get_port_guid(p);
115 		context.vla_context.set_method = TRUE;
116 		break;
117 	default:
118 		return NULL;
119 	}
120 
121 	p_mad = (qos_mad_item_t *) malloc(sizeof(*p_mad));
122 	if (!p_mad)
123 		return NULL;
124 
125 	memset(p_mad, 0, sizeof(*p_mad));
126 
127 	p_madw = osm_prepare_req_set(sm, osm_physp_get_dr_path_ptr(p),
128 				     p_data, data_size,
129 				     attr_id, cl_hton32(attr_mod),
130 				     FALSE, m_key,
131 				     CL_DISP_MSGID_NONE, &context);
132 
133 	if (p_madw == NULL) {
134 		free(p_mad);
135 		return NULL;
136 	}
137 	p_mad->p_madw = p_madw;
138 	return p_mad;
139 }
140 
141 static void osm_qos_mad_delete(qos_mad_item_t ** p_item)
142 {
143 	free(*p_item);
144 	*p_item = NULL;
145 }
146 
147 static ib_api_status_t vlarb_update_table_block(osm_sm_t * sm,
148 						osm_physp_t * p,
149 						uint8_t port_num,
150 						unsigned force_update,
151 						const ib_vl_arb_table_t *
152 						table_block,
153 						unsigned block_length,
154 						unsigned block_num,
155 						cl_qlist_t *mad_list)
156 {
157 	struct osm_routing_engine *re = sm->p_subn->p_osm->routing_engine_used;
158 	ib_vl_arb_table_t block;
159 	uint32_t attr_mod;
160 	unsigned vl_mask, i;
161 	qos_mad_item_t *p_mad;
162 	vl_mask = (1 << (ib_port_info_get_op_vls(&p->port_info) - 1)) - 1;
163 
164 	memset(&block, 0, sizeof(block));
165 	memcpy(&block, table_block, block_length * sizeof(block.vl_entry[0]));
166 
167 	if (re && re->update_vlarb)
168 		re->update_vlarb(re->context, p, port_num, &block,
169 				 block_length, block_num);
170 
171 	for (i = 0; i < block_length; i++)
172 		block.vl_entry[i].vl &= vl_mask;
173 
174 	if (!force_update &&
175 	    !memcmp(&p->vl_arb[block_num], &block,
176 		    block_length * sizeof(block.vl_entry[0])))
177 		return IB_SUCCESS;
178 
179 	attr_mod = ((block_num + 1) << 16) | port_num;
180 
181 	p_mad = osm_qos_mad_create(sm,p,sizeof(block),(uint8_t *) & block,
182 				   IB_MAD_ATTR_VL_ARBITRATION, attr_mod);
183 
184 	if (!p_mad)
185 		return IB_INSUFFICIENT_MEMORY;
186 
187 	/*
188 	 * Zero the stored VL Arbitration block, so in case the MAD will
189 	 * end up with error, we will resend it in the next sweep.
190 	 */
191 	memset(&p->vl_arb[block_num], 0,
192 	       block_length * sizeof(block.vl_entry[0]));
193 
194 	cl_qlist_insert_tail(mad_list, &p_mad->list_item);
195 
196 	return IB_SUCCESS;
197 }
198 
199 static ib_api_status_t vlarb_update(osm_sm_t * sm, osm_physp_t * p,
200 				    uint8_t port_num, unsigned force_update,
201 				    const struct qos_config *qcfg,
202 				    cl_qlist_t *mad_list)
203 {
204 	ib_api_status_t status = IB_SUCCESS;
205 	ib_port_info_t *p_pi = &p->port_info;
206 	unsigned len;
207 
208 	if (p_pi->vl_arb_low_cap > 0) {
209 		len = p_pi->vl_arb_low_cap < IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK ?
210 		    p_pi->vl_arb_low_cap : IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
211 		if ((status = vlarb_update_table_block(sm, p, port_num,
212 						       force_update,
213 						       &qcfg->vlarb_low[0],
214 						       len, 0,
215 						       mad_list)) != IB_SUCCESS)
216 			return status;
217 	}
218 	if (p_pi->vl_arb_low_cap > IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) {
219 		len = p_pi->vl_arb_low_cap % IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
220 		if ((status = vlarb_update_table_block(sm, p, port_num,
221 						       force_update,
222 						       &qcfg->vlarb_low[1],
223 						       len, 1,
224 						       mad_list)) != IB_SUCCESS)
225 			return status;
226 	}
227 	if (p_pi->vl_arb_high_cap > 0) {
228 		len = p_pi->vl_arb_high_cap < IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK ?
229 		    p_pi->vl_arb_high_cap : IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
230 		if ((status = vlarb_update_table_block(sm, p, port_num,
231 						       force_update,
232 						       &qcfg->vlarb_high[0],
233 						       len, 2,
234 						       mad_list)) != IB_SUCCESS)
235 			return status;
236 	}
237 	if (p_pi->vl_arb_high_cap > IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) {
238 		len = p_pi->vl_arb_high_cap % IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
239 		if ((status = vlarb_update_table_block(sm, p, port_num,
240 						       force_update,
241 						       &qcfg->vlarb_high[1],
242 						       len, 3,
243 						       mad_list)) != IB_SUCCESS)
244 			return status;
245 	}
246 
247 	return status;
248 }
249 
250 static ib_api_status_t sl2vl_update_table(osm_sm_t * sm, osm_physp_t * p,
251 					  uint8_t in_port, uint32_t attr_mod,
252 					  unsigned force_update,
253 					  const ib_slvl_table_t * sl2vl_table,
254 					  cl_qlist_t *mad_list)
255 {
256 	ib_slvl_table_t tbl, *p_tbl;
257 	unsigned vl_mask;
258 	uint8_t vl1, vl2;
259 	int i;
260 	qos_mad_item_t *p_mad;
261 
262 	vl_mask = (1 << (ib_port_info_get_op_vls(&p->port_info) - 1)) - 1;
263 
264 	for (i = 0; i < IB_MAX_NUM_VLS / 2; i++) {
265 		vl1 = sl2vl_table->raw_vl_by_sl[i] >> 4;
266 		vl2 = sl2vl_table->raw_vl_by_sl[i] & 0xf;
267 		if (vl1 != 15)
268 			vl1 &= vl_mask;
269 		if (vl2 != 15)
270 			vl2 &= vl_mask;
271 		tbl.raw_vl_by_sl[i] = (vl1 << 4) | vl2;
272 	}
273 
274 	p_tbl = osm_physp_get_slvl_tbl(p, in_port);
275 
276 	if (!force_update && !memcmp(p_tbl, &tbl, sizeof(tbl)))
277 		return IB_SUCCESS;
278 
279 	p_mad = osm_qos_mad_create(sm, p, sizeof(tbl), (uint8_t *) & tbl,
280 				   IB_MAD_ATTR_SLVL_TABLE, attr_mod);
281 	if (!p_mad)
282 		return IB_INSUFFICIENT_MEMORY;
283 
284 	/*
285 	 * Zero the stored SL2VL block, so in case the MAD will
286 	 * end up with error, we will resend it in the next sweep.
287 	 */
288 	memset(p_tbl, 0, sizeof(tbl));
289 
290 	cl_qlist_insert_tail(mad_list, &p_mad->list_item);
291 	return IB_SUCCESS;
292 }
293 
294 static int qos_extports_setup(osm_sm_t * sm, osm_node_t *node,
295 			      const struct qos_config *qcfg,
296 			      cl_qlist_t *port_mad_list)
297 
298 {
299 	osm_physp_t *p0, *p;
300 	unsigned force_update;
301 	unsigned num_ports = osm_node_get_num_physp(node);
302 	struct osm_routing_engine *re = sm->p_subn->p_osm->routing_engine_used;
303 	int ret = 0;
304 	unsigned in, out;
305 	uint8_t op_vl, common_op_vl = 0, max_num = 0;
306 	uint8_t op_vl_arr[15];
307 
308 	/*
309 	 * Do nothing unless the most recent routing attempt was successful.
310 	 */
311 	if (!re)
312 		return ret;
313 
314 	for (out = 1; out < num_ports; out++) {
315 		p = osm_node_get_physp_ptr(node, out);
316 		if (!p)
317 			continue;
318 		if (ib_port_info_get_port_state(&p->port_info) == IB_LINK_DOWN)
319 			continue;
320 		force_update = p->need_update || sm->p_subn->need_update;
321 		p->vl_high_limit = qcfg->vl_high_limit;
322 		if (vlarb_update(sm, p, p->port_num, force_update, qcfg,
323 				 port_mad_list))
324 			ret = -1;
325 	}
326 
327 	p0 = osm_node_get_physp_ptr(node, 0);
328 	if (!(p0->port_info.capability_mask & IB_PORT_CAP_HAS_SL_MAP))
329 		return ret;
330 
331 	if (ib_switch_info_get_opt_sl2vlmapping(&node->sw->switch_info) &&
332 	    sm->p_subn->opt.use_optimized_slvl && !re->update_sl2vl) {
333 
334 		/* we should find the op_vl that is used by majority of ports */
335 		memset(&op_vl_arr[0], 0, sizeof(op_vl_arr));
336 		p0 = osm_node_get_physp_ptr(node, 1);
337 
338 		for (out = 1; out < num_ports; out++) {
339 			p = osm_node_get_physp_ptr(node, out);
340 			if (!p)
341 				continue;
342 			if (ib_port_info_get_port_state(&p->port_info) ==
343 			    IB_LINK_DOWN)
344 				continue;
345 			op_vl = ib_port_info_get_op_vls(&p->port_info);
346 			op_vl_arr[op_vl]++;
347 			if (op_vl_arr[op_vl] > max_num){
348 				max_num = op_vl_arr[op_vl];
349 				common_op_vl = op_vl;
350 				/* remember the port with most common op_vl */
351 				p0 = p;
352 			}
353 
354 		}
355 		if (!p0)
356 			return -1;
357 		force_update = node->sw->need_update || sm->p_subn->need_update;
358 		if (sl2vl_update_table(sm, p0, p0->port_num, 0x30000, force_update,
359 					&qcfg->sl2vl, port_mad_list))
360 			ret = -1;
361 		/*
362 		 * Overwrite default ALL configuration if port's
363 		 * op_vl is different.
364 		 */
365 		for (out = 1; out < num_ports; out++) {
366 			p = osm_node_get_physp_ptr(node, out);
367 			if (!p)
368 				continue;
369 			if (ib_port_info_get_port_state(&p->port_info) ==
370 			    IB_LINK_DOWN)
371 				continue;
372 
373 			force_update = p->need_update || force_update;
374 			if (ib_port_info_get_op_vls(&p->port_info) !=
375 			    common_op_vl &&
376 			    sl2vl_update_table(sm, p, p->port_num, 0x20000 | out,
377 					       force_update, &qcfg->sl2vl,
378 					       port_mad_list))
379 				ret = -1;
380 		}
381 		return ret;
382 	}
383 
384 	/* non optimized sl2vl configuration */
385 	out = ib_switch_info_is_enhanced_port0(&node->sw->switch_info) ? 0 : 1;
386 	for (; out < num_ports; out++) {
387 		p = osm_node_get_physp_ptr(node, out);
388 		if (!p)
389 			continue;
390 		if (ib_port_info_get_port_state(&p->port_info) == IB_LINK_DOWN)
391 			continue;
392 		force_update = p->need_update || sm->p_subn->need_update;
393 		/* go over all in ports */
394 		for (in = 0; in < num_ports; in++) {
395 			const ib_slvl_table_t *port_sl2vl = &qcfg->sl2vl;
396 			ib_slvl_table_t routing_sl2vl;
397 
398 			if (re->update_sl2vl) {
399 				routing_sl2vl = *port_sl2vl;
400 				re->update_sl2vl(re->context,
401 						 p, in, out, &routing_sl2vl);
402 				port_sl2vl = &routing_sl2vl;
403 			}
404 			if (sl2vl_update_table(sm, p, in, in << 8 | out,
405 					       force_update, port_sl2vl,
406 					       port_mad_list))
407 				ret = -1;
408 		}
409 	}
410 
411 	return ret;
412 }
413 
414 static int qos_endport_setup(osm_sm_t * sm, osm_physp_t * p,
415 			     const struct qos_config *qcfg, int vlarb_only,
416 			     cl_qlist_t *port_mad_list)
417 {
418 	unsigned force_update = p->need_update || sm->p_subn->need_update;
419 	struct osm_routing_engine *re = sm->p_subn->p_osm->routing_engine_used;
420 	const ib_slvl_table_t *port_sl2vl = &qcfg->sl2vl;
421 	ib_slvl_table_t routing_sl2vl;
422 
423 	p->vl_high_limit = qcfg->vl_high_limit;
424 	if (vlarb_update(sm, p, 0, force_update, qcfg, port_mad_list))
425 		return -1;
426 	if (vlarb_only)
427 		return 0;
428 
429 	if (!(p->port_info.capability_mask & IB_PORT_CAP_HAS_SL_MAP))
430 		return 0;
431 
432 	if (re && re->update_sl2vl) {
433 		routing_sl2vl = *port_sl2vl;
434 		re->update_sl2vl(re->context, p, 0, 0, &routing_sl2vl);
435 		port_sl2vl = &routing_sl2vl;
436 	}
437 	if (sl2vl_update_table(sm, p, 0, 0, force_update, port_sl2vl,
438 			       port_mad_list))
439 		return -1;
440 
441 	return 0;
442 }
443 
444 int osm_qos_setup(osm_opensm_t * p_osm)
445 {
446 	struct qos_config ca_config, sw0_config, swe_config, rtr_config;
447 	struct qos_config *cfg;
448 	cl_qmap_t *p_tbl;
449 	cl_map_item_t *p_next;
450 	osm_port_t *p_port;
451 	osm_node_t *p_node;
452 	int ret = 0;
453 	int vlarb_only;
454 	qos_mad_list_t *p_list, *p_list_next;
455 	qos_mad_item_t *p_port_mad;
456 	cl_qlist_t qos_mad_list;
457 
458 	if (!p_osm->subn.opt.qos)
459 		return 0;
460 
461 	OSM_LOG_ENTER(&p_osm->log);
462 
463 	qos_build_config(&ca_config, &p_osm->subn.opt.qos_ca_options,
464 			 &p_osm->subn.opt.qos_options);
465 	qos_build_config(&sw0_config, &p_osm->subn.opt.qos_sw0_options,
466 			 &p_osm->subn.opt.qos_options);
467 	qos_build_config(&swe_config, &p_osm->subn.opt.qos_swe_options,
468 			 &p_osm->subn.opt.qos_options);
469 	qos_build_config(&rtr_config, &p_osm->subn.opt.qos_rtr_options,
470 			 &p_osm->subn.opt.qos_options);
471 
472 	cl_qlist_init(&qos_mad_list);
473 
474 	cl_plock_excl_acquire(&p_osm->lock);
475 
476 	/* read QoS policy config file */
477 	osm_qos_parse_policy_file(&p_osm->subn);
478 	p_tbl = &p_osm->subn.port_guid_tbl;
479 	p_next = cl_qmap_head(p_tbl);
480 	while (p_next != cl_qmap_end(p_tbl)) {
481 		vlarb_only = 0;
482 		p_port = (osm_port_t *) p_next;
483 		p_next = cl_qmap_next(p_next);
484 
485 		p_list = (qos_mad_list_t *) malloc(sizeof(*p_list));
486 		if (!p_list) {
487 			cl_plock_release(&p_osm->lock);
488 			return -1;
489 		}
490 
491 		memset(p_list, 0, sizeof(*p_list));
492 
493 		cl_qlist_init(&p_list->port_mad_list);
494 
495 		p_node = p_port->p_node;
496 		if (p_node->sw) {
497 			if (qos_extports_setup(&p_osm->sm, p_node, &swe_config,
498 					       &p_list->port_mad_list)) {
499 				cl_plock_release(&p_osm->lock);
500 				ret = -1;
501 			}
502 
503 			/* skip base port 0 */
504 			if (!ib_switch_info_is_enhanced_port0
505 			    (&p_node->sw->switch_info))
506 				goto Continue;
507 
508 			if (ib_switch_info_get_opt_sl2vlmapping(&p_node->sw->switch_info) &&
509 			    p_osm->sm.p_subn->opt.use_optimized_slvl &&
510 			    !memcmp(&swe_config.sl2vl, &sw0_config.sl2vl,
511 				    sizeof(swe_config.sl2vl)))
512 				vlarb_only = 1;
513 
514 			cfg = &sw0_config;
515 		} else if (osm_node_get_type(p_node) == IB_NODE_TYPE_ROUTER)
516 			cfg = &rtr_config;
517 		else
518 			cfg = &ca_config;
519 
520 		if (qos_endport_setup(&p_osm->sm, p_port->p_physp, cfg,
521 				      vlarb_only, &p_list->port_mad_list)) {
522 			cl_plock_release(&p_osm->lock);
523 			ret = -1;
524 		}
525 Continue:
526 		/* if MAD list is not empty, add it to the global MAD list */
527 		if (cl_qlist_count(&p_list->port_mad_list)) {
528 			cl_qlist_insert_tail(&qos_mad_list, &p_list->list_item);
529 		} else {
530 			free(p_list);
531 		}
532 	}
533 	while (cl_qlist_count(&qos_mad_list)) {
534 		p_list_next = (qos_mad_list_t *) cl_qlist_head(&qos_mad_list);
535 		while (p_list_next !=
536 			(qos_mad_list_t *) cl_qlist_end(&qos_mad_list)) {
537 			p_list = p_list_next;
538 			p_list_next = (qos_mad_list_t *)
539 				      cl_qlist_next(&p_list->list_item);
540 			/* next MAD to send*/
541 			p_port_mad = (qos_mad_item_t *)
542 				     cl_qlist_remove_head(&p_list->port_mad_list);
543 			osm_send_req_mad(&p_osm->sm, p_port_mad->p_madw);
544 			osm_qos_mad_delete(&p_port_mad);
545 			/* remove the QoS MAD from global MAD list */
546 			if (cl_qlist_count(&p_list->port_mad_list) == 0) {
547 				cl_qlist_remove_item(&qos_mad_list, &p_list->list_item);
548 				free(p_list);
549 			}
550 		}
551 	}
552 
553 	cl_plock_release(&p_osm->lock);
554 	OSM_LOG_EXIT(&p_osm->log);
555 
556 	return ret;
557 }
558 
559 /*
560  *  QoS config stuff
561  */
562 static int parse_one_unsigned(const char *str, char delim, unsigned *val)
563 {
564 	char *end;
565 	*val = strtoul(str, &end, 0);
566 	if (*end)
567 		end++;
568 	return (int)(end - str);
569 }
570 
571 static int parse_vlarb_entry(const char *str, ib_vl_arb_element_t * e)
572 {
573 	unsigned val;
574 	const char *p = str;
575 	p += parse_one_unsigned(p, ':', &val);
576 	e->vl = val % 15;
577 	p += parse_one_unsigned(p, ',', &val);
578 	e->weight = (uint8_t) val;
579 	return (int)(p - str);
580 }
581 
582 static int parse_sl2vl_entry(const char *str, uint8_t * raw)
583 {
584 	unsigned val1, val2;
585 	const char *p = str;
586 	p += parse_one_unsigned(p, ',', &val1);
587 	p += parse_one_unsigned(p, ',', &val2);
588 	*raw = (val1 << 4) | (val2 & 0xf);
589 	return (int)(p - str);
590 }
591 
592 static void qos_build_config(struct qos_config *cfg, osm_qos_options_t * opt,
593 			     osm_qos_options_t * dflt)
594 {
595 	int i;
596 	const char *p;
597 
598 	memset(cfg, 0, sizeof(*cfg));
599 
600 	if (opt->max_vls > 0)
601 		cfg->max_vls = opt->max_vls;
602 	else {
603 		if (dflt->max_vls > 0)
604 			cfg->max_vls = dflt->max_vls;
605 		else
606 			cfg->max_vls = OSM_DEFAULT_QOS_MAX_VLS;
607 	}
608 
609 	if (opt->high_limit >= 0)
610 		cfg->vl_high_limit = (uint8_t) opt->high_limit;
611 	else {
612 		if (dflt->high_limit >= 0)
613 			cfg->vl_high_limit = (uint8_t) dflt->high_limit;
614 		else
615 			cfg->vl_high_limit = (uint8_t) OSM_DEFAULT_QOS_HIGH_LIMIT;
616 	}
617 
618 	if (opt->vlarb_high)
619 		p = opt->vlarb_high;
620 	else {
621 		if (dflt->vlarb_high)
622 			p = dflt->vlarb_high;
623 		else
624 			p = OSM_DEFAULT_QOS_VLARB_HIGH;
625 	}
626 	for (i = 0; i < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; i++) {
627 		p += parse_vlarb_entry(p,
628 				       &cfg->vlarb_high[i /
629 							IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK].
630 				       vl_entry[i %
631 						IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]);
632 	}
633 
634 	if (opt->vlarb_low)
635 		p = opt->vlarb_low;
636 	else {
637 		if (dflt->vlarb_low)
638 			p = dflt->vlarb_low;
639 		else
640 			p = OSM_DEFAULT_QOS_VLARB_LOW;
641 	}
642 	for (i = 0; i < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; i++) {
643 		p += parse_vlarb_entry(p,
644 				       &cfg->vlarb_low[i /
645 						       IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK].
646 				       vl_entry[i %
647 						IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]);
648 	}
649 
650 	p = opt->sl2vl ? opt->sl2vl : dflt->sl2vl;
651 	if (opt->sl2vl)
652 		p = opt->sl2vl;
653 	else {
654 		if (dflt->sl2vl)
655 			p = dflt->sl2vl;
656 		else
657 			p = OSM_DEFAULT_QOS_SL2VL;
658 	}
659 	for (i = 0; i < IB_MAX_NUM_VLS / 2; i++)
660 		p += parse_sl2vl_entry(p, &cfg->sl2vl.raw_vl_by_sl[i]);
661 }
662