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