1321936Shselasky/*
2321936Shselasky * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved.
3321936Shselasky * Copyright (c) 2010-2015 Mellanox Technologies LTD. All rights reserved.
4321936Shselasky * Copyright (c) 2009 HNR Consulting. All rights reserved.
5321936Shselasky *
6321936Shselasky * This software is available to you under a choice of one of two
7321936Shselasky * licenses.  You may choose to be licensed under the terms of the GNU
8321936Shselasky * General Public License (GPL) Version 2, available from the file
9321936Shselasky * COPYING in the main directory of this source tree, or the
10321936Shselasky * OpenIB.org BSD license below:
11321936Shselasky *
12321936Shselasky *     Redistribution and use in source and binary forms, with or
13321936Shselasky *     without modification, are permitted provided that the following
14321936Shselasky *     conditions are met:
15321936Shselasky *
16321936Shselasky *      - Redistributions of source code must retain the above
17321936Shselasky *        copyright notice, this list of conditions and the following
18321936Shselasky *        disclaimer.
19321936Shselasky *
20321936Shselasky *      - Redistributions in binary form must reproduce the above
21321936Shselasky *        copyright notice, this list of conditions and the following
22321936Shselasky *        disclaimer in the documentation and/or other materials
23321936Shselasky *        provided with the distribution.
24321936Shselasky *
25321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32321936Shselasky * SOFTWARE.
33321936Shselasky *
34321936Shselasky */
35321936Shselasky
36321936Shselasky/*
37321936Shselasky * Abstract:
38321936Shselasky *    Implementation of OpenSM QoS infrastructure primitives
39321936Shselasky */
40321936Shselasky
41321936Shselasky#if HAVE_CONFIG_H
42321936Shselasky#  include <config.h>
43321936Shselasky#endif				/* HAVE_CONFIG_H */
44321936Shselasky
45321936Shselasky#include <stdlib.h>
46321936Shselasky#include <string.h>
47321936Shselasky
48321936Shselasky#include <iba/ib_types.h>
49321936Shselasky#include <complib/cl_qmap.h>
50321936Shselasky#include <complib/cl_debug.h>
51321936Shselasky#include <opensm/osm_file_ids.h>
52321936Shselasky#define FILE_ID OSM_FILE_QOS_C
53321936Shselasky#include <opensm/osm_opensm.h>
54321936Shselasky#include <opensm/osm_subnet.h>
55321936Shselasky#include <opensm/osm_qos_policy.h>
56321936Shselasky
57321936Shselaskystruct qos_config {
58321936Shselasky	uint8_t max_vls;
59321936Shselasky	uint8_t vl_high_limit;
60321936Shselasky	ib_vl_arb_table_t vlarb_high[2];
61321936Shselasky	ib_vl_arb_table_t vlarb_low[2];
62321936Shselasky	ib_slvl_table_t sl2vl;
63321936Shselasky};
64321936Shselasky
65321936Shselaskytypedef struct qos_mad_item {
66321936Shselasky	cl_list_item_t list_item;
67321936Shselasky	osm_madw_t *p_madw;
68321936Shselasky} qos_mad_item_t;
69321936Shselasky
70321936Shselaskytypedef struct qos_mad_list {
71321936Shselasky	cl_list_item_t list_item;
72321936Shselasky	cl_qlist_t port_mad_list;
73321936Shselasky} qos_mad_list_t;
74321936Shselasky
75321936Shselaskystatic void qos_build_config(struct qos_config *cfg,
76321936Shselasky			     osm_qos_options_t * opt,
77321936Shselasky			     osm_qos_options_t * dflt);
78321936Shselasky
79321936Shselasky/*
80321936Shselasky * QoS primitives
81321936Shselasky */
82321936Shselasky
83321936Shselaskystatic qos_mad_item_t *osm_qos_mad_create(IN osm_sm_t * sm,
84321936Shselasky					  IN osm_physp_t * p,
85321936Shselasky					  IN uint32_t data_size,
86321936Shselasky					  IN uint8_t * p_data,
87321936Shselasky					  IN ib_net16_t attr_id,
88321936Shselasky					  IN uint32_t attr_mod)
89321936Shselasky
90321936Shselasky{
91321936Shselasky	qos_mad_item_t *p_mad;
92321936Shselasky	osm_madw_context_t context;
93321936Shselasky	osm_madw_t *p_madw;
94321936Shselasky	osm_node_t *p_node;
95321936Shselasky	osm_physp_t *physp0;
96321936Shselasky	ib_net64_t m_key;
97321936Shselasky
98321936Shselasky	p_node = osm_physp_get_node_ptr(p);
99321936Shselasky	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH &&
100321936Shselasky	    osm_physp_get_port_num(p) != 0) {
101321936Shselasky		physp0 = osm_node_get_physp_ptr(p_node, 0);
102321936Shselasky		m_key = ib_port_info_get_m_key(&physp0->port_info);
103321936Shselasky	} else
104321936Shselasky		m_key = ib_port_info_get_m_key(&p->port_info);
105321936Shselasky
106321936Shselasky	switch (attr_id){
107321936Shselasky	case IB_MAD_ATTR_SLVL_TABLE:
108321936Shselasky		context.slvl_context.node_guid = osm_node_get_node_guid(p_node);
109321936Shselasky		context.slvl_context.port_guid = osm_physp_get_port_guid(p);
110321936Shselasky		context.slvl_context.set_method = TRUE;
111321936Shselasky		break;
112321936Shselasky	case IB_MAD_ATTR_VL_ARBITRATION:
113321936Shselasky		context.vla_context.node_guid = osm_node_get_node_guid(p_node);
114321936Shselasky		context.vla_context.port_guid = osm_physp_get_port_guid(p);
115321936Shselasky		context.vla_context.set_method = TRUE;
116321936Shselasky		break;
117321936Shselasky	default:
118321936Shselasky		return NULL;
119321936Shselasky	}
120321936Shselasky
121321936Shselasky	p_mad = (qos_mad_item_t *) malloc(sizeof(*p_mad));
122321936Shselasky	if (!p_mad)
123321936Shselasky		return NULL;
124321936Shselasky
125321936Shselasky	memset(p_mad, 0, sizeof(*p_mad));
126321936Shselasky
127321936Shselasky	p_madw = osm_prepare_req_set(sm, osm_physp_get_dr_path_ptr(p),
128321936Shselasky				     p_data, data_size,
129321936Shselasky				     attr_id, cl_hton32(attr_mod),
130321936Shselasky				     FALSE, m_key,
131321936Shselasky				     CL_DISP_MSGID_NONE, &context);
132321936Shselasky
133321936Shselasky	if (p_madw == NULL) {
134321936Shselasky		free(p_mad);
135321936Shselasky		return NULL;
136321936Shselasky	}
137321936Shselasky	p_mad->p_madw = p_madw;
138321936Shselasky	return p_mad;
139321936Shselasky}
140321936Shselasky
141321936Shselaskystatic void osm_qos_mad_delete(qos_mad_item_t ** p_item)
142321936Shselasky{
143321936Shselasky	free(*p_item);
144321936Shselasky	*p_item = NULL;
145321936Shselasky}
146321936Shselasky
147321936Shselaskystatic ib_api_status_t vlarb_update_table_block(osm_sm_t * sm,
148321936Shselasky						osm_physp_t * p,
149321936Shselasky						uint8_t port_num,
150321936Shselasky						unsigned force_update,
151321936Shselasky						const ib_vl_arb_table_t *
152321936Shselasky						table_block,
153321936Shselasky						unsigned block_length,
154321936Shselasky						unsigned block_num,
155321936Shselasky						cl_qlist_t *mad_list)
156321936Shselasky{
157321936Shselasky	struct osm_routing_engine *re = sm->p_subn->p_osm->routing_engine_used;
158321936Shselasky	ib_vl_arb_table_t block;
159321936Shselasky	uint32_t attr_mod;
160321936Shselasky	unsigned vl_mask, i;
161321936Shselasky	qos_mad_item_t *p_mad;
162321936Shselasky	vl_mask = (1 << (ib_port_info_get_op_vls(&p->port_info) - 1)) - 1;
163321936Shselasky
164321936Shselasky	memset(&block, 0, sizeof(block));
165321936Shselasky	memcpy(&block, table_block, block_length * sizeof(block.vl_entry[0]));
166321936Shselasky
167321936Shselasky	if (re && re->update_vlarb)
168321936Shselasky		re->update_vlarb(re->context, p, port_num, &block,
169321936Shselasky				 block_length, block_num);
170321936Shselasky
171321936Shselasky	for (i = 0; i < block_length; i++)
172321936Shselasky		block.vl_entry[i].vl &= vl_mask;
173321936Shselasky
174321936Shselasky	if (!force_update &&
175321936Shselasky	    !memcmp(&p->vl_arb[block_num], &block,
176321936Shselasky		    block_length * sizeof(block.vl_entry[0])))
177321936Shselasky		return IB_SUCCESS;
178321936Shselasky
179321936Shselasky	attr_mod = ((block_num + 1) << 16) | port_num;
180321936Shselasky
181321936Shselasky	p_mad = osm_qos_mad_create(sm,p,sizeof(block),(uint8_t *) & block,
182321936Shselasky				   IB_MAD_ATTR_VL_ARBITRATION, attr_mod);
183321936Shselasky
184321936Shselasky	if (!p_mad)
185321936Shselasky		return IB_INSUFFICIENT_MEMORY;
186321936Shselasky
187321936Shselasky	/*
188321936Shselasky	 * Zero the stored VL Arbitration block, so in case the MAD will
189321936Shselasky	 * end up with error, we will resend it in the next sweep.
190321936Shselasky	 */
191321936Shselasky	memset(&p->vl_arb[block_num], 0,
192321936Shselasky	       block_length * sizeof(block.vl_entry[0]));
193321936Shselasky
194321936Shselasky	cl_qlist_insert_tail(mad_list, &p_mad->list_item);
195321936Shselasky
196321936Shselasky	return IB_SUCCESS;
197321936Shselasky}
198321936Shselasky
199321936Shselaskystatic ib_api_status_t vlarb_update(osm_sm_t * sm, osm_physp_t * p,
200321936Shselasky				    uint8_t port_num, unsigned force_update,
201321936Shselasky				    const struct qos_config *qcfg,
202321936Shselasky				    cl_qlist_t *mad_list)
203321936Shselasky{
204321936Shselasky	ib_api_status_t status = IB_SUCCESS;
205321936Shselasky	ib_port_info_t *p_pi = &p->port_info;
206321936Shselasky	unsigned len;
207321936Shselasky
208321936Shselasky	if (p_pi->vl_arb_low_cap > 0) {
209321936Shselasky		len = p_pi->vl_arb_low_cap < IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK ?
210321936Shselasky		    p_pi->vl_arb_low_cap : IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
211321936Shselasky		if ((status = vlarb_update_table_block(sm, p, port_num,
212321936Shselasky						       force_update,
213321936Shselasky						       &qcfg->vlarb_low[0],
214321936Shselasky						       len, 0,
215321936Shselasky						       mad_list)) != IB_SUCCESS)
216321936Shselasky			return status;
217321936Shselasky	}
218321936Shselasky	if (p_pi->vl_arb_low_cap > IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) {
219321936Shselasky		len = p_pi->vl_arb_low_cap % IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
220321936Shselasky		if ((status = vlarb_update_table_block(sm, p, port_num,
221321936Shselasky						       force_update,
222321936Shselasky						       &qcfg->vlarb_low[1],
223321936Shselasky						       len, 1,
224321936Shselasky						       mad_list)) != IB_SUCCESS)
225321936Shselasky			return status;
226321936Shselasky	}
227321936Shselasky	if (p_pi->vl_arb_high_cap > 0) {
228321936Shselasky		len = p_pi->vl_arb_high_cap < IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK ?
229321936Shselasky		    p_pi->vl_arb_high_cap : IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
230321936Shselasky		if ((status = vlarb_update_table_block(sm, p, port_num,
231321936Shselasky						       force_update,
232321936Shselasky						       &qcfg->vlarb_high[0],
233321936Shselasky						       len, 2,
234321936Shselasky						       mad_list)) != IB_SUCCESS)
235321936Shselasky			return status;
236321936Shselasky	}
237321936Shselasky	if (p_pi->vl_arb_high_cap > IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) {
238321936Shselasky		len = p_pi->vl_arb_high_cap % IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
239321936Shselasky		if ((status = vlarb_update_table_block(sm, p, port_num,
240321936Shselasky						       force_update,
241321936Shselasky						       &qcfg->vlarb_high[1],
242321936Shselasky						       len, 3,
243321936Shselasky						       mad_list)) != IB_SUCCESS)
244321936Shselasky			return status;
245321936Shselasky	}
246321936Shselasky
247321936Shselasky	return status;
248321936Shselasky}
249321936Shselasky
250321936Shselaskystatic ib_api_status_t sl2vl_update_table(osm_sm_t * sm, osm_physp_t * p,
251321936Shselasky					  uint8_t in_port, uint32_t attr_mod,
252321936Shselasky					  unsigned force_update,
253321936Shselasky					  const ib_slvl_table_t * sl2vl_table,
254321936Shselasky					  cl_qlist_t *mad_list)
255321936Shselasky{
256321936Shselasky	ib_slvl_table_t tbl, *p_tbl;
257321936Shselasky	unsigned vl_mask;
258321936Shselasky	uint8_t vl1, vl2;
259321936Shselasky	int i;
260321936Shselasky	qos_mad_item_t *p_mad;
261321936Shselasky
262321936Shselasky	vl_mask = (1 << (ib_port_info_get_op_vls(&p->port_info) - 1)) - 1;
263321936Shselasky
264321936Shselasky	for (i = 0; i < IB_MAX_NUM_VLS / 2; i++) {
265321936Shselasky		vl1 = sl2vl_table->raw_vl_by_sl[i] >> 4;
266321936Shselasky		vl2 = sl2vl_table->raw_vl_by_sl[i] & 0xf;
267321936Shselasky		if (vl1 != 15)
268321936Shselasky			vl1 &= vl_mask;
269321936Shselasky		if (vl2 != 15)
270321936Shselasky			vl2 &= vl_mask;
271321936Shselasky		tbl.raw_vl_by_sl[i] = (vl1 << 4) | vl2;
272321936Shselasky	}
273321936Shselasky
274321936Shselasky	p_tbl = osm_physp_get_slvl_tbl(p, in_port);
275321936Shselasky
276321936Shselasky	if (!force_update && !memcmp(p_tbl, &tbl, sizeof(tbl)))
277321936Shselasky		return IB_SUCCESS;
278321936Shselasky
279321936Shselasky	p_mad = osm_qos_mad_create(sm, p, sizeof(tbl), (uint8_t *) & tbl,
280321936Shselasky				   IB_MAD_ATTR_SLVL_TABLE, attr_mod);
281321936Shselasky	if (!p_mad)
282321936Shselasky		return IB_INSUFFICIENT_MEMORY;
283321936Shselasky
284321936Shselasky	/*
285321936Shselasky	 * Zero the stored SL2VL block, so in case the MAD will
286321936Shselasky	 * end up with error, we will resend it in the next sweep.
287321936Shselasky	 */
288321936Shselasky	memset(p_tbl, 0, sizeof(tbl));
289321936Shselasky
290321936Shselasky	cl_qlist_insert_tail(mad_list, &p_mad->list_item);
291321936Shselasky	return IB_SUCCESS;
292321936Shselasky}
293321936Shselasky
294321936Shselaskystatic int qos_extports_setup(osm_sm_t * sm, osm_node_t *node,
295321936Shselasky			      const struct qos_config *qcfg,
296321936Shselasky			      cl_qlist_t *port_mad_list)
297321936Shselasky
298321936Shselasky{
299321936Shselasky	osm_physp_t *p0, *p;
300321936Shselasky	unsigned force_update;
301321936Shselasky	unsigned num_ports = osm_node_get_num_physp(node);
302321936Shselasky	struct osm_routing_engine *re = sm->p_subn->p_osm->routing_engine_used;
303321936Shselasky	int ret = 0;
304321936Shselasky	unsigned in, out;
305321936Shselasky	uint8_t op_vl, common_op_vl = 0, max_num = 0;
306321936Shselasky	uint8_t op_vl_arr[15];
307321936Shselasky
308321936Shselasky	/*
309321936Shselasky	 * Do nothing unless the most recent routing attempt was successful.
310321936Shselasky	 */
311321936Shselasky	if (!re)
312321936Shselasky		return ret;
313321936Shselasky
314321936Shselasky	for (out = 1; out < num_ports; out++) {
315321936Shselasky		p = osm_node_get_physp_ptr(node, out);
316321936Shselasky		if (!p)
317321936Shselasky			continue;
318321936Shselasky		if (ib_port_info_get_port_state(&p->port_info) == IB_LINK_DOWN)
319321936Shselasky			continue;
320321936Shselasky		force_update = p->need_update || sm->p_subn->need_update;
321321936Shselasky		p->vl_high_limit = qcfg->vl_high_limit;
322321936Shselasky		if (vlarb_update(sm, p, p->port_num, force_update, qcfg,
323321936Shselasky				 port_mad_list))
324321936Shselasky			ret = -1;
325321936Shselasky	}
326321936Shselasky
327321936Shselasky	p0 = osm_node_get_physp_ptr(node, 0);
328321936Shselasky	if (!(p0->port_info.capability_mask & IB_PORT_CAP_HAS_SL_MAP))
329321936Shselasky		return ret;
330321936Shselasky
331321936Shselasky	if (ib_switch_info_get_opt_sl2vlmapping(&node->sw->switch_info) &&
332321936Shselasky	    sm->p_subn->opt.use_optimized_slvl && !re->update_sl2vl) {
333321936Shselasky
334321936Shselasky		/* we should find the op_vl that is used by majority of ports */
335321936Shselasky		memset(&op_vl_arr[0], 0, sizeof(op_vl_arr));
336321936Shselasky		p0 = osm_node_get_physp_ptr(node, 1);
337321936Shselasky
338321936Shselasky		for (out = 1; out < num_ports; out++) {
339321936Shselasky			p = osm_node_get_physp_ptr(node, out);
340321936Shselasky			if (!p)
341321936Shselasky				continue;
342321936Shselasky			if (ib_port_info_get_port_state(&p->port_info) ==
343321936Shselasky			    IB_LINK_DOWN)
344321936Shselasky				continue;
345321936Shselasky			op_vl = ib_port_info_get_op_vls(&p->port_info);
346321936Shselasky			op_vl_arr[op_vl]++;
347321936Shselasky			if (op_vl_arr[op_vl] > max_num){
348321936Shselasky				max_num = op_vl_arr[op_vl];
349321936Shselasky				common_op_vl = op_vl;
350321936Shselasky				/* remember the port with most common op_vl */
351321936Shselasky				p0 = p;
352321936Shselasky			}
353321936Shselasky
354321936Shselasky		}
355321936Shselasky		if (!p0)
356321936Shselasky			return -1;
357321936Shselasky		force_update = node->sw->need_update || sm->p_subn->need_update;
358321936Shselasky		if (sl2vl_update_table(sm, p0, p0->port_num, 0x30000, force_update,
359321936Shselasky					&qcfg->sl2vl, port_mad_list))
360321936Shselasky			ret = -1;
361321936Shselasky		/*
362321936Shselasky		 * Overwrite default ALL configuration if port's
363321936Shselasky		 * op_vl is different.
364321936Shselasky		 */
365321936Shselasky		for (out = 1; out < num_ports; out++) {
366321936Shselasky			p = osm_node_get_physp_ptr(node, out);
367321936Shselasky			if (!p)
368321936Shselasky				continue;
369321936Shselasky			if (ib_port_info_get_port_state(&p->port_info) ==
370321936Shselasky			    IB_LINK_DOWN)
371321936Shselasky				continue;
372321936Shselasky
373321936Shselasky			force_update = p->need_update || force_update;
374321936Shselasky			if (ib_port_info_get_op_vls(&p->port_info) !=
375321936Shselasky			    common_op_vl &&
376321936Shselasky			    sl2vl_update_table(sm, p, p->port_num, 0x20000 | out,
377321936Shselasky					       force_update, &qcfg->sl2vl,
378321936Shselasky					       port_mad_list))
379321936Shselasky				ret = -1;
380321936Shselasky		}
381321936Shselasky		return ret;
382321936Shselasky	}
383321936Shselasky
384321936Shselasky	/* non optimized sl2vl configuration */
385321936Shselasky	out = ib_switch_info_is_enhanced_port0(&node->sw->switch_info) ? 0 : 1;
386321936Shselasky	for (; out < num_ports; out++) {
387321936Shselasky		p = osm_node_get_physp_ptr(node, out);
388321936Shselasky		if (!p)
389321936Shselasky			continue;
390321936Shselasky		if (ib_port_info_get_port_state(&p->port_info) == IB_LINK_DOWN)
391321936Shselasky			continue;
392321936Shselasky		force_update = p->need_update || sm->p_subn->need_update;
393321936Shselasky		/* go over all in ports */
394321936Shselasky		for (in = 0; in < num_ports; in++) {
395321936Shselasky			const ib_slvl_table_t *port_sl2vl = &qcfg->sl2vl;
396321936Shselasky			ib_slvl_table_t routing_sl2vl;
397321936Shselasky
398321936Shselasky			if (re->update_sl2vl) {
399321936Shselasky				routing_sl2vl = *port_sl2vl;
400321936Shselasky				re->update_sl2vl(re->context,
401321936Shselasky						 p, in, out, &routing_sl2vl);
402321936Shselasky				port_sl2vl = &routing_sl2vl;
403321936Shselasky			}
404321936Shselasky			if (sl2vl_update_table(sm, p, in, in << 8 | out,
405321936Shselasky					       force_update, port_sl2vl,
406321936Shselasky					       port_mad_list))
407321936Shselasky				ret = -1;
408321936Shselasky		}
409321936Shselasky	}
410321936Shselasky
411321936Shselasky	return ret;
412321936Shselasky}
413321936Shselasky
414321936Shselaskystatic int qos_endport_setup(osm_sm_t * sm, osm_physp_t * p,
415321936Shselasky			     const struct qos_config *qcfg, int vlarb_only,
416321936Shselasky			     cl_qlist_t *port_mad_list)
417321936Shselasky{
418321936Shselasky	unsigned force_update = p->need_update || sm->p_subn->need_update;
419321936Shselasky	struct osm_routing_engine *re = sm->p_subn->p_osm->routing_engine_used;
420321936Shselasky	const ib_slvl_table_t *port_sl2vl = &qcfg->sl2vl;
421321936Shselasky	ib_slvl_table_t routing_sl2vl;
422321936Shselasky
423321936Shselasky	p->vl_high_limit = qcfg->vl_high_limit;
424321936Shselasky	if (vlarb_update(sm, p, 0, force_update, qcfg, port_mad_list))
425321936Shselasky		return -1;
426321936Shselasky	if (vlarb_only)
427321936Shselasky		return 0;
428321936Shselasky
429321936Shselasky	if (!(p->port_info.capability_mask & IB_PORT_CAP_HAS_SL_MAP))
430321936Shselasky		return 0;
431321936Shselasky
432321936Shselasky	if (re && re->update_sl2vl) {
433321936Shselasky		routing_sl2vl = *port_sl2vl;
434321936Shselasky		re->update_sl2vl(re->context, p, 0, 0, &routing_sl2vl);
435321936Shselasky		port_sl2vl = &routing_sl2vl;
436321936Shselasky	}
437321936Shselasky	if (sl2vl_update_table(sm, p, 0, 0, force_update, port_sl2vl,
438321936Shselasky			       port_mad_list))
439321936Shselasky		return -1;
440321936Shselasky
441321936Shselasky	return 0;
442321936Shselasky}
443321936Shselasky
444321936Shselaskyint osm_qos_setup(osm_opensm_t * p_osm)
445321936Shselasky{
446321936Shselasky	struct qos_config ca_config, sw0_config, swe_config, rtr_config;
447321936Shselasky	struct qos_config *cfg;
448321936Shselasky	cl_qmap_t *p_tbl;
449321936Shselasky	cl_map_item_t *p_next;
450321936Shselasky	osm_port_t *p_port;
451321936Shselasky	osm_node_t *p_node;
452321936Shselasky	int ret = 0;
453321936Shselasky	int vlarb_only;
454321936Shselasky	qos_mad_list_t *p_list, *p_list_next;
455321936Shselasky	qos_mad_item_t *p_port_mad;
456321936Shselasky	cl_qlist_t qos_mad_list;
457321936Shselasky
458321936Shselasky	if (!p_osm->subn.opt.qos)
459321936Shselasky		return 0;
460321936Shselasky
461321936Shselasky	OSM_LOG_ENTER(&p_osm->log);
462321936Shselasky
463321936Shselasky	qos_build_config(&ca_config, &p_osm->subn.opt.qos_ca_options,
464321936Shselasky			 &p_osm->subn.opt.qos_options);
465321936Shselasky	qos_build_config(&sw0_config, &p_osm->subn.opt.qos_sw0_options,
466321936Shselasky			 &p_osm->subn.opt.qos_options);
467321936Shselasky	qos_build_config(&swe_config, &p_osm->subn.opt.qos_swe_options,
468321936Shselasky			 &p_osm->subn.opt.qos_options);
469321936Shselasky	qos_build_config(&rtr_config, &p_osm->subn.opt.qos_rtr_options,
470321936Shselasky			 &p_osm->subn.opt.qos_options);
471321936Shselasky
472321936Shselasky	cl_qlist_init(&qos_mad_list);
473321936Shselasky
474321936Shselasky	cl_plock_excl_acquire(&p_osm->lock);
475321936Shselasky
476321936Shselasky	/* read QoS policy config file */
477321936Shselasky	osm_qos_parse_policy_file(&p_osm->subn);
478321936Shselasky	p_tbl = &p_osm->subn.port_guid_tbl;
479321936Shselasky	p_next = cl_qmap_head(p_tbl);
480321936Shselasky	while (p_next != cl_qmap_end(p_tbl)) {
481321936Shselasky		vlarb_only = 0;
482321936Shselasky		p_port = (osm_port_t *) p_next;
483321936Shselasky		p_next = cl_qmap_next(p_next);
484321936Shselasky
485321936Shselasky		p_list = (qos_mad_list_t *) malloc(sizeof(*p_list));
486321936Shselasky		if (!p_list) {
487321936Shselasky			cl_plock_release(&p_osm->lock);
488321936Shselasky			return -1;
489321936Shselasky		}
490321936Shselasky
491321936Shselasky		memset(p_list, 0, sizeof(*p_list));
492321936Shselasky
493321936Shselasky		cl_qlist_init(&p_list->port_mad_list);
494321936Shselasky
495321936Shselasky		p_node = p_port->p_node;
496321936Shselasky		if (p_node->sw) {
497321936Shselasky			if (qos_extports_setup(&p_osm->sm, p_node, &swe_config,
498321936Shselasky					       &p_list->port_mad_list)) {
499321936Shselasky				cl_plock_release(&p_osm->lock);
500321936Shselasky				ret = -1;
501321936Shselasky			}
502321936Shselasky
503321936Shselasky			/* skip base port 0 */
504321936Shselasky			if (!ib_switch_info_is_enhanced_port0
505321936Shselasky			    (&p_node->sw->switch_info))
506321936Shselasky				goto Continue;
507321936Shselasky
508321936Shselasky			if (ib_switch_info_get_opt_sl2vlmapping(&p_node->sw->switch_info) &&
509321936Shselasky			    p_osm->sm.p_subn->opt.use_optimized_slvl &&
510321936Shselasky			    !memcmp(&swe_config.sl2vl, &sw0_config.sl2vl,
511321936Shselasky				    sizeof(swe_config.sl2vl)))
512321936Shselasky				vlarb_only = 1;
513321936Shselasky
514321936Shselasky			cfg = &sw0_config;
515321936Shselasky		} else if (osm_node_get_type(p_node) == IB_NODE_TYPE_ROUTER)
516321936Shselasky			cfg = &rtr_config;
517321936Shselasky		else
518321936Shselasky			cfg = &ca_config;
519321936Shselasky
520321936Shselasky		if (qos_endport_setup(&p_osm->sm, p_port->p_physp, cfg,
521321936Shselasky				      vlarb_only, &p_list->port_mad_list)) {
522321936Shselasky			cl_plock_release(&p_osm->lock);
523321936Shselasky			ret = -1;
524321936Shselasky		}
525321936ShselaskyContinue:
526321936Shselasky		/* if MAD list is not empty, add it to the global MAD list */
527321936Shselasky		if (cl_qlist_count(&p_list->port_mad_list)) {
528321936Shselasky			cl_qlist_insert_tail(&qos_mad_list, &p_list->list_item);
529321936Shselasky		} else {
530321936Shselasky			free(p_list);
531321936Shselasky		}
532321936Shselasky	}
533321936Shselasky	while (cl_qlist_count(&qos_mad_list)) {
534321936Shselasky		p_list_next = (qos_mad_list_t *) cl_qlist_head(&qos_mad_list);
535321936Shselasky		while (p_list_next !=
536321936Shselasky			(qos_mad_list_t *) cl_qlist_end(&qos_mad_list)) {
537321936Shselasky			p_list = p_list_next;
538321936Shselasky			p_list_next = (qos_mad_list_t *)
539321936Shselasky				      cl_qlist_next(&p_list->list_item);
540321936Shselasky			/* next MAD to send*/
541321936Shselasky			p_port_mad = (qos_mad_item_t *)
542321936Shselasky				     cl_qlist_remove_head(&p_list->port_mad_list);
543321936Shselasky			osm_send_req_mad(&p_osm->sm, p_port_mad->p_madw);
544321936Shselasky			osm_qos_mad_delete(&p_port_mad);
545321936Shselasky			/* remove the QoS MAD from global MAD list */
546321936Shselasky			if (cl_qlist_count(&p_list->port_mad_list) == 0) {
547321936Shselasky				cl_qlist_remove_item(&qos_mad_list, &p_list->list_item);
548321936Shselasky				free(p_list);
549321936Shselasky			}
550321936Shselasky		}
551321936Shselasky	}
552321936Shselasky
553321936Shselasky	cl_plock_release(&p_osm->lock);
554321936Shselasky	OSM_LOG_EXIT(&p_osm->log);
555321936Shselasky
556321936Shselasky	return ret;
557321936Shselasky}
558321936Shselasky
559321936Shselasky/*
560321936Shselasky *  QoS config stuff
561321936Shselasky */
562321936Shselaskystatic int parse_one_unsigned(const char *str, char delim, unsigned *val)
563321936Shselasky{
564321936Shselasky	char *end;
565321936Shselasky	*val = strtoul(str, &end, 0);
566321936Shselasky	if (*end)
567321936Shselasky		end++;
568321936Shselasky	return (int)(end - str);
569321936Shselasky}
570321936Shselasky
571321936Shselaskystatic int parse_vlarb_entry(const char *str, ib_vl_arb_element_t * e)
572321936Shselasky{
573321936Shselasky	unsigned val;
574321936Shselasky	const char *p = str;
575321936Shselasky	p += parse_one_unsigned(p, ':', &val);
576321936Shselasky	e->vl = val % 15;
577321936Shselasky	p += parse_one_unsigned(p, ',', &val);
578321936Shselasky	e->weight = (uint8_t) val;
579321936Shselasky	return (int)(p - str);
580321936Shselasky}
581321936Shselasky
582321936Shselaskystatic int parse_sl2vl_entry(const char *str, uint8_t * raw)
583321936Shselasky{
584321936Shselasky	unsigned val1, val2;
585321936Shselasky	const char *p = str;
586321936Shselasky	p += parse_one_unsigned(p, ',', &val1);
587321936Shselasky	p += parse_one_unsigned(p, ',', &val2);
588321936Shselasky	*raw = (val1 << 4) | (val2 & 0xf);
589321936Shselasky	return (int)(p - str);
590321936Shselasky}
591321936Shselasky
592321936Shselaskystatic void qos_build_config(struct qos_config *cfg, osm_qos_options_t * opt,
593321936Shselasky			     osm_qos_options_t * dflt)
594321936Shselasky{
595321936Shselasky	int i;
596321936Shselasky	const char *p;
597321936Shselasky
598321936Shselasky	memset(cfg, 0, sizeof(*cfg));
599321936Shselasky
600321936Shselasky	if (opt->max_vls > 0)
601321936Shselasky		cfg->max_vls = opt->max_vls;
602321936Shselasky	else {
603321936Shselasky		if (dflt->max_vls > 0)
604321936Shselasky			cfg->max_vls = dflt->max_vls;
605321936Shselasky		else
606321936Shselasky			cfg->max_vls = OSM_DEFAULT_QOS_MAX_VLS;
607321936Shselasky	}
608321936Shselasky
609321936Shselasky	if (opt->high_limit >= 0)
610321936Shselasky		cfg->vl_high_limit = (uint8_t) opt->high_limit;
611321936Shselasky	else {
612321936Shselasky		if (dflt->high_limit >= 0)
613321936Shselasky			cfg->vl_high_limit = (uint8_t) dflt->high_limit;
614321936Shselasky		else
615321936Shselasky			cfg->vl_high_limit = (uint8_t) OSM_DEFAULT_QOS_HIGH_LIMIT;
616321936Shselasky	}
617321936Shselasky
618321936Shselasky	if (opt->vlarb_high)
619321936Shselasky		p = opt->vlarb_high;
620321936Shselasky	else {
621321936Shselasky		if (dflt->vlarb_high)
622321936Shselasky			p = dflt->vlarb_high;
623321936Shselasky		else
624321936Shselasky			p = OSM_DEFAULT_QOS_VLARB_HIGH;
625321936Shselasky	}
626321936Shselasky	for (i = 0; i < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; i++) {
627321936Shselasky		p += parse_vlarb_entry(p,
628321936Shselasky				       &cfg->vlarb_high[i /
629321936Shselasky							IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK].
630321936Shselasky				       vl_entry[i %
631321936Shselasky						IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]);
632321936Shselasky	}
633321936Shselasky
634321936Shselasky	if (opt->vlarb_low)
635321936Shselasky		p = opt->vlarb_low;
636321936Shselasky	else {
637321936Shselasky		if (dflt->vlarb_low)
638321936Shselasky			p = dflt->vlarb_low;
639321936Shselasky		else
640321936Shselasky			p = OSM_DEFAULT_QOS_VLARB_LOW;
641321936Shselasky	}
642321936Shselasky	for (i = 0; i < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; i++) {
643321936Shselasky		p += parse_vlarb_entry(p,
644321936Shselasky				       &cfg->vlarb_low[i /
645321936Shselasky						       IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK].
646321936Shselasky				       vl_entry[i %
647321936Shselasky						IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]);
648321936Shselasky	}
649321936Shselasky
650321936Shselasky	p = opt->sl2vl ? opt->sl2vl : dflt->sl2vl;
651321936Shselasky	if (opt->sl2vl)
652321936Shselasky		p = opt->sl2vl;
653321936Shselasky	else {
654321936Shselasky		if (dflt->sl2vl)
655321936Shselasky			p = dflt->sl2vl;
656321936Shselasky		else
657321936Shselasky			p = OSM_DEFAULT_QOS_SL2VL;
658321936Shselasky	}
659321936Shselasky	for (i = 0; i < IB_MAX_NUM_VLS / 2; i++)
660321936Shselasky		p += parse_sl2vl_entry(p, &cfg->sl2vl.raw_vl_by_sl[i]);
661321936Shselasky}
662