1f48ad614SDennis Dalessandro /* 2f48ad614SDennis Dalessandro * Copyright(c) 2015, 2016 Intel Corporation. 3f48ad614SDennis Dalessandro * 4f48ad614SDennis Dalessandro * This file is provided under a dual BSD/GPLv2 license. When using or 5f48ad614SDennis Dalessandro * redistributing this file, you may do so under either license. 6f48ad614SDennis Dalessandro * 7f48ad614SDennis Dalessandro * GPL LICENSE SUMMARY 8f48ad614SDennis Dalessandro * 9f48ad614SDennis Dalessandro * This program is free software; you can redistribute it and/or modify 10f48ad614SDennis Dalessandro * it under the terms of version 2 of the GNU General Public License as 11f48ad614SDennis Dalessandro * published by the Free Software Foundation. 12f48ad614SDennis Dalessandro * 13f48ad614SDennis Dalessandro * This program is distributed in the hope that it will be useful, but 14f48ad614SDennis Dalessandro * WITHOUT ANY WARRANTY; without even the implied warranty of 15f48ad614SDennis Dalessandro * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16f48ad614SDennis Dalessandro * General Public License for more details. 17f48ad614SDennis Dalessandro * 18f48ad614SDennis Dalessandro * BSD LICENSE 19f48ad614SDennis Dalessandro * 20f48ad614SDennis Dalessandro * Redistribution and use in source and binary forms, with or without 21f48ad614SDennis Dalessandro * modification, are permitted provided that the following conditions 22f48ad614SDennis Dalessandro * are met: 23f48ad614SDennis Dalessandro * 24f48ad614SDennis Dalessandro * - Redistributions of source code must retain the above copyright 25f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer. 26f48ad614SDennis Dalessandro * - Redistributions in binary form must reproduce the above copyright 27f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer in 28f48ad614SDennis Dalessandro * the documentation and/or other materials provided with the 29f48ad614SDennis Dalessandro * distribution. 30f48ad614SDennis Dalessandro * - Neither the name of Intel Corporation nor the names of its 31f48ad614SDennis Dalessandro * contributors may be used to endorse or promote products derived 32f48ad614SDennis Dalessandro * from this software without specific prior written permission. 33f48ad614SDennis Dalessandro * 34f48ad614SDennis Dalessandro * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 35f48ad614SDennis Dalessandro * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 36f48ad614SDennis Dalessandro * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 37f48ad614SDennis Dalessandro * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 38f48ad614SDennis Dalessandro * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39f48ad614SDennis Dalessandro * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40f48ad614SDennis Dalessandro * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 41f48ad614SDennis Dalessandro * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 42f48ad614SDennis Dalessandro * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 43f48ad614SDennis Dalessandro * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 44f48ad614SDennis Dalessandro * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45f48ad614SDennis Dalessandro * 46f48ad614SDennis Dalessandro */ 47f48ad614SDennis Dalessandro 48f48ad614SDennis Dalessandro #include <linux/net.h> 49f48ad614SDennis Dalessandro #define OPA_NUM_PKEY_BLOCKS_PER_SMP (OPA_SMP_DR_DATA_SIZE \ 50f48ad614SDennis Dalessandro / (OPA_PARTITION_TABLE_BLK_SIZE * sizeof(u16))) 51f48ad614SDennis Dalessandro 52f48ad614SDennis Dalessandro #include "hfi.h" 53f48ad614SDennis Dalessandro #include "mad.h" 54f48ad614SDennis Dalessandro #include "trace.h" 55f48ad614SDennis Dalessandro #include "qp.h" 56f48ad614SDennis Dalessandro 57f48ad614SDennis Dalessandro /* the reset value from the FM is supposed to be 0xffff, handle both */ 58f48ad614SDennis Dalessandro #define OPA_LINK_WIDTH_RESET_OLD 0x0fff 59f48ad614SDennis Dalessandro #define OPA_LINK_WIDTH_RESET 0xffff 60f48ad614SDennis Dalessandro 61f48ad614SDennis Dalessandro static int reply(struct ib_mad_hdr *smp) 62f48ad614SDennis Dalessandro { 63f48ad614SDennis Dalessandro /* 64f48ad614SDennis Dalessandro * The verbs framework will handle the directed/LID route 65f48ad614SDennis Dalessandro * packet changes. 66f48ad614SDennis Dalessandro */ 67f48ad614SDennis Dalessandro smp->method = IB_MGMT_METHOD_GET_RESP; 68f48ad614SDennis Dalessandro if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 69f48ad614SDennis Dalessandro smp->status |= IB_SMP_DIRECTION; 70f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 71f48ad614SDennis Dalessandro } 72f48ad614SDennis Dalessandro 73f48ad614SDennis Dalessandro static inline void clear_opa_smp_data(struct opa_smp *smp) 74f48ad614SDennis Dalessandro { 75f48ad614SDennis Dalessandro void *data = opa_get_smp_data(smp); 76f48ad614SDennis Dalessandro size_t size = opa_get_smp_data_size(smp); 77f48ad614SDennis Dalessandro 78f48ad614SDennis Dalessandro memset(data, 0, size); 79f48ad614SDennis Dalessandro } 80f48ad614SDennis Dalessandro 8134d351f8SSebastian Sanchez void hfi1_event_pkey_change(struct hfi1_devdata *dd, u8 port) 8234d351f8SSebastian Sanchez { 8334d351f8SSebastian Sanchez struct ib_event event; 8434d351f8SSebastian Sanchez 8534d351f8SSebastian Sanchez event.event = IB_EVENT_PKEY_CHANGE; 8634d351f8SSebastian Sanchez event.device = &dd->verbs_dev.rdi.ibdev; 8734d351f8SSebastian Sanchez event.element.port_num = port; 8834d351f8SSebastian Sanchez ib_dispatch_event(&event); 8934d351f8SSebastian Sanchez } 9034d351f8SSebastian Sanchez 91f48ad614SDennis Dalessandro static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len) 92f48ad614SDennis Dalessandro { 93f48ad614SDennis Dalessandro struct ib_mad_send_buf *send_buf; 94f48ad614SDennis Dalessandro struct ib_mad_agent *agent; 95f48ad614SDennis Dalessandro struct opa_smp *smp; 96f48ad614SDennis Dalessandro int ret; 97f48ad614SDennis Dalessandro unsigned long flags; 98f48ad614SDennis Dalessandro unsigned long timeout; 99f48ad614SDennis Dalessandro int pkey_idx; 100f48ad614SDennis Dalessandro u32 qpn = ppd_from_ibp(ibp)->sm_trap_qp; 101f48ad614SDennis Dalessandro 102f48ad614SDennis Dalessandro agent = ibp->rvp.send_agent; 103f48ad614SDennis Dalessandro if (!agent) 104f48ad614SDennis Dalessandro return; 105f48ad614SDennis Dalessandro 106f48ad614SDennis Dalessandro /* o14-3.2.1 */ 107f48ad614SDennis Dalessandro if (ppd_from_ibp(ibp)->lstate != IB_PORT_ACTIVE) 108f48ad614SDennis Dalessandro return; 109f48ad614SDennis Dalessandro 110f48ad614SDennis Dalessandro /* o14-2 */ 111f48ad614SDennis Dalessandro if (ibp->rvp.trap_timeout && time_before(jiffies, 112f48ad614SDennis Dalessandro ibp->rvp.trap_timeout)) 113f48ad614SDennis Dalessandro return; 114f48ad614SDennis Dalessandro 115f48ad614SDennis Dalessandro pkey_idx = hfi1_lookup_pkey_idx(ibp, LIM_MGMT_P_KEY); 116f48ad614SDennis Dalessandro if (pkey_idx < 0) { 117f48ad614SDennis Dalessandro pr_warn("%s: failed to find limited mgmt pkey, defaulting 0x%x\n", 118f48ad614SDennis Dalessandro __func__, hfi1_get_pkey(ibp, 1)); 119f48ad614SDennis Dalessandro pkey_idx = 1; 120f48ad614SDennis Dalessandro } 121f48ad614SDennis Dalessandro 122f48ad614SDennis Dalessandro send_buf = ib_create_send_mad(agent, qpn, pkey_idx, 0, 123f48ad614SDennis Dalessandro IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, 124f48ad614SDennis Dalessandro GFP_ATOMIC, IB_MGMT_BASE_VERSION); 125f48ad614SDennis Dalessandro if (IS_ERR(send_buf)) 126f48ad614SDennis Dalessandro return; 127f48ad614SDennis Dalessandro 128f48ad614SDennis Dalessandro smp = send_buf->mad; 129f48ad614SDennis Dalessandro smp->base_version = OPA_MGMT_BASE_VERSION; 130f48ad614SDennis Dalessandro smp->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; 1319fa240bbSHal Rosenstock smp->class_version = OPA_SM_CLASS_VERSION; 132f48ad614SDennis Dalessandro smp->method = IB_MGMT_METHOD_TRAP; 133f48ad614SDennis Dalessandro ibp->rvp.tid++; 134f48ad614SDennis Dalessandro smp->tid = cpu_to_be64(ibp->rvp.tid); 135f48ad614SDennis Dalessandro smp->attr_id = IB_SMP_ATTR_NOTICE; 136f48ad614SDennis Dalessandro /* o14-1: smp->mkey = 0; */ 137f48ad614SDennis Dalessandro memcpy(smp->route.lid.data, data, len); 138f48ad614SDennis Dalessandro 139f48ad614SDennis Dalessandro spin_lock_irqsave(&ibp->rvp.lock, flags); 140f48ad614SDennis Dalessandro if (!ibp->rvp.sm_ah) { 141f48ad614SDennis Dalessandro if (ibp->rvp.sm_lid != be16_to_cpu(IB_LID_PERMISSIVE)) { 142f48ad614SDennis Dalessandro struct ib_ah *ah; 143f48ad614SDennis Dalessandro 144f48ad614SDennis Dalessandro ah = hfi1_create_qp0_ah(ibp, ibp->rvp.sm_lid); 145f48ad614SDennis Dalessandro if (IS_ERR(ah)) { 146f48ad614SDennis Dalessandro ret = PTR_ERR(ah); 147f48ad614SDennis Dalessandro } else { 148f48ad614SDennis Dalessandro send_buf->ah = ah; 149f48ad614SDennis Dalessandro ibp->rvp.sm_ah = ibah_to_rvtah(ah); 150f48ad614SDennis Dalessandro ret = 0; 151f48ad614SDennis Dalessandro } 152f48ad614SDennis Dalessandro } else { 153f48ad614SDennis Dalessandro ret = -EINVAL; 154f48ad614SDennis Dalessandro } 155f48ad614SDennis Dalessandro } else { 156f48ad614SDennis Dalessandro send_buf->ah = &ibp->rvp.sm_ah->ibah; 157f48ad614SDennis Dalessandro ret = 0; 158f48ad614SDennis Dalessandro } 159f48ad614SDennis Dalessandro spin_unlock_irqrestore(&ibp->rvp.lock, flags); 160f48ad614SDennis Dalessandro 161f48ad614SDennis Dalessandro if (!ret) 162f48ad614SDennis Dalessandro ret = ib_post_send_mad(send_buf, NULL); 163f48ad614SDennis Dalessandro if (!ret) { 164f48ad614SDennis Dalessandro /* 4.096 usec. */ 165f48ad614SDennis Dalessandro timeout = (4096 * (1UL << ibp->rvp.subnet_timeout)) / 1000; 166f48ad614SDennis Dalessandro ibp->rvp.trap_timeout = jiffies + usecs_to_jiffies(timeout); 167f48ad614SDennis Dalessandro } else { 168f48ad614SDennis Dalessandro ib_free_send_mad(send_buf); 169f48ad614SDennis Dalessandro ibp->rvp.trap_timeout = 0; 170f48ad614SDennis Dalessandro } 171f48ad614SDennis Dalessandro } 172f48ad614SDennis Dalessandro 173f48ad614SDennis Dalessandro /* 174f48ad614SDennis Dalessandro * Send a bad [PQ]_Key trap (ch. 14.3.8). 175f48ad614SDennis Dalessandro */ 176f48ad614SDennis Dalessandro void hfi1_bad_pqkey(struct hfi1_ibport *ibp, __be16 trap_num, u32 key, u32 sl, 177f48ad614SDennis Dalessandro u32 qp1, u32 qp2, u16 lid1, u16 lid2) 178f48ad614SDennis Dalessandro { 179f48ad614SDennis Dalessandro struct opa_mad_notice_attr data; 180f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 181f48ad614SDennis Dalessandro u32 _lid1 = lid1; 182f48ad614SDennis Dalessandro u32 _lid2 = lid2; 183f48ad614SDennis Dalessandro 184f48ad614SDennis Dalessandro memset(&data, 0, sizeof(data)); 185f48ad614SDennis Dalessandro 186f48ad614SDennis Dalessandro if (trap_num == OPA_TRAP_BAD_P_KEY) 187f48ad614SDennis Dalessandro ibp->rvp.pkey_violations++; 188f48ad614SDennis Dalessandro else 189f48ad614SDennis Dalessandro ibp->rvp.qkey_violations++; 190f48ad614SDennis Dalessandro ibp->rvp.n_pkt_drops++; 191f48ad614SDennis Dalessandro 192f48ad614SDennis Dalessandro /* Send violation trap */ 193f48ad614SDennis Dalessandro data.generic_type = IB_NOTICE_TYPE_SECURITY; 194f48ad614SDennis Dalessandro data.prod_type_lsb = IB_NOTICE_PROD_CA; 195f48ad614SDennis Dalessandro data.trap_num = trap_num; 196f48ad614SDennis Dalessandro data.issuer_lid = cpu_to_be32(lid); 197f48ad614SDennis Dalessandro data.ntc_257_258.lid1 = cpu_to_be32(_lid1); 198f48ad614SDennis Dalessandro data.ntc_257_258.lid2 = cpu_to_be32(_lid2); 199f48ad614SDennis Dalessandro data.ntc_257_258.key = cpu_to_be32(key); 200f48ad614SDennis Dalessandro data.ntc_257_258.sl = sl << 3; 201f48ad614SDennis Dalessandro data.ntc_257_258.qp1 = cpu_to_be32(qp1); 202f48ad614SDennis Dalessandro data.ntc_257_258.qp2 = cpu_to_be32(qp2); 203f48ad614SDennis Dalessandro 204f48ad614SDennis Dalessandro send_trap(ibp, &data, sizeof(data)); 205f48ad614SDennis Dalessandro } 206f48ad614SDennis Dalessandro 207f48ad614SDennis Dalessandro /* 208f48ad614SDennis Dalessandro * Send a bad M_Key trap (ch. 14.3.9). 209f48ad614SDennis Dalessandro */ 210f48ad614SDennis Dalessandro static void bad_mkey(struct hfi1_ibport *ibp, struct ib_mad_hdr *mad, 211f48ad614SDennis Dalessandro __be64 mkey, __be32 dr_slid, u8 return_path[], u8 hop_cnt) 212f48ad614SDennis Dalessandro { 213f48ad614SDennis Dalessandro struct opa_mad_notice_attr data; 214f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 215f48ad614SDennis Dalessandro 216f48ad614SDennis Dalessandro memset(&data, 0, sizeof(data)); 217f48ad614SDennis Dalessandro /* Send violation trap */ 218f48ad614SDennis Dalessandro data.generic_type = IB_NOTICE_TYPE_SECURITY; 219f48ad614SDennis Dalessandro data.prod_type_lsb = IB_NOTICE_PROD_CA; 220f48ad614SDennis Dalessandro data.trap_num = OPA_TRAP_BAD_M_KEY; 221f48ad614SDennis Dalessandro data.issuer_lid = cpu_to_be32(lid); 222f48ad614SDennis Dalessandro data.ntc_256.lid = data.issuer_lid; 223f48ad614SDennis Dalessandro data.ntc_256.method = mad->method; 224f48ad614SDennis Dalessandro data.ntc_256.attr_id = mad->attr_id; 225f48ad614SDennis Dalessandro data.ntc_256.attr_mod = mad->attr_mod; 226f48ad614SDennis Dalessandro data.ntc_256.mkey = mkey; 227f48ad614SDennis Dalessandro if (mad->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 228f48ad614SDennis Dalessandro data.ntc_256.dr_slid = dr_slid; 229f48ad614SDennis Dalessandro data.ntc_256.dr_trunc_hop = IB_NOTICE_TRAP_DR_NOTICE; 230f48ad614SDennis Dalessandro if (hop_cnt > ARRAY_SIZE(data.ntc_256.dr_rtn_path)) { 231f48ad614SDennis Dalessandro data.ntc_256.dr_trunc_hop |= 232f48ad614SDennis Dalessandro IB_NOTICE_TRAP_DR_TRUNC; 233f48ad614SDennis Dalessandro hop_cnt = ARRAY_SIZE(data.ntc_256.dr_rtn_path); 234f48ad614SDennis Dalessandro } 235f48ad614SDennis Dalessandro data.ntc_256.dr_trunc_hop |= hop_cnt; 236f48ad614SDennis Dalessandro memcpy(data.ntc_256.dr_rtn_path, return_path, 237f48ad614SDennis Dalessandro hop_cnt); 238f48ad614SDennis Dalessandro } 239f48ad614SDennis Dalessandro 240f48ad614SDennis Dalessandro send_trap(ibp, &data, sizeof(data)); 241f48ad614SDennis Dalessandro } 242f48ad614SDennis Dalessandro 243f48ad614SDennis Dalessandro /* 244f48ad614SDennis Dalessandro * Send a Port Capability Mask Changed trap (ch. 14.3.11). 245f48ad614SDennis Dalessandro */ 246f48ad614SDennis Dalessandro void hfi1_cap_mask_chg(struct rvt_dev_info *rdi, u8 port_num) 247f48ad614SDennis Dalessandro { 248f48ad614SDennis Dalessandro struct opa_mad_notice_attr data; 249f48ad614SDennis Dalessandro struct hfi1_ibdev *verbs_dev = dev_from_rdi(rdi); 250f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_dev(verbs_dev); 251f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = &dd->pport[port_num - 1].ibport_data; 252f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 253f48ad614SDennis Dalessandro 254f48ad614SDennis Dalessandro memset(&data, 0, sizeof(data)); 255f48ad614SDennis Dalessandro 256f48ad614SDennis Dalessandro data.generic_type = IB_NOTICE_TYPE_INFO; 257f48ad614SDennis Dalessandro data.prod_type_lsb = IB_NOTICE_PROD_CA; 258f48ad614SDennis Dalessandro data.trap_num = OPA_TRAP_CHANGE_CAPABILITY; 259f48ad614SDennis Dalessandro data.issuer_lid = cpu_to_be32(lid); 260f48ad614SDennis Dalessandro data.ntc_144.lid = data.issuer_lid; 261f48ad614SDennis Dalessandro data.ntc_144.new_cap_mask = cpu_to_be32(ibp->rvp.port_cap_flags); 262f48ad614SDennis Dalessandro 263f48ad614SDennis Dalessandro send_trap(ibp, &data, sizeof(data)); 264f48ad614SDennis Dalessandro } 265f48ad614SDennis Dalessandro 266f48ad614SDennis Dalessandro /* 267f48ad614SDennis Dalessandro * Send a System Image GUID Changed trap (ch. 14.3.12). 268f48ad614SDennis Dalessandro */ 269f48ad614SDennis Dalessandro void hfi1_sys_guid_chg(struct hfi1_ibport *ibp) 270f48ad614SDennis Dalessandro { 271f48ad614SDennis Dalessandro struct opa_mad_notice_attr data; 272f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 273f48ad614SDennis Dalessandro 274f48ad614SDennis Dalessandro memset(&data, 0, sizeof(data)); 275f48ad614SDennis Dalessandro 276f48ad614SDennis Dalessandro data.generic_type = IB_NOTICE_TYPE_INFO; 277f48ad614SDennis Dalessandro data.prod_type_lsb = IB_NOTICE_PROD_CA; 278f48ad614SDennis Dalessandro data.trap_num = OPA_TRAP_CHANGE_SYSGUID; 279f48ad614SDennis Dalessandro data.issuer_lid = cpu_to_be32(lid); 280f48ad614SDennis Dalessandro data.ntc_145.new_sys_guid = ib_hfi1_sys_image_guid; 281f48ad614SDennis Dalessandro data.ntc_145.lid = data.issuer_lid; 282f48ad614SDennis Dalessandro 283f48ad614SDennis Dalessandro send_trap(ibp, &data, sizeof(data)); 284f48ad614SDennis Dalessandro } 285f48ad614SDennis Dalessandro 286f48ad614SDennis Dalessandro /* 287f48ad614SDennis Dalessandro * Send a Node Description Changed trap (ch. 14.3.13). 288f48ad614SDennis Dalessandro */ 289f48ad614SDennis Dalessandro void hfi1_node_desc_chg(struct hfi1_ibport *ibp) 290f48ad614SDennis Dalessandro { 291f48ad614SDennis Dalessandro struct opa_mad_notice_attr data; 292f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 293f48ad614SDennis Dalessandro 294f48ad614SDennis Dalessandro memset(&data, 0, sizeof(data)); 295f48ad614SDennis Dalessandro 296f48ad614SDennis Dalessandro data.generic_type = IB_NOTICE_TYPE_INFO; 297f48ad614SDennis Dalessandro data.prod_type_lsb = IB_NOTICE_PROD_CA; 298f48ad614SDennis Dalessandro data.trap_num = OPA_TRAP_CHANGE_CAPABILITY; 299f48ad614SDennis Dalessandro data.issuer_lid = cpu_to_be32(lid); 300f48ad614SDennis Dalessandro data.ntc_144.lid = data.issuer_lid; 301f48ad614SDennis Dalessandro data.ntc_144.change_flags = 302f48ad614SDennis Dalessandro cpu_to_be16(OPA_NOTICE_TRAP_NODE_DESC_CHG); 303f48ad614SDennis Dalessandro 304f48ad614SDennis Dalessandro send_trap(ibp, &data, sizeof(data)); 305f48ad614SDennis Dalessandro } 306f48ad614SDennis Dalessandro 307f48ad614SDennis Dalessandro static int __subn_get_opa_nodedesc(struct opa_smp *smp, u32 am, 308f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, 309f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 310f48ad614SDennis Dalessandro { 311f48ad614SDennis Dalessandro struct opa_node_description *nd; 312f48ad614SDennis Dalessandro 313f48ad614SDennis Dalessandro if (am) { 314f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 315f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 316f48ad614SDennis Dalessandro } 317f48ad614SDennis Dalessandro 318f48ad614SDennis Dalessandro nd = (struct opa_node_description *)data; 319f48ad614SDennis Dalessandro 320f48ad614SDennis Dalessandro memcpy(nd->data, ibdev->node_desc, sizeof(nd->data)); 321f48ad614SDennis Dalessandro 322f48ad614SDennis Dalessandro if (resp_len) 323f48ad614SDennis Dalessandro *resp_len += sizeof(*nd); 324f48ad614SDennis Dalessandro 325f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 326f48ad614SDennis Dalessandro } 327f48ad614SDennis Dalessandro 328f48ad614SDennis Dalessandro static int __subn_get_opa_nodeinfo(struct opa_smp *smp, u32 am, u8 *data, 329f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 330f48ad614SDennis Dalessandro u32 *resp_len) 331f48ad614SDennis Dalessandro { 332f48ad614SDennis Dalessandro struct opa_node_info *ni; 333f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 334f48ad614SDennis Dalessandro unsigned pidx = port - 1; /* IB number port from 1, hw from 0 */ 335f48ad614SDennis Dalessandro 336f48ad614SDennis Dalessandro ni = (struct opa_node_info *)data; 337f48ad614SDennis Dalessandro 338f48ad614SDennis Dalessandro /* GUID 0 is illegal */ 339a6cd5f08SJakub Pawlak if (am || pidx >= dd->num_pports || ibdev->node_guid == 0 || 340a6cd5f08SJakub Pawlak get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX) == 0) { 341f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 342f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 343f48ad614SDennis Dalessandro } 344f48ad614SDennis Dalessandro 345a6cd5f08SJakub Pawlak ni->port_guid = get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX); 346f48ad614SDennis Dalessandro ni->base_version = OPA_MGMT_BASE_VERSION; 3479fa240bbSHal Rosenstock ni->class_version = OPA_SM_CLASS_VERSION; 348f48ad614SDennis Dalessandro ni->node_type = 1; /* channel adapter */ 349f48ad614SDennis Dalessandro ni->num_ports = ibdev->phys_port_cnt; 350f48ad614SDennis Dalessandro /* This is already in network order */ 351f48ad614SDennis Dalessandro ni->system_image_guid = ib_hfi1_sys_image_guid; 352a6cd5f08SJakub Pawlak ni->node_guid = ibdev->node_guid; 353f48ad614SDennis Dalessandro ni->partition_cap = cpu_to_be16(hfi1_get_npkeys(dd)); 354f48ad614SDennis Dalessandro ni->device_id = cpu_to_be16(dd->pcidev->device); 355f48ad614SDennis Dalessandro ni->revision = cpu_to_be32(dd->minrev); 356f48ad614SDennis Dalessandro ni->local_port_num = port; 357f48ad614SDennis Dalessandro ni->vendor_id[0] = dd->oui1; 358f48ad614SDennis Dalessandro ni->vendor_id[1] = dd->oui2; 359f48ad614SDennis Dalessandro ni->vendor_id[2] = dd->oui3; 360f48ad614SDennis Dalessandro 361f48ad614SDennis Dalessandro if (resp_len) 362f48ad614SDennis Dalessandro *resp_len += sizeof(*ni); 363f48ad614SDennis Dalessandro 364f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 365f48ad614SDennis Dalessandro } 366f48ad614SDennis Dalessandro 367f48ad614SDennis Dalessandro static int subn_get_nodeinfo(struct ib_smp *smp, struct ib_device *ibdev, 368f48ad614SDennis Dalessandro u8 port) 369f48ad614SDennis Dalessandro { 370f48ad614SDennis Dalessandro struct ib_node_info *nip = (struct ib_node_info *)&smp->data; 371f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 372f48ad614SDennis Dalessandro unsigned pidx = port - 1; /* IB number port from 1, hw from 0 */ 373f48ad614SDennis Dalessandro 374f48ad614SDennis Dalessandro /* GUID 0 is illegal */ 375f48ad614SDennis Dalessandro if (smp->attr_mod || pidx >= dd->num_pports || 376a6cd5f08SJakub Pawlak ibdev->node_guid == 0 || 377a6cd5f08SJakub Pawlak get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX) == 0) { 378f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 379a6cd5f08SJakub Pawlak return reply((struct ib_mad_hdr *)smp); 380a6cd5f08SJakub Pawlak } 381f48ad614SDennis Dalessandro 382a6cd5f08SJakub Pawlak nip->port_guid = get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX); 383f48ad614SDennis Dalessandro nip->base_version = OPA_MGMT_BASE_VERSION; 3849fa240bbSHal Rosenstock nip->class_version = OPA_SM_CLASS_VERSION; 385f48ad614SDennis Dalessandro nip->node_type = 1; /* channel adapter */ 386f48ad614SDennis Dalessandro nip->num_ports = ibdev->phys_port_cnt; 387f48ad614SDennis Dalessandro /* This is already in network order */ 388f48ad614SDennis Dalessandro nip->sys_guid = ib_hfi1_sys_image_guid; 389a6cd5f08SJakub Pawlak nip->node_guid = ibdev->node_guid; 390f48ad614SDennis Dalessandro nip->partition_cap = cpu_to_be16(hfi1_get_npkeys(dd)); 391f48ad614SDennis Dalessandro nip->device_id = cpu_to_be16(dd->pcidev->device); 392f48ad614SDennis Dalessandro nip->revision = cpu_to_be32(dd->minrev); 393f48ad614SDennis Dalessandro nip->local_port_num = port; 394f48ad614SDennis Dalessandro nip->vendor_id[0] = dd->oui1; 395f48ad614SDennis Dalessandro nip->vendor_id[1] = dd->oui2; 396f48ad614SDennis Dalessandro nip->vendor_id[2] = dd->oui3; 397f48ad614SDennis Dalessandro 398f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 399f48ad614SDennis Dalessandro } 400f48ad614SDennis Dalessandro 401f48ad614SDennis Dalessandro static void set_link_width_enabled(struct hfi1_pportdata *ppd, u32 w) 402f48ad614SDennis Dalessandro { 403f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_LWID_ENB, w); 404f48ad614SDennis Dalessandro } 405f48ad614SDennis Dalessandro 406f48ad614SDennis Dalessandro static void set_link_width_downgrade_enabled(struct hfi1_pportdata *ppd, u32 w) 407f48ad614SDennis Dalessandro { 408f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_LWID_DG_ENB, w); 409f48ad614SDennis Dalessandro } 410f48ad614SDennis Dalessandro 411f48ad614SDennis Dalessandro static void set_link_speed_enabled(struct hfi1_pportdata *ppd, u32 s) 412f48ad614SDennis Dalessandro { 413f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_SPD_ENB, s); 414f48ad614SDennis Dalessandro } 415f48ad614SDennis Dalessandro 416f48ad614SDennis Dalessandro static int check_mkey(struct hfi1_ibport *ibp, struct ib_mad_hdr *mad, 417f48ad614SDennis Dalessandro int mad_flags, __be64 mkey, __be32 dr_slid, 418f48ad614SDennis Dalessandro u8 return_path[], u8 hop_cnt) 419f48ad614SDennis Dalessandro { 420f48ad614SDennis Dalessandro int valid_mkey = 0; 421f48ad614SDennis Dalessandro int ret = 0; 422f48ad614SDennis Dalessandro 423f48ad614SDennis Dalessandro /* Is the mkey in the process of expiring? */ 424f48ad614SDennis Dalessandro if (ibp->rvp.mkey_lease_timeout && 425f48ad614SDennis Dalessandro time_after_eq(jiffies, ibp->rvp.mkey_lease_timeout)) { 426f48ad614SDennis Dalessandro /* Clear timeout and mkey protection field. */ 427f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_timeout = 0; 428f48ad614SDennis Dalessandro ibp->rvp.mkeyprot = 0; 429f48ad614SDennis Dalessandro } 430f48ad614SDennis Dalessandro 431f48ad614SDennis Dalessandro if ((mad_flags & IB_MAD_IGNORE_MKEY) || ibp->rvp.mkey == 0 || 432f48ad614SDennis Dalessandro ibp->rvp.mkey == mkey) 433f48ad614SDennis Dalessandro valid_mkey = 1; 434f48ad614SDennis Dalessandro 435f48ad614SDennis Dalessandro /* Unset lease timeout on any valid Get/Set/TrapRepress */ 436f48ad614SDennis Dalessandro if (valid_mkey && ibp->rvp.mkey_lease_timeout && 437f48ad614SDennis Dalessandro (mad->method == IB_MGMT_METHOD_GET || 438f48ad614SDennis Dalessandro mad->method == IB_MGMT_METHOD_SET || 439f48ad614SDennis Dalessandro mad->method == IB_MGMT_METHOD_TRAP_REPRESS)) 440f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_timeout = 0; 441f48ad614SDennis Dalessandro 442f48ad614SDennis Dalessandro if (!valid_mkey) { 443f48ad614SDennis Dalessandro switch (mad->method) { 444f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 445f48ad614SDennis Dalessandro /* Bad mkey not a violation below level 2 */ 446f48ad614SDennis Dalessandro if (ibp->rvp.mkeyprot < 2) 447f48ad614SDennis Dalessandro break; 448f48ad614SDennis Dalessandro case IB_MGMT_METHOD_SET: 449f48ad614SDennis Dalessandro case IB_MGMT_METHOD_TRAP_REPRESS: 450f48ad614SDennis Dalessandro if (ibp->rvp.mkey_violations != 0xFFFF) 451f48ad614SDennis Dalessandro ++ibp->rvp.mkey_violations; 452f48ad614SDennis Dalessandro if (!ibp->rvp.mkey_lease_timeout && 453f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_period) 454f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_timeout = jiffies + 455f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_period * HZ; 456f48ad614SDennis Dalessandro /* Generate a trap notice. */ 457f48ad614SDennis Dalessandro bad_mkey(ibp, mad, mkey, dr_slid, return_path, 458f48ad614SDennis Dalessandro hop_cnt); 459f48ad614SDennis Dalessandro ret = 1; 460f48ad614SDennis Dalessandro } 461f48ad614SDennis Dalessandro } 462f48ad614SDennis Dalessandro 463f48ad614SDennis Dalessandro return ret; 464f48ad614SDennis Dalessandro } 465f48ad614SDennis Dalessandro 466f48ad614SDennis Dalessandro /* 467f48ad614SDennis Dalessandro * The SMA caches reads from LCB registers in case the LCB is unavailable. 468f48ad614SDennis Dalessandro * (The LCB is unavailable in certain link states, for example.) 469f48ad614SDennis Dalessandro */ 470f48ad614SDennis Dalessandro struct lcb_datum { 471f48ad614SDennis Dalessandro u32 off; 472f48ad614SDennis Dalessandro u64 val; 473f48ad614SDennis Dalessandro }; 474f48ad614SDennis Dalessandro 475f48ad614SDennis Dalessandro static struct lcb_datum lcb_cache[] = { 476f48ad614SDennis Dalessandro { DC_LCB_STS_ROUND_TRIP_LTP_CNT, 0 }, 477f48ad614SDennis Dalessandro }; 478f48ad614SDennis Dalessandro 479f48ad614SDennis Dalessandro static int write_lcb_cache(u32 off, u64 val) 480f48ad614SDennis Dalessandro { 481f48ad614SDennis Dalessandro int i; 482f48ad614SDennis Dalessandro 483f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(lcb_cache); i++) { 484f48ad614SDennis Dalessandro if (lcb_cache[i].off == off) { 485f48ad614SDennis Dalessandro lcb_cache[i].val = val; 486f48ad614SDennis Dalessandro return 0; 487f48ad614SDennis Dalessandro } 488f48ad614SDennis Dalessandro } 489f48ad614SDennis Dalessandro 490f48ad614SDennis Dalessandro pr_warn("%s bad offset 0x%x\n", __func__, off); 491f48ad614SDennis Dalessandro return -1; 492f48ad614SDennis Dalessandro } 493f48ad614SDennis Dalessandro 494f48ad614SDennis Dalessandro static int read_lcb_cache(u32 off, u64 *val) 495f48ad614SDennis Dalessandro { 496f48ad614SDennis Dalessandro int i; 497f48ad614SDennis Dalessandro 498f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(lcb_cache); i++) { 499f48ad614SDennis Dalessandro if (lcb_cache[i].off == off) { 500f48ad614SDennis Dalessandro *val = lcb_cache[i].val; 501f48ad614SDennis Dalessandro return 0; 502f48ad614SDennis Dalessandro } 503f48ad614SDennis Dalessandro } 504f48ad614SDennis Dalessandro 505f48ad614SDennis Dalessandro pr_warn("%s bad offset 0x%x\n", __func__, off); 506f48ad614SDennis Dalessandro return -1; 507f48ad614SDennis Dalessandro } 508f48ad614SDennis Dalessandro 509f48ad614SDennis Dalessandro void read_ltp_rtt(struct hfi1_devdata *dd) 510f48ad614SDennis Dalessandro { 511f48ad614SDennis Dalessandro u64 reg; 512f48ad614SDennis Dalessandro 513f48ad614SDennis Dalessandro if (read_lcb_csr(dd, DC_LCB_STS_ROUND_TRIP_LTP_CNT, ®)) 514f48ad614SDennis Dalessandro dd_dev_err(dd, "%s: unable to read LTP RTT\n", __func__); 515f48ad614SDennis Dalessandro else 516f48ad614SDennis Dalessandro write_lcb_cache(DC_LCB_STS_ROUND_TRIP_LTP_CNT, reg); 517f48ad614SDennis Dalessandro } 518f48ad614SDennis Dalessandro 519f48ad614SDennis Dalessandro static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, 520f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 521f48ad614SDennis Dalessandro u32 *resp_len) 522f48ad614SDennis Dalessandro { 523f48ad614SDennis Dalessandro int i; 524f48ad614SDennis Dalessandro struct hfi1_devdata *dd; 525f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 526f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 527f48ad614SDennis Dalessandro struct opa_port_info *pi = (struct opa_port_info *)data; 528f48ad614SDennis Dalessandro u8 mtu; 529f48ad614SDennis Dalessandro u8 credit_rate; 530f48ad614SDennis Dalessandro u8 is_beaconing_active; 531f48ad614SDennis Dalessandro u32 state; 532f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 533f48ad614SDennis Dalessandro u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); 534f48ad614SDennis Dalessandro u32 buffer_units; 535f48ad614SDennis Dalessandro u64 tmp = 0; 536f48ad614SDennis Dalessandro 537f48ad614SDennis Dalessandro if (num_ports != 1) { 538f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 539f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 540f48ad614SDennis Dalessandro } 541f48ad614SDennis Dalessandro 542f48ad614SDennis Dalessandro dd = dd_from_ibdev(ibdev); 543f48ad614SDennis Dalessandro /* IB numbers ports from 1, hw from 0 */ 544f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 545f48ad614SDennis Dalessandro ibp = &ppd->ibport_data; 546f48ad614SDennis Dalessandro 547f48ad614SDennis Dalessandro if (ppd->vls_supported / 2 > ARRAY_SIZE(pi->neigh_mtu.pvlx_to_mtu) || 548f48ad614SDennis Dalessandro ppd->vls_supported > ARRAY_SIZE(dd->vld)) { 549f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 550f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 551f48ad614SDennis Dalessandro } 552f48ad614SDennis Dalessandro 553f48ad614SDennis Dalessandro pi->lid = cpu_to_be32(ppd->lid); 554f48ad614SDennis Dalessandro 555f48ad614SDennis Dalessandro /* Only return the mkey if the protection field allows it. */ 556f48ad614SDennis Dalessandro if (!(smp->method == IB_MGMT_METHOD_GET && 557f48ad614SDennis Dalessandro ibp->rvp.mkey != smp->mkey && 558f48ad614SDennis Dalessandro ibp->rvp.mkeyprot == 1)) 559f48ad614SDennis Dalessandro pi->mkey = ibp->rvp.mkey; 560f48ad614SDennis Dalessandro 561f48ad614SDennis Dalessandro pi->subnet_prefix = ibp->rvp.gid_prefix; 562f48ad614SDennis Dalessandro pi->sm_lid = cpu_to_be32(ibp->rvp.sm_lid); 563f48ad614SDennis Dalessandro pi->ib_cap_mask = cpu_to_be32(ibp->rvp.port_cap_flags); 564f48ad614SDennis Dalessandro pi->mkey_lease_period = cpu_to_be16(ibp->rvp.mkey_lease_period); 565f48ad614SDennis Dalessandro pi->sm_trap_qp = cpu_to_be32(ppd->sm_trap_qp); 566f48ad614SDennis Dalessandro pi->sa_qp = cpu_to_be32(ppd->sa_qp); 567f48ad614SDennis Dalessandro 568f48ad614SDennis Dalessandro pi->link_width.enabled = cpu_to_be16(ppd->link_width_enabled); 569f48ad614SDennis Dalessandro pi->link_width.supported = cpu_to_be16(ppd->link_width_supported); 570f48ad614SDennis Dalessandro pi->link_width.active = cpu_to_be16(ppd->link_width_active); 571f48ad614SDennis Dalessandro 572f48ad614SDennis Dalessandro pi->link_width_downgrade.supported = 573f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_supported); 574f48ad614SDennis Dalessandro pi->link_width_downgrade.enabled = 575f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_enabled); 576f48ad614SDennis Dalessandro pi->link_width_downgrade.tx_active = 577f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_tx_active); 578f48ad614SDennis Dalessandro pi->link_width_downgrade.rx_active = 579f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_rx_active); 580f48ad614SDennis Dalessandro 581f48ad614SDennis Dalessandro pi->link_speed.supported = cpu_to_be16(ppd->link_speed_supported); 582f48ad614SDennis Dalessandro pi->link_speed.active = cpu_to_be16(ppd->link_speed_active); 583f48ad614SDennis Dalessandro pi->link_speed.enabled = cpu_to_be16(ppd->link_speed_enabled); 584f48ad614SDennis Dalessandro 585f48ad614SDennis Dalessandro state = driver_lstate(ppd); 586f48ad614SDennis Dalessandro 587f48ad614SDennis Dalessandro if (start_of_sm_config && (state == IB_PORT_INIT)) 588f48ad614SDennis Dalessandro ppd->is_sm_config_started = 1; 589f48ad614SDennis Dalessandro 590f48ad614SDennis Dalessandro pi->port_phys_conf = (ppd->port_type & 0xf); 591f48ad614SDennis Dalessandro 592f48ad614SDennis Dalessandro pi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4; 593f48ad614SDennis Dalessandro pi->port_states.ledenable_offlinereason |= 594f48ad614SDennis Dalessandro ppd->is_sm_config_started << 5; 595f48ad614SDennis Dalessandro /* 596f48ad614SDennis Dalessandro * This pairs with the memory barrier in hfi1_start_led_override to 597f48ad614SDennis Dalessandro * ensure that we read the correct state of LED beaconing represented 598f48ad614SDennis Dalessandro * by led_override_timer_active 599f48ad614SDennis Dalessandro */ 600f48ad614SDennis Dalessandro smp_rmb(); 601f48ad614SDennis Dalessandro is_beaconing_active = !!atomic_read(&ppd->led_override_timer_active); 602f48ad614SDennis Dalessandro pi->port_states.ledenable_offlinereason |= is_beaconing_active << 6; 603f48ad614SDennis Dalessandro pi->port_states.ledenable_offlinereason |= 604f48ad614SDennis Dalessandro ppd->offline_disabled_reason; 605f48ad614SDennis Dalessandro 606f48ad614SDennis Dalessandro pi->port_states.portphysstate_portstate = 607f48ad614SDennis Dalessandro (hfi1_ibphys_portstate(ppd) << 4) | state; 608f48ad614SDennis Dalessandro 609f48ad614SDennis Dalessandro pi->mkeyprotect_lmc = (ibp->rvp.mkeyprot << 6) | ppd->lmc; 610f48ad614SDennis Dalessandro 611f48ad614SDennis Dalessandro memset(pi->neigh_mtu.pvlx_to_mtu, 0, sizeof(pi->neigh_mtu.pvlx_to_mtu)); 612f48ad614SDennis Dalessandro for (i = 0; i < ppd->vls_supported; i++) { 613f48ad614SDennis Dalessandro mtu = mtu_to_enum(dd->vld[i].mtu, HFI1_DEFAULT_ACTIVE_MTU); 614f48ad614SDennis Dalessandro if ((i % 2) == 0) 615f48ad614SDennis Dalessandro pi->neigh_mtu.pvlx_to_mtu[i / 2] |= (mtu << 4); 616f48ad614SDennis Dalessandro else 617f48ad614SDennis Dalessandro pi->neigh_mtu.pvlx_to_mtu[i / 2] |= mtu; 618f48ad614SDennis Dalessandro } 619f48ad614SDennis Dalessandro /* don't forget VL 15 */ 620f48ad614SDennis Dalessandro mtu = mtu_to_enum(dd->vld[15].mtu, 2048); 621f48ad614SDennis Dalessandro pi->neigh_mtu.pvlx_to_mtu[15 / 2] |= mtu; 622f48ad614SDennis Dalessandro pi->smsl = ibp->rvp.sm_sl & OPA_PI_MASK_SMSL; 623f48ad614SDennis Dalessandro pi->operational_vls = hfi1_get_ib_cfg(ppd, HFI1_IB_CFG_OP_VLS); 624f48ad614SDennis Dalessandro pi->partenforce_filterraw |= 625f48ad614SDennis Dalessandro (ppd->linkinit_reason & OPA_PI_MASK_LINKINIT_REASON); 626f48ad614SDennis Dalessandro if (ppd->part_enforce & HFI1_PART_ENFORCE_IN) 627f48ad614SDennis Dalessandro pi->partenforce_filterraw |= OPA_PI_MASK_PARTITION_ENFORCE_IN; 628f48ad614SDennis Dalessandro if (ppd->part_enforce & HFI1_PART_ENFORCE_OUT) 629f48ad614SDennis Dalessandro pi->partenforce_filterraw |= OPA_PI_MASK_PARTITION_ENFORCE_OUT; 630f48ad614SDennis Dalessandro pi->mkey_violations = cpu_to_be16(ibp->rvp.mkey_violations); 631f48ad614SDennis Dalessandro /* P_KeyViolations are counted by hardware. */ 632f48ad614SDennis Dalessandro pi->pkey_violations = cpu_to_be16(ibp->rvp.pkey_violations); 633f48ad614SDennis Dalessandro pi->qkey_violations = cpu_to_be16(ibp->rvp.qkey_violations); 634f48ad614SDennis Dalessandro 635f48ad614SDennis Dalessandro pi->vl.cap = ppd->vls_supported; 636f48ad614SDennis Dalessandro pi->vl.high_limit = cpu_to_be16(ibp->rvp.vl_high_limit); 637f48ad614SDennis Dalessandro pi->vl.arb_high_cap = (u8)hfi1_get_ib_cfg(ppd, HFI1_IB_CFG_VL_HIGH_CAP); 638f48ad614SDennis Dalessandro pi->vl.arb_low_cap = (u8)hfi1_get_ib_cfg(ppd, HFI1_IB_CFG_VL_LOW_CAP); 639f48ad614SDennis Dalessandro 640f48ad614SDennis Dalessandro pi->clientrereg_subnettimeout = ibp->rvp.subnet_timeout; 641f48ad614SDennis Dalessandro 642f48ad614SDennis Dalessandro pi->port_link_mode = cpu_to_be16(OPA_PORT_LINK_MODE_OPA << 10 | 643f48ad614SDennis Dalessandro OPA_PORT_LINK_MODE_OPA << 5 | 644f48ad614SDennis Dalessandro OPA_PORT_LINK_MODE_OPA); 645f48ad614SDennis Dalessandro 646f48ad614SDennis Dalessandro pi->port_ltp_crc_mode = cpu_to_be16(ppd->port_ltp_crc_mode); 647f48ad614SDennis Dalessandro 648f48ad614SDennis Dalessandro pi->port_mode = cpu_to_be16( 649f48ad614SDennis Dalessandro ppd->is_active_optimize_enabled ? 650f48ad614SDennis Dalessandro OPA_PI_MASK_PORT_ACTIVE_OPTOMIZE : 0); 651f48ad614SDennis Dalessandro 652f48ad614SDennis Dalessandro pi->port_packet_format.supported = 653f48ad614SDennis Dalessandro cpu_to_be16(OPA_PORT_PACKET_FORMAT_9B); 654f48ad614SDennis Dalessandro pi->port_packet_format.enabled = 655f48ad614SDennis Dalessandro cpu_to_be16(OPA_PORT_PACKET_FORMAT_9B); 656f48ad614SDennis Dalessandro 657f48ad614SDennis Dalessandro /* flit_control.interleave is (OPA V1, version .76): 658f48ad614SDennis Dalessandro * bits use 659f48ad614SDennis Dalessandro * ---- --- 660f48ad614SDennis Dalessandro * 2 res 661f48ad614SDennis Dalessandro * 2 DistanceSupported 662f48ad614SDennis Dalessandro * 2 DistanceEnabled 663f48ad614SDennis Dalessandro * 5 MaxNextLevelTxEnabled 664f48ad614SDennis Dalessandro * 5 MaxNestLevelRxSupported 665f48ad614SDennis Dalessandro * 666f48ad614SDennis Dalessandro * HFI supports only "distance mode 1" (see OPA V1, version .76, 667f48ad614SDennis Dalessandro * section 9.6.2), so set DistanceSupported, DistanceEnabled 668f48ad614SDennis Dalessandro * to 0x1. 669f48ad614SDennis Dalessandro */ 670f48ad614SDennis Dalessandro pi->flit_control.interleave = cpu_to_be16(0x1400); 671f48ad614SDennis Dalessandro 672f48ad614SDennis Dalessandro pi->link_down_reason = ppd->local_link_down_reason.sma; 673f48ad614SDennis Dalessandro pi->neigh_link_down_reason = ppd->neigh_link_down_reason.sma; 674f48ad614SDennis Dalessandro pi->port_error_action = cpu_to_be32(ppd->port_error_action); 675f48ad614SDennis Dalessandro pi->mtucap = mtu_to_enum(hfi1_max_mtu, IB_MTU_4096); 676f48ad614SDennis Dalessandro 677f48ad614SDennis Dalessandro /* 32.768 usec. response time (guessing) */ 678f48ad614SDennis Dalessandro pi->resptimevalue = 3; 679f48ad614SDennis Dalessandro 680f48ad614SDennis Dalessandro pi->local_port_num = port; 681f48ad614SDennis Dalessandro 682f48ad614SDennis Dalessandro /* buffer info for FM */ 683f48ad614SDennis Dalessandro pi->overall_buffer_space = cpu_to_be16(dd->link_credits); 684f48ad614SDennis Dalessandro 685f48ad614SDennis Dalessandro pi->neigh_node_guid = cpu_to_be64(ppd->neighbor_guid); 686f48ad614SDennis Dalessandro pi->neigh_port_num = ppd->neighbor_port_number; 687f48ad614SDennis Dalessandro pi->port_neigh_mode = 688f48ad614SDennis Dalessandro (ppd->neighbor_type & OPA_PI_MASK_NEIGH_NODE_TYPE) | 689f48ad614SDennis Dalessandro (ppd->mgmt_allowed ? OPA_PI_MASK_NEIGH_MGMT_ALLOWED : 0) | 690f48ad614SDennis Dalessandro (ppd->neighbor_fm_security ? 691f48ad614SDennis Dalessandro OPA_PI_MASK_NEIGH_FW_AUTH_BYPASS : 0); 692f48ad614SDennis Dalessandro 693f48ad614SDennis Dalessandro /* HFIs shall always return VL15 credits to their 694f48ad614SDennis Dalessandro * neighbor in a timely manner, without any credit return pacing. 695f48ad614SDennis Dalessandro */ 696f48ad614SDennis Dalessandro credit_rate = 0; 697f48ad614SDennis Dalessandro buffer_units = (dd->vau) & OPA_PI_MASK_BUF_UNIT_BUF_ALLOC; 698f48ad614SDennis Dalessandro buffer_units |= (dd->vcu << 3) & OPA_PI_MASK_BUF_UNIT_CREDIT_ACK; 699f48ad614SDennis Dalessandro buffer_units |= (credit_rate << 6) & 700f48ad614SDennis Dalessandro OPA_PI_MASK_BUF_UNIT_VL15_CREDIT_RATE; 701f48ad614SDennis Dalessandro buffer_units |= (dd->vl15_init << 11) & OPA_PI_MASK_BUF_UNIT_VL15_INIT; 702f48ad614SDennis Dalessandro pi->buffer_units = cpu_to_be32(buffer_units); 703f48ad614SDennis Dalessandro 704f48ad614SDennis Dalessandro pi->opa_cap_mask = cpu_to_be16(OPA_CAP_MASK3_IsSharedSpaceSupported); 705f48ad614SDennis Dalessandro 706f48ad614SDennis Dalessandro /* HFI supports a replay buffer 128 LTPs in size */ 707f48ad614SDennis Dalessandro pi->replay_depth.buffer = 0x80; 708f48ad614SDennis Dalessandro /* read the cached value of DC_LCB_STS_ROUND_TRIP_LTP_CNT */ 709f48ad614SDennis Dalessandro read_lcb_cache(DC_LCB_STS_ROUND_TRIP_LTP_CNT, &tmp); 710f48ad614SDennis Dalessandro 711f48ad614SDennis Dalessandro /* 712f48ad614SDennis Dalessandro * this counter is 16 bits wide, but the replay_depth.wire 713f48ad614SDennis Dalessandro * variable is only 8 bits 714f48ad614SDennis Dalessandro */ 715f48ad614SDennis Dalessandro if (tmp > 0xff) 716f48ad614SDennis Dalessandro tmp = 0xff; 717f48ad614SDennis Dalessandro pi->replay_depth.wire = tmp; 718f48ad614SDennis Dalessandro 719f48ad614SDennis Dalessandro if (resp_len) 720f48ad614SDennis Dalessandro *resp_len += sizeof(struct opa_port_info); 721f48ad614SDennis Dalessandro 722f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 723f48ad614SDennis Dalessandro } 724f48ad614SDennis Dalessandro 725f48ad614SDennis Dalessandro /** 726f48ad614SDennis Dalessandro * get_pkeys - return the PKEY table 727f48ad614SDennis Dalessandro * @dd: the hfi1_ib device 728f48ad614SDennis Dalessandro * @port: the IB port number 729f48ad614SDennis Dalessandro * @pkeys: the pkey table is placed here 730f48ad614SDennis Dalessandro */ 731f48ad614SDennis Dalessandro static int get_pkeys(struct hfi1_devdata *dd, u8 port, u16 *pkeys) 732f48ad614SDennis Dalessandro { 733f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = dd->pport + port - 1; 734f48ad614SDennis Dalessandro 735f48ad614SDennis Dalessandro memcpy(pkeys, ppd->pkeys, sizeof(ppd->pkeys)); 736f48ad614SDennis Dalessandro 737f48ad614SDennis Dalessandro return 0; 738f48ad614SDennis Dalessandro } 739f48ad614SDennis Dalessandro 740f48ad614SDennis Dalessandro static int __subn_get_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data, 741f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 742f48ad614SDennis Dalessandro u32 *resp_len) 743f48ad614SDennis Dalessandro { 744f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 745f48ad614SDennis Dalessandro u32 n_blocks_req = OPA_AM_NBLK(am); 746f48ad614SDennis Dalessandro u32 start_block = am & 0x7ff; 747f48ad614SDennis Dalessandro __be16 *p; 748f48ad614SDennis Dalessandro u16 *q; 749f48ad614SDennis Dalessandro int i; 750f48ad614SDennis Dalessandro u16 n_blocks_avail; 751f48ad614SDennis Dalessandro unsigned npkeys = hfi1_get_npkeys(dd); 752f48ad614SDennis Dalessandro size_t size; 753f48ad614SDennis Dalessandro 754f48ad614SDennis Dalessandro if (n_blocks_req == 0) { 755f48ad614SDennis Dalessandro pr_warn("OPA Get PKey AM Invalid : P = %d; B = 0x%x; N = 0x%x\n", 756f48ad614SDennis Dalessandro port, start_block, n_blocks_req); 757f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 758f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 759f48ad614SDennis Dalessandro } 760f48ad614SDennis Dalessandro 761f48ad614SDennis Dalessandro n_blocks_avail = (u16)(npkeys / OPA_PARTITION_TABLE_BLK_SIZE) + 1; 762f48ad614SDennis Dalessandro 763f48ad614SDennis Dalessandro size = (n_blocks_req * OPA_PARTITION_TABLE_BLK_SIZE) * sizeof(u16); 764f48ad614SDennis Dalessandro 765f48ad614SDennis Dalessandro if (start_block + n_blocks_req > n_blocks_avail || 766f48ad614SDennis Dalessandro n_blocks_req > OPA_NUM_PKEY_BLOCKS_PER_SMP) { 767f48ad614SDennis Dalessandro pr_warn("OPA Get PKey AM Invalid : s 0x%x; req 0x%x; " 768f48ad614SDennis Dalessandro "avail 0x%x; blk/smp 0x%lx\n", 769f48ad614SDennis Dalessandro start_block, n_blocks_req, n_blocks_avail, 770f48ad614SDennis Dalessandro OPA_NUM_PKEY_BLOCKS_PER_SMP); 771f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 772f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 773f48ad614SDennis Dalessandro } 774f48ad614SDennis Dalessandro 775f48ad614SDennis Dalessandro p = (__be16 *)data; 776f48ad614SDennis Dalessandro q = (u16 *)data; 777f48ad614SDennis Dalessandro /* get the real pkeys if we are requesting the first block */ 778f48ad614SDennis Dalessandro if (start_block == 0) { 779f48ad614SDennis Dalessandro get_pkeys(dd, port, q); 780f48ad614SDennis Dalessandro for (i = 0; i < npkeys; i++) 781f48ad614SDennis Dalessandro p[i] = cpu_to_be16(q[i]); 782f48ad614SDennis Dalessandro if (resp_len) 783f48ad614SDennis Dalessandro *resp_len += size; 784f48ad614SDennis Dalessandro } else { 785f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 786f48ad614SDennis Dalessandro } 787f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 788f48ad614SDennis Dalessandro } 789f48ad614SDennis Dalessandro 790f48ad614SDennis Dalessandro enum { 791f48ad614SDennis Dalessandro HFI_TRANSITION_DISALLOWED, 792f48ad614SDennis Dalessandro HFI_TRANSITION_IGNORED, 793f48ad614SDennis Dalessandro HFI_TRANSITION_ALLOWED, 794f48ad614SDennis Dalessandro HFI_TRANSITION_UNDEFINED, 795f48ad614SDennis Dalessandro }; 796f48ad614SDennis Dalessandro 797f48ad614SDennis Dalessandro /* 798f48ad614SDennis Dalessandro * Use shortened names to improve readability of 799f48ad614SDennis Dalessandro * {logical,physical}_state_transitions 800f48ad614SDennis Dalessandro */ 801f48ad614SDennis Dalessandro enum { 802f48ad614SDennis Dalessandro __D = HFI_TRANSITION_DISALLOWED, 803f48ad614SDennis Dalessandro __I = HFI_TRANSITION_IGNORED, 804f48ad614SDennis Dalessandro __A = HFI_TRANSITION_ALLOWED, 805f48ad614SDennis Dalessandro __U = HFI_TRANSITION_UNDEFINED, 806f48ad614SDennis Dalessandro }; 807f48ad614SDennis Dalessandro 808f48ad614SDennis Dalessandro /* 809f48ad614SDennis Dalessandro * IB_PORTPHYSSTATE_POLLING (2) through OPA_PORTPHYSSTATE_MAX (11) are 810f48ad614SDennis Dalessandro * represented in physical_state_transitions. 811f48ad614SDennis Dalessandro */ 812f48ad614SDennis Dalessandro #define __N_PHYSTATES (OPA_PORTPHYSSTATE_MAX - IB_PORTPHYSSTATE_POLLING + 1) 813f48ad614SDennis Dalessandro 814f48ad614SDennis Dalessandro /* 815f48ad614SDennis Dalessandro * Within physical_state_transitions, rows represent "old" states, 816f48ad614SDennis Dalessandro * columns "new" states, and physical_state_transitions.allowed[old][new] 817f48ad614SDennis Dalessandro * indicates if the transition from old state to new state is legal (see 818f48ad614SDennis Dalessandro * OPAg1v1, Table 6-4). 819f48ad614SDennis Dalessandro */ 820f48ad614SDennis Dalessandro static const struct { 821f48ad614SDennis Dalessandro u8 allowed[__N_PHYSTATES][__N_PHYSTATES]; 822f48ad614SDennis Dalessandro } physical_state_transitions = { 823f48ad614SDennis Dalessandro { 824f48ad614SDennis Dalessandro /* 2 3 4 5 6 7 8 9 10 11 */ 825f48ad614SDennis Dalessandro /* 2 */ { __A, __A, __D, __D, __D, __D, __D, __D, __D, __D }, 826f48ad614SDennis Dalessandro /* 3 */ { __A, __I, __D, __D, __D, __D, __D, __D, __D, __A }, 827f48ad614SDennis Dalessandro /* 4 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, 828f48ad614SDennis Dalessandro /* 5 */ { __A, __A, __D, __I, __D, __D, __D, __D, __D, __D }, 829f48ad614SDennis Dalessandro /* 6 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, 830f48ad614SDennis Dalessandro /* 7 */ { __D, __A, __D, __D, __D, __I, __D, __D, __D, __D }, 831f48ad614SDennis Dalessandro /* 8 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, 832f48ad614SDennis Dalessandro /* 9 */ { __I, __A, __D, __D, __D, __D, __D, __I, __D, __D }, 833f48ad614SDennis Dalessandro /*10 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, 834f48ad614SDennis Dalessandro /*11 */ { __D, __A, __D, __D, __D, __D, __D, __D, __D, __I }, 835f48ad614SDennis Dalessandro } 836f48ad614SDennis Dalessandro }; 837f48ad614SDennis Dalessandro 838f48ad614SDennis Dalessandro /* 839f48ad614SDennis Dalessandro * IB_PORT_DOWN (1) through IB_PORT_ACTIVE_DEFER (5) are represented 840f48ad614SDennis Dalessandro * logical_state_transitions 841f48ad614SDennis Dalessandro */ 842f48ad614SDennis Dalessandro 843f48ad614SDennis Dalessandro #define __N_LOGICAL_STATES (IB_PORT_ACTIVE_DEFER - IB_PORT_DOWN + 1) 844f48ad614SDennis Dalessandro 845f48ad614SDennis Dalessandro /* 846f48ad614SDennis Dalessandro * Within logical_state_transitions rows represent "old" states, 847f48ad614SDennis Dalessandro * columns "new" states, and logical_state_transitions.allowed[old][new] 848f48ad614SDennis Dalessandro * indicates if the transition from old state to new state is legal (see 849f48ad614SDennis Dalessandro * OPAg1v1, Table 9-12). 850f48ad614SDennis Dalessandro */ 851f48ad614SDennis Dalessandro static const struct { 852f48ad614SDennis Dalessandro u8 allowed[__N_LOGICAL_STATES][__N_LOGICAL_STATES]; 853f48ad614SDennis Dalessandro } logical_state_transitions = { 854f48ad614SDennis Dalessandro { 855f48ad614SDennis Dalessandro /* 1 2 3 4 5 */ 856f48ad614SDennis Dalessandro /* 1 */ { __I, __D, __D, __D, __U}, 857f48ad614SDennis Dalessandro /* 2 */ { __D, __I, __A, __D, __U}, 858f48ad614SDennis Dalessandro /* 3 */ { __D, __D, __I, __A, __U}, 859f48ad614SDennis Dalessandro /* 4 */ { __D, __D, __I, __I, __U}, 860f48ad614SDennis Dalessandro /* 5 */ { __U, __U, __U, __U, __U}, 861f48ad614SDennis Dalessandro } 862f48ad614SDennis Dalessandro }; 863f48ad614SDennis Dalessandro 864f48ad614SDennis Dalessandro static int logical_transition_allowed(int old, int new) 865f48ad614SDennis Dalessandro { 866f48ad614SDennis Dalessandro if (old < IB_PORT_NOP || old > IB_PORT_ACTIVE_DEFER || 867f48ad614SDennis Dalessandro new < IB_PORT_NOP || new > IB_PORT_ACTIVE_DEFER) { 868f48ad614SDennis Dalessandro pr_warn("invalid logical state(s) (old %d new %d)\n", 869f48ad614SDennis Dalessandro old, new); 870f48ad614SDennis Dalessandro return HFI_TRANSITION_UNDEFINED; 871f48ad614SDennis Dalessandro } 872f48ad614SDennis Dalessandro 873f48ad614SDennis Dalessandro if (new == IB_PORT_NOP) 874f48ad614SDennis Dalessandro return HFI_TRANSITION_ALLOWED; /* always allowed */ 875f48ad614SDennis Dalessandro 876f48ad614SDennis Dalessandro /* adjust states for indexing into logical_state_transitions */ 877f48ad614SDennis Dalessandro old -= IB_PORT_DOWN; 878f48ad614SDennis Dalessandro new -= IB_PORT_DOWN; 879f48ad614SDennis Dalessandro 880f48ad614SDennis Dalessandro if (old < 0 || new < 0) 881f48ad614SDennis Dalessandro return HFI_TRANSITION_UNDEFINED; 882f48ad614SDennis Dalessandro return logical_state_transitions.allowed[old][new]; 883f48ad614SDennis Dalessandro } 884f48ad614SDennis Dalessandro 885f48ad614SDennis Dalessandro static int physical_transition_allowed(int old, int new) 886f48ad614SDennis Dalessandro { 887f48ad614SDennis Dalessandro if (old < IB_PORTPHYSSTATE_NOP || old > OPA_PORTPHYSSTATE_MAX || 888f48ad614SDennis Dalessandro new < IB_PORTPHYSSTATE_NOP || new > OPA_PORTPHYSSTATE_MAX) { 889f48ad614SDennis Dalessandro pr_warn("invalid physical state(s) (old %d new %d)\n", 890f48ad614SDennis Dalessandro old, new); 891f48ad614SDennis Dalessandro return HFI_TRANSITION_UNDEFINED; 892f48ad614SDennis Dalessandro } 893f48ad614SDennis Dalessandro 894f48ad614SDennis Dalessandro if (new == IB_PORTPHYSSTATE_NOP) 895f48ad614SDennis Dalessandro return HFI_TRANSITION_ALLOWED; /* always allowed */ 896f48ad614SDennis Dalessandro 897f48ad614SDennis Dalessandro /* adjust states for indexing into physical_state_transitions */ 898f48ad614SDennis Dalessandro old -= IB_PORTPHYSSTATE_POLLING; 899f48ad614SDennis Dalessandro new -= IB_PORTPHYSSTATE_POLLING; 900f48ad614SDennis Dalessandro 901f48ad614SDennis Dalessandro if (old < 0 || new < 0) 902f48ad614SDennis Dalessandro return HFI_TRANSITION_UNDEFINED; 903f48ad614SDennis Dalessandro return physical_state_transitions.allowed[old][new]; 904f48ad614SDennis Dalessandro } 905f48ad614SDennis Dalessandro 906f48ad614SDennis Dalessandro static int port_states_transition_allowed(struct hfi1_pportdata *ppd, 907f48ad614SDennis Dalessandro u32 logical_new, u32 physical_new) 908f48ad614SDennis Dalessandro { 909f48ad614SDennis Dalessandro u32 physical_old = driver_physical_state(ppd); 910f48ad614SDennis Dalessandro u32 logical_old = driver_logical_state(ppd); 911f48ad614SDennis Dalessandro int ret, logical_allowed, physical_allowed; 912f48ad614SDennis Dalessandro 913f48ad614SDennis Dalessandro ret = logical_transition_allowed(logical_old, logical_new); 914f48ad614SDennis Dalessandro logical_allowed = ret; 915f48ad614SDennis Dalessandro 916f48ad614SDennis Dalessandro if (ret == HFI_TRANSITION_DISALLOWED || 917f48ad614SDennis Dalessandro ret == HFI_TRANSITION_UNDEFINED) { 918f48ad614SDennis Dalessandro pr_warn("invalid logical state transition %s -> %s\n", 919f48ad614SDennis Dalessandro opa_lstate_name(logical_old), 920f48ad614SDennis Dalessandro opa_lstate_name(logical_new)); 921f48ad614SDennis Dalessandro return ret; 922f48ad614SDennis Dalessandro } 923f48ad614SDennis Dalessandro 924f48ad614SDennis Dalessandro ret = physical_transition_allowed(physical_old, physical_new); 925f48ad614SDennis Dalessandro physical_allowed = ret; 926f48ad614SDennis Dalessandro 927f48ad614SDennis Dalessandro if (ret == HFI_TRANSITION_DISALLOWED || 928f48ad614SDennis Dalessandro ret == HFI_TRANSITION_UNDEFINED) { 929f48ad614SDennis Dalessandro pr_warn("invalid physical state transition %s -> %s\n", 930f48ad614SDennis Dalessandro opa_pstate_name(physical_old), 931f48ad614SDennis Dalessandro opa_pstate_name(physical_new)); 932f48ad614SDennis Dalessandro return ret; 933f48ad614SDennis Dalessandro } 934f48ad614SDennis Dalessandro 935f48ad614SDennis Dalessandro if (logical_allowed == HFI_TRANSITION_IGNORED && 936f48ad614SDennis Dalessandro physical_allowed == HFI_TRANSITION_IGNORED) 937f48ad614SDennis Dalessandro return HFI_TRANSITION_IGNORED; 938f48ad614SDennis Dalessandro 939f48ad614SDennis Dalessandro /* 940f48ad614SDennis Dalessandro * A change request of Physical Port State from 941f48ad614SDennis Dalessandro * 'Offline' to 'Polling' should be ignored. 942f48ad614SDennis Dalessandro */ 943f48ad614SDennis Dalessandro if ((physical_old == OPA_PORTPHYSSTATE_OFFLINE) && 944f48ad614SDennis Dalessandro (physical_new == IB_PORTPHYSSTATE_POLLING)) 945f48ad614SDennis Dalessandro return HFI_TRANSITION_IGNORED; 946f48ad614SDennis Dalessandro 947f48ad614SDennis Dalessandro /* 948f48ad614SDennis Dalessandro * Either physical_allowed or logical_allowed is 949f48ad614SDennis Dalessandro * HFI_TRANSITION_ALLOWED. 950f48ad614SDennis Dalessandro */ 951f48ad614SDennis Dalessandro return HFI_TRANSITION_ALLOWED; 952f48ad614SDennis Dalessandro } 953f48ad614SDennis Dalessandro 954f48ad614SDennis Dalessandro static int set_port_states(struct hfi1_pportdata *ppd, struct opa_smp *smp, 955f48ad614SDennis Dalessandro u32 logical_state, u32 phys_state, 956f48ad614SDennis Dalessandro int suppress_idle_sma) 957f48ad614SDennis Dalessandro { 958f48ad614SDennis Dalessandro struct hfi1_devdata *dd = ppd->dd; 959f48ad614SDennis Dalessandro u32 link_state; 960f48ad614SDennis Dalessandro int ret; 961f48ad614SDennis Dalessandro 962f48ad614SDennis Dalessandro ret = port_states_transition_allowed(ppd, logical_state, phys_state); 963f48ad614SDennis Dalessandro if (ret == HFI_TRANSITION_DISALLOWED || 964f48ad614SDennis Dalessandro ret == HFI_TRANSITION_UNDEFINED) { 965f48ad614SDennis Dalessandro /* error message emitted above */ 966f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 967f48ad614SDennis Dalessandro return 0; 968f48ad614SDennis Dalessandro } 969f48ad614SDennis Dalessandro 970f48ad614SDennis Dalessandro if (ret == HFI_TRANSITION_IGNORED) 971f48ad614SDennis Dalessandro return 0; 972f48ad614SDennis Dalessandro 973f48ad614SDennis Dalessandro if ((phys_state != IB_PORTPHYSSTATE_NOP) && 974f48ad614SDennis Dalessandro !(logical_state == IB_PORT_DOWN || 975f48ad614SDennis Dalessandro logical_state == IB_PORT_NOP)){ 976f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) port state invalid: logical_state 0x%x physical_state 0x%x\n", 977f48ad614SDennis Dalessandro logical_state, phys_state); 978f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 979f48ad614SDennis Dalessandro } 980f48ad614SDennis Dalessandro 981f48ad614SDennis Dalessandro /* 982f48ad614SDennis Dalessandro * Logical state changes are summarized in OPAv1g1 spec., 983f48ad614SDennis Dalessandro * Table 9-12; physical state changes are summarized in 984f48ad614SDennis Dalessandro * OPAv1g1 spec., Table 6.4. 985f48ad614SDennis Dalessandro */ 986f48ad614SDennis Dalessandro switch (logical_state) { 987f48ad614SDennis Dalessandro case IB_PORT_NOP: 988f48ad614SDennis Dalessandro if (phys_state == IB_PORTPHYSSTATE_NOP) 989f48ad614SDennis Dalessandro break; 990f48ad614SDennis Dalessandro /* FALLTHROUGH */ 991f48ad614SDennis Dalessandro case IB_PORT_DOWN: 992f48ad614SDennis Dalessandro if (phys_state == IB_PORTPHYSSTATE_NOP) { 993f48ad614SDennis Dalessandro link_state = HLS_DN_DOWNDEF; 994f48ad614SDennis Dalessandro } else if (phys_state == IB_PORTPHYSSTATE_POLLING) { 995f48ad614SDennis Dalessandro link_state = HLS_DN_POLL; 996f48ad614SDennis Dalessandro set_link_down_reason(ppd, OPA_LINKDOWN_REASON_FM_BOUNCE, 997f48ad614SDennis Dalessandro 0, OPA_LINKDOWN_REASON_FM_BOUNCE); 998f48ad614SDennis Dalessandro } else if (phys_state == IB_PORTPHYSSTATE_DISABLED) { 999f48ad614SDennis Dalessandro link_state = HLS_DN_DISABLE; 1000f48ad614SDennis Dalessandro } else { 1001f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) invalid physical state 0x%x\n", 1002f48ad614SDennis Dalessandro phys_state); 1003f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1004f48ad614SDennis Dalessandro break; 1005f48ad614SDennis Dalessandro } 1006f48ad614SDennis Dalessandro 1007f48ad614SDennis Dalessandro if ((link_state == HLS_DN_POLL || 1008f48ad614SDennis Dalessandro link_state == HLS_DN_DOWNDEF)) { 1009f48ad614SDennis Dalessandro /* 1010f48ad614SDennis Dalessandro * Going to poll. No matter what the current state, 1011f48ad614SDennis Dalessandro * always move offline first, then tune and start the 1012f48ad614SDennis Dalessandro * link. This correctly handles a FM link bounce and 1013f48ad614SDennis Dalessandro * a link enable. Going offline is a no-op if already 1014f48ad614SDennis Dalessandro * offline. 1015f48ad614SDennis Dalessandro */ 1016f48ad614SDennis Dalessandro set_link_state(ppd, HLS_DN_OFFLINE); 1017f48ad614SDennis Dalessandro start_link(ppd); 1018f48ad614SDennis Dalessandro } else { 1019f48ad614SDennis Dalessandro set_link_state(ppd, link_state); 1020f48ad614SDennis Dalessandro } 1021f48ad614SDennis Dalessandro if (link_state == HLS_DN_DISABLE && 1022f48ad614SDennis Dalessandro (ppd->offline_disabled_reason > 1023f48ad614SDennis Dalessandro HFI1_ODR_MASK(OPA_LINKDOWN_REASON_SMA_DISABLED) || 1024f48ad614SDennis Dalessandro ppd->offline_disabled_reason == 1025f48ad614SDennis Dalessandro HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE))) 1026f48ad614SDennis Dalessandro ppd->offline_disabled_reason = 1027f48ad614SDennis Dalessandro HFI1_ODR_MASK(OPA_LINKDOWN_REASON_SMA_DISABLED); 1028f48ad614SDennis Dalessandro /* 1029f48ad614SDennis Dalessandro * Don't send a reply if the response would be sent 1030f48ad614SDennis Dalessandro * through the disabled port. 1031f48ad614SDennis Dalessandro */ 1032f48ad614SDennis Dalessandro if (link_state == HLS_DN_DISABLE && smp->hop_cnt) 1033f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 1034f48ad614SDennis Dalessandro break; 1035f48ad614SDennis Dalessandro case IB_PORT_ARMED: 1036f48ad614SDennis Dalessandro ret = set_link_state(ppd, HLS_UP_ARMED); 1037f48ad614SDennis Dalessandro if ((ret == 0) && (suppress_idle_sma == 0)) 1038f48ad614SDennis Dalessandro send_idle_sma(dd, SMA_IDLE_ARM); 1039f48ad614SDennis Dalessandro break; 1040f48ad614SDennis Dalessandro case IB_PORT_ACTIVE: 1041f48ad614SDennis Dalessandro if (ppd->neighbor_normal) { 1042f48ad614SDennis Dalessandro ret = set_link_state(ppd, HLS_UP_ACTIVE); 1043f48ad614SDennis Dalessandro if (ret == 0) 1044f48ad614SDennis Dalessandro send_idle_sma(dd, SMA_IDLE_ACTIVE); 1045f48ad614SDennis Dalessandro } else { 1046f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) Cannot move to Active with NeighborNormal 0\n"); 1047f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1048f48ad614SDennis Dalessandro } 1049f48ad614SDennis Dalessandro break; 1050f48ad614SDennis Dalessandro default: 1051f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) invalid logical state 0x%x\n", 1052f48ad614SDennis Dalessandro logical_state); 1053f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1054f48ad614SDennis Dalessandro } 1055f48ad614SDennis Dalessandro 1056f48ad614SDennis Dalessandro return 0; 1057f48ad614SDennis Dalessandro } 1058f48ad614SDennis Dalessandro 1059f48ad614SDennis Dalessandro /** 1060f48ad614SDennis Dalessandro * subn_set_opa_portinfo - set port information 1061f48ad614SDennis Dalessandro * @smp: the incoming SM packet 1062f48ad614SDennis Dalessandro * @ibdev: the infiniband device 1063f48ad614SDennis Dalessandro * @port: the port on the device 1064f48ad614SDennis Dalessandro * 1065f48ad614SDennis Dalessandro */ 1066f48ad614SDennis Dalessandro static int __subn_set_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, 1067f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1068f48ad614SDennis Dalessandro u32 *resp_len) 1069f48ad614SDennis Dalessandro { 1070f48ad614SDennis Dalessandro struct opa_port_info *pi = (struct opa_port_info *)data; 1071f48ad614SDennis Dalessandro struct ib_event event; 1072f48ad614SDennis Dalessandro struct hfi1_devdata *dd; 1073f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1074f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 1075f48ad614SDennis Dalessandro u8 clientrereg; 1076f48ad614SDennis Dalessandro unsigned long flags; 1077f48ad614SDennis Dalessandro u32 smlid, opa_lid; /* tmp vars to hold LID values */ 1078f48ad614SDennis Dalessandro u16 lid; 1079f48ad614SDennis Dalessandro u8 ls_old, ls_new, ps_new; 1080f48ad614SDennis Dalessandro u8 vls; 1081f48ad614SDennis Dalessandro u8 msl; 1082f48ad614SDennis Dalessandro u8 crc_enabled; 1083f48ad614SDennis Dalessandro u16 lse, lwe, mtu; 1084f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 1085f48ad614SDennis Dalessandro u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); 1086f48ad614SDennis Dalessandro int ret, i, invalid = 0, call_set_mtu = 0; 1087f48ad614SDennis Dalessandro int call_link_downgrade_policy = 0; 1088f48ad614SDennis Dalessandro 1089f48ad614SDennis Dalessandro if (num_ports != 1) { 1090f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1091f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1092f48ad614SDennis Dalessandro } 1093f48ad614SDennis Dalessandro 1094f48ad614SDennis Dalessandro opa_lid = be32_to_cpu(pi->lid); 1095f48ad614SDennis Dalessandro if (opa_lid & 0xFFFF0000) { 1096f48ad614SDennis Dalessandro pr_warn("OPA_PortInfo lid out of range: %X\n", opa_lid); 1097f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1098f48ad614SDennis Dalessandro goto get_only; 1099f48ad614SDennis Dalessandro } 1100f48ad614SDennis Dalessandro 1101f48ad614SDennis Dalessandro lid = (u16)(opa_lid & 0x0000FFFF); 1102f48ad614SDennis Dalessandro 1103f48ad614SDennis Dalessandro smlid = be32_to_cpu(pi->sm_lid); 1104f48ad614SDennis Dalessandro if (smlid & 0xFFFF0000) { 1105f48ad614SDennis Dalessandro pr_warn("OPA_PortInfo SM lid out of range: %X\n", smlid); 1106f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1107f48ad614SDennis Dalessandro goto get_only; 1108f48ad614SDennis Dalessandro } 1109f48ad614SDennis Dalessandro smlid &= 0x0000FFFF; 1110f48ad614SDennis Dalessandro 1111f48ad614SDennis Dalessandro clientrereg = (pi->clientrereg_subnettimeout & 1112f48ad614SDennis Dalessandro OPA_PI_MASK_CLIENT_REREGISTER); 1113f48ad614SDennis Dalessandro 1114f48ad614SDennis Dalessandro dd = dd_from_ibdev(ibdev); 1115f48ad614SDennis Dalessandro /* IB numbers ports from 1, hw from 0 */ 1116f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1117f48ad614SDennis Dalessandro ibp = &ppd->ibport_data; 1118f48ad614SDennis Dalessandro event.device = ibdev; 1119f48ad614SDennis Dalessandro event.element.port_num = port; 1120f48ad614SDennis Dalessandro 1121f48ad614SDennis Dalessandro ls_old = driver_lstate(ppd); 1122f48ad614SDennis Dalessandro 1123f48ad614SDennis Dalessandro ibp->rvp.mkey = pi->mkey; 1124f48ad614SDennis Dalessandro ibp->rvp.gid_prefix = pi->subnet_prefix; 1125f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_period = be16_to_cpu(pi->mkey_lease_period); 1126f48ad614SDennis Dalessandro 1127f48ad614SDennis Dalessandro /* Must be a valid unicast LID address. */ 1128f48ad614SDennis Dalessandro if ((lid == 0 && ls_old > IB_PORT_INIT) || 1129f48ad614SDennis Dalessandro lid >= be16_to_cpu(IB_MULTICAST_LID_BASE)) { 1130f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1131f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) lid invalid 0x%x\n", 1132f48ad614SDennis Dalessandro lid); 1133f48ad614SDennis Dalessandro } else if (ppd->lid != lid || 1134f48ad614SDennis Dalessandro ppd->lmc != (pi->mkeyprotect_lmc & OPA_PI_MASK_LMC)) { 1135f48ad614SDennis Dalessandro if (ppd->lid != lid) 1136f48ad614SDennis Dalessandro hfi1_set_uevent_bits(ppd, _HFI1_EVENT_LID_CHANGE_BIT); 1137f48ad614SDennis Dalessandro if (ppd->lmc != (pi->mkeyprotect_lmc & OPA_PI_MASK_LMC)) 1138f48ad614SDennis Dalessandro hfi1_set_uevent_bits(ppd, _HFI1_EVENT_LMC_CHANGE_BIT); 1139f48ad614SDennis Dalessandro hfi1_set_lid(ppd, lid, pi->mkeyprotect_lmc & OPA_PI_MASK_LMC); 1140f48ad614SDennis Dalessandro event.event = IB_EVENT_LID_CHANGE; 1141f48ad614SDennis Dalessandro ib_dispatch_event(&event); 1142f48ad614SDennis Dalessandro } 1143f48ad614SDennis Dalessandro 1144f48ad614SDennis Dalessandro msl = pi->smsl & OPA_PI_MASK_SMSL; 1145f48ad614SDennis Dalessandro if (pi->partenforce_filterraw & OPA_PI_MASK_LINKINIT_REASON) 1146f48ad614SDennis Dalessandro ppd->linkinit_reason = 1147f48ad614SDennis Dalessandro (pi->partenforce_filterraw & 1148f48ad614SDennis Dalessandro OPA_PI_MASK_LINKINIT_REASON); 1149f48ad614SDennis Dalessandro /* enable/disable SW pkey checking as per FM control */ 1150f48ad614SDennis Dalessandro if (pi->partenforce_filterraw & OPA_PI_MASK_PARTITION_ENFORCE_IN) 1151f48ad614SDennis Dalessandro ppd->part_enforce |= HFI1_PART_ENFORCE_IN; 1152f48ad614SDennis Dalessandro else 1153f48ad614SDennis Dalessandro ppd->part_enforce &= ~HFI1_PART_ENFORCE_IN; 1154f48ad614SDennis Dalessandro 1155f48ad614SDennis Dalessandro if (pi->partenforce_filterraw & OPA_PI_MASK_PARTITION_ENFORCE_OUT) 1156f48ad614SDennis Dalessandro ppd->part_enforce |= HFI1_PART_ENFORCE_OUT; 1157f48ad614SDennis Dalessandro else 1158f48ad614SDennis Dalessandro ppd->part_enforce &= ~HFI1_PART_ENFORCE_OUT; 1159f48ad614SDennis Dalessandro 1160f48ad614SDennis Dalessandro /* Must be a valid unicast LID address. */ 1161f48ad614SDennis Dalessandro if ((smlid == 0 && ls_old > IB_PORT_INIT) || 1162f48ad614SDennis Dalessandro smlid >= be16_to_cpu(IB_MULTICAST_LID_BASE)) { 1163f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1164f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) smlid invalid 0x%x\n", smlid); 1165f48ad614SDennis Dalessandro } else if (smlid != ibp->rvp.sm_lid || msl != ibp->rvp.sm_sl) { 1166f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) smlid 0x%x\n", smlid); 1167f48ad614SDennis Dalessandro spin_lock_irqsave(&ibp->rvp.lock, flags); 1168f48ad614SDennis Dalessandro if (ibp->rvp.sm_ah) { 1169f48ad614SDennis Dalessandro if (smlid != ibp->rvp.sm_lid) 1170f48ad614SDennis Dalessandro ibp->rvp.sm_ah->attr.dlid = smlid; 1171f48ad614SDennis Dalessandro if (msl != ibp->rvp.sm_sl) 1172f48ad614SDennis Dalessandro ibp->rvp.sm_ah->attr.sl = msl; 1173f48ad614SDennis Dalessandro } 1174f48ad614SDennis Dalessandro spin_unlock_irqrestore(&ibp->rvp.lock, flags); 1175f48ad614SDennis Dalessandro if (smlid != ibp->rvp.sm_lid) 1176f48ad614SDennis Dalessandro ibp->rvp.sm_lid = smlid; 1177f48ad614SDennis Dalessandro if (msl != ibp->rvp.sm_sl) 1178f48ad614SDennis Dalessandro ibp->rvp.sm_sl = msl; 1179f48ad614SDennis Dalessandro event.event = IB_EVENT_SM_CHANGE; 1180f48ad614SDennis Dalessandro ib_dispatch_event(&event); 1181f48ad614SDennis Dalessandro } 1182f48ad614SDennis Dalessandro 1183f48ad614SDennis Dalessandro if (pi->link_down_reason == 0) { 1184f48ad614SDennis Dalessandro ppd->local_link_down_reason.sma = 0; 1185f48ad614SDennis Dalessandro ppd->local_link_down_reason.latest = 0; 1186f48ad614SDennis Dalessandro } 1187f48ad614SDennis Dalessandro 1188f48ad614SDennis Dalessandro if (pi->neigh_link_down_reason == 0) { 1189f48ad614SDennis Dalessandro ppd->neigh_link_down_reason.sma = 0; 1190f48ad614SDennis Dalessandro ppd->neigh_link_down_reason.latest = 0; 1191f48ad614SDennis Dalessandro } 1192f48ad614SDennis Dalessandro 1193f48ad614SDennis Dalessandro ppd->sm_trap_qp = be32_to_cpu(pi->sm_trap_qp); 1194f48ad614SDennis Dalessandro ppd->sa_qp = be32_to_cpu(pi->sa_qp); 1195f48ad614SDennis Dalessandro 1196f48ad614SDennis Dalessandro ppd->port_error_action = be32_to_cpu(pi->port_error_action); 1197f48ad614SDennis Dalessandro lwe = be16_to_cpu(pi->link_width.enabled); 1198f48ad614SDennis Dalessandro if (lwe) { 1199f48ad614SDennis Dalessandro if (lwe == OPA_LINK_WIDTH_RESET || 1200f48ad614SDennis Dalessandro lwe == OPA_LINK_WIDTH_RESET_OLD) 1201f48ad614SDennis Dalessandro set_link_width_enabled(ppd, ppd->link_width_supported); 1202f48ad614SDennis Dalessandro else if ((lwe & ~ppd->link_width_supported) == 0) 1203f48ad614SDennis Dalessandro set_link_width_enabled(ppd, lwe); 1204f48ad614SDennis Dalessandro else 1205f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1206f48ad614SDennis Dalessandro } 1207f48ad614SDennis Dalessandro lwe = be16_to_cpu(pi->link_width_downgrade.enabled); 1208f48ad614SDennis Dalessandro /* LWD.E is always applied - 0 means "disabled" */ 1209f48ad614SDennis Dalessandro if (lwe == OPA_LINK_WIDTH_RESET || 1210f48ad614SDennis Dalessandro lwe == OPA_LINK_WIDTH_RESET_OLD) { 1211f48ad614SDennis Dalessandro set_link_width_downgrade_enabled(ppd, 1212f48ad614SDennis Dalessandro ppd-> 1213f48ad614SDennis Dalessandro link_width_downgrade_supported 1214f48ad614SDennis Dalessandro ); 1215f48ad614SDennis Dalessandro } else if ((lwe & ~ppd->link_width_downgrade_supported) == 0) { 1216f48ad614SDennis Dalessandro /* only set and apply if something changed */ 1217f48ad614SDennis Dalessandro if (lwe != ppd->link_width_downgrade_enabled) { 1218f48ad614SDennis Dalessandro set_link_width_downgrade_enabled(ppd, lwe); 1219f48ad614SDennis Dalessandro call_link_downgrade_policy = 1; 1220f48ad614SDennis Dalessandro } 1221f48ad614SDennis Dalessandro } else { 1222f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1223f48ad614SDennis Dalessandro } 1224f48ad614SDennis Dalessandro lse = be16_to_cpu(pi->link_speed.enabled); 1225f48ad614SDennis Dalessandro if (lse) { 1226f48ad614SDennis Dalessandro if (lse & be16_to_cpu(pi->link_speed.supported)) 1227f48ad614SDennis Dalessandro set_link_speed_enabled(ppd, lse); 1228f48ad614SDennis Dalessandro else 1229f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1230f48ad614SDennis Dalessandro } 1231f48ad614SDennis Dalessandro 1232f48ad614SDennis Dalessandro ibp->rvp.mkeyprot = 1233f48ad614SDennis Dalessandro (pi->mkeyprotect_lmc & OPA_PI_MASK_MKEY_PROT_BIT) >> 6; 1234f48ad614SDennis Dalessandro ibp->rvp.vl_high_limit = be16_to_cpu(pi->vl.high_limit) & 0xFF; 1235f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_VL_HIGH_LIMIT, 1236f48ad614SDennis Dalessandro ibp->rvp.vl_high_limit); 1237f48ad614SDennis Dalessandro 1238f48ad614SDennis Dalessandro if (ppd->vls_supported / 2 > ARRAY_SIZE(pi->neigh_mtu.pvlx_to_mtu) || 1239f48ad614SDennis Dalessandro ppd->vls_supported > ARRAY_SIZE(dd->vld)) { 1240f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1241f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1242f48ad614SDennis Dalessandro } 1243f48ad614SDennis Dalessandro for (i = 0; i < ppd->vls_supported; i++) { 1244f48ad614SDennis Dalessandro if ((i % 2) == 0) 1245f48ad614SDennis Dalessandro mtu = enum_to_mtu((pi->neigh_mtu.pvlx_to_mtu[i / 2] >> 1246f48ad614SDennis Dalessandro 4) & 0xF); 1247f48ad614SDennis Dalessandro else 1248f48ad614SDennis Dalessandro mtu = enum_to_mtu(pi->neigh_mtu.pvlx_to_mtu[i / 2] & 1249f48ad614SDennis Dalessandro 0xF); 1250f48ad614SDennis Dalessandro if (mtu == 0xffff) { 1251f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) mtu invalid %d (0x%x)\n", 1252f48ad614SDennis Dalessandro mtu, 1253f48ad614SDennis Dalessandro (pi->neigh_mtu.pvlx_to_mtu[0] >> 4) & 0xF); 1254f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1255f48ad614SDennis Dalessandro mtu = hfi1_max_mtu; /* use a valid MTU */ 1256f48ad614SDennis Dalessandro } 1257f48ad614SDennis Dalessandro if (dd->vld[i].mtu != mtu) { 1258f48ad614SDennis Dalessandro dd_dev_info(dd, 1259f48ad614SDennis Dalessandro "MTU change on vl %d from %d to %d\n", 1260f48ad614SDennis Dalessandro i, dd->vld[i].mtu, mtu); 1261f48ad614SDennis Dalessandro dd->vld[i].mtu = mtu; 1262f48ad614SDennis Dalessandro call_set_mtu++; 1263f48ad614SDennis Dalessandro } 1264f48ad614SDennis Dalessandro } 1265f48ad614SDennis Dalessandro /* As per OPAV1 spec: VL15 must support and be configured 1266f48ad614SDennis Dalessandro * for operation with a 2048 or larger MTU. 1267f48ad614SDennis Dalessandro */ 1268f48ad614SDennis Dalessandro mtu = enum_to_mtu(pi->neigh_mtu.pvlx_to_mtu[15 / 2] & 0xF); 1269f48ad614SDennis Dalessandro if (mtu < 2048 || mtu == 0xffff) 1270f48ad614SDennis Dalessandro mtu = 2048; 1271f48ad614SDennis Dalessandro if (dd->vld[15].mtu != mtu) { 1272f48ad614SDennis Dalessandro dd_dev_info(dd, 1273f48ad614SDennis Dalessandro "MTU change on vl 15 from %d to %d\n", 1274f48ad614SDennis Dalessandro dd->vld[15].mtu, mtu); 1275f48ad614SDennis Dalessandro dd->vld[15].mtu = mtu; 1276f48ad614SDennis Dalessandro call_set_mtu++; 1277f48ad614SDennis Dalessandro } 1278f48ad614SDennis Dalessandro if (call_set_mtu) 1279f48ad614SDennis Dalessandro set_mtu(ppd); 1280f48ad614SDennis Dalessandro 1281f48ad614SDennis Dalessandro /* Set operational VLs */ 1282f48ad614SDennis Dalessandro vls = pi->operational_vls & OPA_PI_MASK_OPERATIONAL_VL; 1283f48ad614SDennis Dalessandro if (vls) { 1284f48ad614SDennis Dalessandro if (vls > ppd->vls_supported) { 1285f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) VL's supported invalid %d\n", 1286f48ad614SDennis Dalessandro pi->operational_vls); 1287f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1288f48ad614SDennis Dalessandro } else { 1289f48ad614SDennis Dalessandro if (hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_OP_VLS, 1290f48ad614SDennis Dalessandro vls) == -EINVAL) 1291f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1292f48ad614SDennis Dalessandro } 1293f48ad614SDennis Dalessandro } 1294f48ad614SDennis Dalessandro 1295f48ad614SDennis Dalessandro if (pi->mkey_violations == 0) 1296f48ad614SDennis Dalessandro ibp->rvp.mkey_violations = 0; 1297f48ad614SDennis Dalessandro 1298f48ad614SDennis Dalessandro if (pi->pkey_violations == 0) 1299f48ad614SDennis Dalessandro ibp->rvp.pkey_violations = 0; 1300f48ad614SDennis Dalessandro 1301f48ad614SDennis Dalessandro if (pi->qkey_violations == 0) 1302f48ad614SDennis Dalessandro ibp->rvp.qkey_violations = 0; 1303f48ad614SDennis Dalessandro 1304f48ad614SDennis Dalessandro ibp->rvp.subnet_timeout = 1305f48ad614SDennis Dalessandro pi->clientrereg_subnettimeout & OPA_PI_MASK_SUBNET_TIMEOUT; 1306f48ad614SDennis Dalessandro 1307f48ad614SDennis Dalessandro crc_enabled = be16_to_cpu(pi->port_ltp_crc_mode); 1308f48ad614SDennis Dalessandro crc_enabled >>= 4; 1309f48ad614SDennis Dalessandro crc_enabled &= 0xf; 1310f48ad614SDennis Dalessandro 1311f48ad614SDennis Dalessandro if (crc_enabled != 0) 1312f48ad614SDennis Dalessandro ppd->port_crc_mode_enabled = port_ltp_to_cap(crc_enabled); 1313f48ad614SDennis Dalessandro 1314f48ad614SDennis Dalessandro ppd->is_active_optimize_enabled = 1315f48ad614SDennis Dalessandro !!(be16_to_cpu(pi->port_mode) 1316f48ad614SDennis Dalessandro & OPA_PI_MASK_PORT_ACTIVE_OPTOMIZE); 1317f48ad614SDennis Dalessandro 1318f48ad614SDennis Dalessandro ls_new = pi->port_states.portphysstate_portstate & 1319f48ad614SDennis Dalessandro OPA_PI_MASK_PORT_STATE; 1320f48ad614SDennis Dalessandro ps_new = (pi->port_states.portphysstate_portstate & 1321f48ad614SDennis Dalessandro OPA_PI_MASK_PORT_PHYSICAL_STATE) >> 4; 1322f48ad614SDennis Dalessandro 1323f48ad614SDennis Dalessandro if (ls_old == IB_PORT_INIT) { 1324f48ad614SDennis Dalessandro if (start_of_sm_config) { 1325f48ad614SDennis Dalessandro if (ls_new == ls_old || (ls_new == IB_PORT_ARMED)) 1326f48ad614SDennis Dalessandro ppd->is_sm_config_started = 1; 1327f48ad614SDennis Dalessandro } else if (ls_new == IB_PORT_ARMED) { 1328f48ad614SDennis Dalessandro if (ppd->is_sm_config_started == 0) 1329f48ad614SDennis Dalessandro invalid = 1; 1330f48ad614SDennis Dalessandro } 1331f48ad614SDennis Dalessandro } 1332f48ad614SDennis Dalessandro 1333f48ad614SDennis Dalessandro /* Handle CLIENT_REREGISTER event b/c SM asked us for it */ 1334f48ad614SDennis Dalessandro if (clientrereg) { 1335f48ad614SDennis Dalessandro event.event = IB_EVENT_CLIENT_REREGISTER; 1336f48ad614SDennis Dalessandro ib_dispatch_event(&event); 1337f48ad614SDennis Dalessandro } 1338f48ad614SDennis Dalessandro 1339f48ad614SDennis Dalessandro /* 1340f48ad614SDennis Dalessandro * Do the port state change now that the other link parameters 1341f48ad614SDennis Dalessandro * have been set. 1342f48ad614SDennis Dalessandro * Changing the port physical state only makes sense if the link 1343f48ad614SDennis Dalessandro * is down or is being set to down. 1344f48ad614SDennis Dalessandro */ 1345f48ad614SDennis Dalessandro 1346f48ad614SDennis Dalessandro ret = set_port_states(ppd, smp, ls_new, ps_new, invalid); 1347f48ad614SDennis Dalessandro if (ret) 1348f48ad614SDennis Dalessandro return ret; 1349f48ad614SDennis Dalessandro 1350f48ad614SDennis Dalessandro ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len); 1351f48ad614SDennis Dalessandro 1352f48ad614SDennis Dalessandro /* restore re-reg bit per o14-12.2.1 */ 1353f48ad614SDennis Dalessandro pi->clientrereg_subnettimeout |= clientrereg; 1354f48ad614SDennis Dalessandro 1355f48ad614SDennis Dalessandro /* 1356f48ad614SDennis Dalessandro * Apply the new link downgrade policy. This may result in a link 1357f48ad614SDennis Dalessandro * bounce. Do this after everything else so things are settled. 1358f48ad614SDennis Dalessandro * Possible problem: if setting the port state above fails, then 1359f48ad614SDennis Dalessandro * the policy change is not applied. 1360f48ad614SDennis Dalessandro */ 1361f48ad614SDennis Dalessandro if (call_link_downgrade_policy) 1362f48ad614SDennis Dalessandro apply_link_downgrade_policy(ppd, 0); 1363f48ad614SDennis Dalessandro 1364f48ad614SDennis Dalessandro return ret; 1365f48ad614SDennis Dalessandro 1366f48ad614SDennis Dalessandro get_only: 1367f48ad614SDennis Dalessandro return __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len); 1368f48ad614SDennis Dalessandro } 1369f48ad614SDennis Dalessandro 1370f48ad614SDennis Dalessandro /** 1371f48ad614SDennis Dalessandro * set_pkeys - set the PKEY table for ctxt 0 1372f48ad614SDennis Dalessandro * @dd: the hfi1_ib device 1373f48ad614SDennis Dalessandro * @port: the IB port number 1374f48ad614SDennis Dalessandro * @pkeys: the PKEY table 1375f48ad614SDennis Dalessandro */ 1376f48ad614SDennis Dalessandro static int set_pkeys(struct hfi1_devdata *dd, u8 port, u16 *pkeys) 1377f48ad614SDennis Dalessandro { 1378f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1379f48ad614SDennis Dalessandro int i; 1380f48ad614SDennis Dalessandro int changed = 0; 1381f48ad614SDennis Dalessandro int update_includes_mgmt_partition = 0; 1382f48ad614SDennis Dalessandro 1383f48ad614SDennis Dalessandro /* 1384f48ad614SDennis Dalessandro * IB port one/two always maps to context zero/one, 1385f48ad614SDennis Dalessandro * always a kernel context, no locking needed 1386f48ad614SDennis Dalessandro * If we get here with ppd setup, no need to check 1387f48ad614SDennis Dalessandro * that rcd is valid. 1388f48ad614SDennis Dalessandro */ 1389f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1390f48ad614SDennis Dalessandro /* 1391f48ad614SDennis Dalessandro * If the update does not include the management pkey, don't do it. 1392f48ad614SDennis Dalessandro */ 1393f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) { 1394f48ad614SDennis Dalessandro if (pkeys[i] == LIM_MGMT_P_KEY) { 1395f48ad614SDennis Dalessandro update_includes_mgmt_partition = 1; 1396f48ad614SDennis Dalessandro break; 1397f48ad614SDennis Dalessandro } 1398f48ad614SDennis Dalessandro } 1399f48ad614SDennis Dalessandro 1400f48ad614SDennis Dalessandro if (!update_includes_mgmt_partition) 1401f48ad614SDennis Dalessandro return 1; 1402f48ad614SDennis Dalessandro 1403f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) { 1404f48ad614SDennis Dalessandro u16 key = pkeys[i]; 1405f48ad614SDennis Dalessandro u16 okey = ppd->pkeys[i]; 1406f48ad614SDennis Dalessandro 1407f48ad614SDennis Dalessandro if (key == okey) 1408f48ad614SDennis Dalessandro continue; 1409f48ad614SDennis Dalessandro /* 1410f48ad614SDennis Dalessandro * The SM gives us the complete PKey table. We have 1411f48ad614SDennis Dalessandro * to ensure that we put the PKeys in the matching 1412f48ad614SDennis Dalessandro * slots. 1413f48ad614SDennis Dalessandro */ 1414f48ad614SDennis Dalessandro ppd->pkeys[i] = key; 1415f48ad614SDennis Dalessandro changed = 1; 1416f48ad614SDennis Dalessandro } 1417f48ad614SDennis Dalessandro 1418f48ad614SDennis Dalessandro if (changed) { 1419f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_PKEYS, 0); 142034d351f8SSebastian Sanchez hfi1_event_pkey_change(dd, port); 1421f48ad614SDennis Dalessandro } 142234d351f8SSebastian Sanchez 1423f48ad614SDennis Dalessandro return 0; 1424f48ad614SDennis Dalessandro } 1425f48ad614SDennis Dalessandro 1426f48ad614SDennis Dalessandro static int __subn_set_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data, 1427f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1428f48ad614SDennis Dalessandro u32 *resp_len) 1429f48ad614SDennis Dalessandro { 1430f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1431f48ad614SDennis Dalessandro u32 n_blocks_sent = OPA_AM_NBLK(am); 1432f48ad614SDennis Dalessandro u32 start_block = am & 0x7ff; 1433f48ad614SDennis Dalessandro u16 *p = (u16 *)data; 1434f48ad614SDennis Dalessandro __be16 *q = (__be16 *)data; 1435f48ad614SDennis Dalessandro int i; 1436f48ad614SDennis Dalessandro u16 n_blocks_avail; 1437f48ad614SDennis Dalessandro unsigned npkeys = hfi1_get_npkeys(dd); 1438f48ad614SDennis Dalessandro 1439f48ad614SDennis Dalessandro if (n_blocks_sent == 0) { 1440f48ad614SDennis Dalessandro pr_warn("OPA Get PKey AM Invalid : P = %d; B = 0x%x; N = 0x%x\n", 1441f48ad614SDennis Dalessandro port, start_block, n_blocks_sent); 1442f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1443f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1444f48ad614SDennis Dalessandro } 1445f48ad614SDennis Dalessandro 1446f48ad614SDennis Dalessandro n_blocks_avail = (u16)(npkeys / OPA_PARTITION_TABLE_BLK_SIZE) + 1; 1447f48ad614SDennis Dalessandro 1448f48ad614SDennis Dalessandro if (start_block + n_blocks_sent > n_blocks_avail || 1449f48ad614SDennis Dalessandro n_blocks_sent > OPA_NUM_PKEY_BLOCKS_PER_SMP) { 1450f48ad614SDennis Dalessandro pr_warn("OPA Set PKey AM Invalid : s 0x%x; req 0x%x; avail 0x%x; blk/smp 0x%lx\n", 1451f48ad614SDennis Dalessandro start_block, n_blocks_sent, n_blocks_avail, 1452f48ad614SDennis Dalessandro OPA_NUM_PKEY_BLOCKS_PER_SMP); 1453f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1454f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1455f48ad614SDennis Dalessandro } 1456f48ad614SDennis Dalessandro 1457f48ad614SDennis Dalessandro for (i = 0; i < n_blocks_sent * OPA_PARTITION_TABLE_BLK_SIZE; i++) 1458f48ad614SDennis Dalessandro p[i] = be16_to_cpu(q[i]); 1459f48ad614SDennis Dalessandro 1460f48ad614SDennis Dalessandro if (start_block == 0 && set_pkeys(dd, port, p) != 0) { 1461f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1462f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1463f48ad614SDennis Dalessandro } 1464f48ad614SDennis Dalessandro 1465f48ad614SDennis Dalessandro return __subn_get_opa_pkeytable(smp, am, data, ibdev, port, resp_len); 1466f48ad614SDennis Dalessandro } 1467f48ad614SDennis Dalessandro 1468f48ad614SDennis Dalessandro static int get_sc2vlt_tables(struct hfi1_devdata *dd, void *data) 1469f48ad614SDennis Dalessandro { 1470f48ad614SDennis Dalessandro u64 *val = data; 1471f48ad614SDennis Dalessandro 1472f48ad614SDennis Dalessandro *val++ = read_csr(dd, SEND_SC2VLT0); 1473f48ad614SDennis Dalessandro *val++ = read_csr(dd, SEND_SC2VLT1); 1474f48ad614SDennis Dalessandro *val++ = read_csr(dd, SEND_SC2VLT2); 1475f48ad614SDennis Dalessandro *val++ = read_csr(dd, SEND_SC2VLT3); 1476f48ad614SDennis Dalessandro return 0; 1477f48ad614SDennis Dalessandro } 1478f48ad614SDennis Dalessandro 1479f48ad614SDennis Dalessandro #define ILLEGAL_VL 12 1480f48ad614SDennis Dalessandro /* 1481f48ad614SDennis Dalessandro * filter_sc2vlt changes mappings to VL15 to ILLEGAL_VL (except 1482f48ad614SDennis Dalessandro * for SC15, which must map to VL15). If we don't remap things this 1483f48ad614SDennis Dalessandro * way it is possible for VL15 counters to increment when we try to 1484f48ad614SDennis Dalessandro * send on a SC which is mapped to an invalid VL. 1485f48ad614SDennis Dalessandro */ 1486f48ad614SDennis Dalessandro static void filter_sc2vlt(void *data) 1487f48ad614SDennis Dalessandro { 1488f48ad614SDennis Dalessandro int i; 1489f48ad614SDennis Dalessandro u8 *pd = data; 1490f48ad614SDennis Dalessandro 1491f48ad614SDennis Dalessandro for (i = 0; i < OPA_MAX_SCS; i++) { 1492f48ad614SDennis Dalessandro if (i == 15) 1493f48ad614SDennis Dalessandro continue; 1494f48ad614SDennis Dalessandro if ((pd[i] & 0x1f) == 0xf) 1495f48ad614SDennis Dalessandro pd[i] = ILLEGAL_VL; 1496f48ad614SDennis Dalessandro } 1497f48ad614SDennis Dalessandro } 1498f48ad614SDennis Dalessandro 1499f48ad614SDennis Dalessandro static int set_sc2vlt_tables(struct hfi1_devdata *dd, void *data) 1500f48ad614SDennis Dalessandro { 1501f48ad614SDennis Dalessandro u64 *val = data; 1502f48ad614SDennis Dalessandro 1503f48ad614SDennis Dalessandro filter_sc2vlt(data); 1504f48ad614SDennis Dalessandro 1505f48ad614SDennis Dalessandro write_csr(dd, SEND_SC2VLT0, *val++); 1506f48ad614SDennis Dalessandro write_csr(dd, SEND_SC2VLT1, *val++); 1507f48ad614SDennis Dalessandro write_csr(dd, SEND_SC2VLT2, *val++); 1508f48ad614SDennis Dalessandro write_csr(dd, SEND_SC2VLT3, *val++); 1509f48ad614SDennis Dalessandro write_seqlock_irq(&dd->sc2vl_lock); 1510f48ad614SDennis Dalessandro memcpy(dd->sc2vl, data, sizeof(dd->sc2vl)); 1511f48ad614SDennis Dalessandro write_sequnlock_irq(&dd->sc2vl_lock); 1512f48ad614SDennis Dalessandro return 0; 1513f48ad614SDennis Dalessandro } 1514f48ad614SDennis Dalessandro 1515f48ad614SDennis Dalessandro static int __subn_get_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data, 1516f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1517f48ad614SDennis Dalessandro u32 *resp_len) 1518f48ad614SDennis Dalessandro { 1519f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 1520f48ad614SDennis Dalessandro u8 *p = data; 1521f48ad614SDennis Dalessandro size_t size = ARRAY_SIZE(ibp->sl_to_sc); /* == 32 */ 1522f48ad614SDennis Dalessandro unsigned i; 1523f48ad614SDennis Dalessandro 1524f48ad614SDennis Dalessandro if (am) { 1525f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1526f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1527f48ad614SDennis Dalessandro } 1528f48ad614SDennis Dalessandro 1529f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ibp->sl_to_sc); i++) 1530f48ad614SDennis Dalessandro *p++ = ibp->sl_to_sc[i]; 1531f48ad614SDennis Dalessandro 1532f48ad614SDennis Dalessandro if (resp_len) 1533f48ad614SDennis Dalessandro *resp_len += size; 1534f48ad614SDennis Dalessandro 1535f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1536f48ad614SDennis Dalessandro } 1537f48ad614SDennis Dalessandro 1538f48ad614SDennis Dalessandro static int __subn_set_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data, 1539f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1540f48ad614SDennis Dalessandro u32 *resp_len) 1541f48ad614SDennis Dalessandro { 1542f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 1543f48ad614SDennis Dalessandro u8 *p = data; 1544f48ad614SDennis Dalessandro int i; 1545f48ad614SDennis Dalessandro u8 sc; 1546f48ad614SDennis Dalessandro 1547f48ad614SDennis Dalessandro if (am) { 1548f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1549f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1550f48ad614SDennis Dalessandro } 1551f48ad614SDennis Dalessandro 1552f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ibp->sl_to_sc); i++) { 1553f48ad614SDennis Dalessandro sc = *p++; 1554f48ad614SDennis Dalessandro if (ibp->sl_to_sc[i] != sc) { 1555f48ad614SDennis Dalessandro ibp->sl_to_sc[i] = sc; 1556f48ad614SDennis Dalessandro 1557f48ad614SDennis Dalessandro /* Put all stale qps into error state */ 1558f48ad614SDennis Dalessandro hfi1_error_port_qps(ibp, i); 1559f48ad614SDennis Dalessandro } 1560f48ad614SDennis Dalessandro } 1561f48ad614SDennis Dalessandro 1562f48ad614SDennis Dalessandro return __subn_get_opa_sl_to_sc(smp, am, data, ibdev, port, resp_len); 1563f48ad614SDennis Dalessandro } 1564f48ad614SDennis Dalessandro 1565f48ad614SDennis Dalessandro static int __subn_get_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data, 1566f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1567f48ad614SDennis Dalessandro u32 *resp_len) 1568f48ad614SDennis Dalessandro { 1569f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 1570f48ad614SDennis Dalessandro u8 *p = data; 1571f48ad614SDennis Dalessandro size_t size = ARRAY_SIZE(ibp->sc_to_sl); /* == 32 */ 1572f48ad614SDennis Dalessandro unsigned i; 1573f48ad614SDennis Dalessandro 1574f48ad614SDennis Dalessandro if (am) { 1575f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1576f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1577f48ad614SDennis Dalessandro } 1578f48ad614SDennis Dalessandro 1579f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ibp->sc_to_sl); i++) 1580f48ad614SDennis Dalessandro *p++ = ibp->sc_to_sl[i]; 1581f48ad614SDennis Dalessandro 1582f48ad614SDennis Dalessandro if (resp_len) 1583f48ad614SDennis Dalessandro *resp_len += size; 1584f48ad614SDennis Dalessandro 1585f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1586f48ad614SDennis Dalessandro } 1587f48ad614SDennis Dalessandro 1588f48ad614SDennis Dalessandro static int __subn_set_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data, 1589f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1590f48ad614SDennis Dalessandro u32 *resp_len) 1591f48ad614SDennis Dalessandro { 1592f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 1593f48ad614SDennis Dalessandro u8 *p = data; 1594f48ad614SDennis Dalessandro int i; 1595f48ad614SDennis Dalessandro 1596f48ad614SDennis Dalessandro if (am) { 1597f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1598f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1599f48ad614SDennis Dalessandro } 1600f48ad614SDennis Dalessandro 1601f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ibp->sc_to_sl); i++) 1602f48ad614SDennis Dalessandro ibp->sc_to_sl[i] = *p++; 1603f48ad614SDennis Dalessandro 1604f48ad614SDennis Dalessandro return __subn_get_opa_sc_to_sl(smp, am, data, ibdev, port, resp_len); 1605f48ad614SDennis Dalessandro } 1606f48ad614SDennis Dalessandro 1607f48ad614SDennis Dalessandro static int __subn_get_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data, 1608f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1609f48ad614SDennis Dalessandro u32 *resp_len) 1610f48ad614SDennis Dalessandro { 1611f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NBLK(am); 1612f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1613f48ad614SDennis Dalessandro void *vp = (void *)data; 1614f48ad614SDennis Dalessandro size_t size = 4 * sizeof(u64); 1615f48ad614SDennis Dalessandro 1616f48ad614SDennis Dalessandro if (n_blocks != 1) { 1617f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1618f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1619f48ad614SDennis Dalessandro } 1620f48ad614SDennis Dalessandro 1621f48ad614SDennis Dalessandro get_sc2vlt_tables(dd, vp); 1622f48ad614SDennis Dalessandro 1623f48ad614SDennis Dalessandro if (resp_len) 1624f48ad614SDennis Dalessandro *resp_len += size; 1625f48ad614SDennis Dalessandro 1626f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1627f48ad614SDennis Dalessandro } 1628f48ad614SDennis Dalessandro 1629f48ad614SDennis Dalessandro static int __subn_set_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data, 1630f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1631f48ad614SDennis Dalessandro u32 *resp_len) 1632f48ad614SDennis Dalessandro { 1633f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NBLK(am); 1634f48ad614SDennis Dalessandro int async_update = OPA_AM_ASYNC(am); 1635f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1636f48ad614SDennis Dalessandro void *vp = (void *)data; 1637f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1638f48ad614SDennis Dalessandro int lstate; 1639f48ad614SDennis Dalessandro 1640f48ad614SDennis Dalessandro if (n_blocks != 1 || async_update) { 1641f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1642f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1643f48ad614SDennis Dalessandro } 1644f48ad614SDennis Dalessandro 1645f48ad614SDennis Dalessandro /* IB numbers ports from 1, hw from 0 */ 1646f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1647f48ad614SDennis Dalessandro lstate = driver_lstate(ppd); 1648f48ad614SDennis Dalessandro /* 1649f48ad614SDennis Dalessandro * it's known that async_update is 0 by this point, but include 1650f48ad614SDennis Dalessandro * the explicit check for clarity 1651f48ad614SDennis Dalessandro */ 1652f48ad614SDennis Dalessandro if (!async_update && 1653f48ad614SDennis Dalessandro (lstate == IB_PORT_ARMED || lstate == IB_PORT_ACTIVE)) { 1654f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1655f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1656f48ad614SDennis Dalessandro } 1657f48ad614SDennis Dalessandro 1658f48ad614SDennis Dalessandro set_sc2vlt_tables(dd, vp); 1659f48ad614SDennis Dalessandro 1660f48ad614SDennis Dalessandro return __subn_get_opa_sc_to_vlt(smp, am, data, ibdev, port, resp_len); 1661f48ad614SDennis Dalessandro } 1662f48ad614SDennis Dalessandro 1663f48ad614SDennis Dalessandro static int __subn_get_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data, 1664f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1665f48ad614SDennis Dalessandro u32 *resp_len) 1666f48ad614SDennis Dalessandro { 1667f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NPORT(am); 1668f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1669f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1670f48ad614SDennis Dalessandro void *vp = (void *)data; 1671f48ad614SDennis Dalessandro int size; 1672f48ad614SDennis Dalessandro 1673f48ad614SDennis Dalessandro if (n_blocks != 1) { 1674f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1675f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1676f48ad614SDennis Dalessandro } 1677f48ad614SDennis Dalessandro 1678f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1679f48ad614SDennis Dalessandro 1680f48ad614SDennis Dalessandro size = fm_get_table(ppd, FM_TBL_SC2VLNT, vp); 1681f48ad614SDennis Dalessandro 1682f48ad614SDennis Dalessandro if (resp_len) 1683f48ad614SDennis Dalessandro *resp_len += size; 1684f48ad614SDennis Dalessandro 1685f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1686f48ad614SDennis Dalessandro } 1687f48ad614SDennis Dalessandro 1688f48ad614SDennis Dalessandro static int __subn_set_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data, 1689f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1690f48ad614SDennis Dalessandro u32 *resp_len) 1691f48ad614SDennis Dalessandro { 1692f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NPORT(am); 1693f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1694f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1695f48ad614SDennis Dalessandro void *vp = (void *)data; 1696f48ad614SDennis Dalessandro int lstate; 1697f48ad614SDennis Dalessandro 1698f48ad614SDennis Dalessandro if (n_blocks != 1) { 1699f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1700f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1701f48ad614SDennis Dalessandro } 1702f48ad614SDennis Dalessandro 1703f48ad614SDennis Dalessandro /* IB numbers ports from 1, hw from 0 */ 1704f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1705f48ad614SDennis Dalessandro lstate = driver_lstate(ppd); 1706f48ad614SDennis Dalessandro if (lstate == IB_PORT_ARMED || lstate == IB_PORT_ACTIVE) { 1707f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1708f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1709f48ad614SDennis Dalessandro } 1710f48ad614SDennis Dalessandro 1711f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1712f48ad614SDennis Dalessandro 1713f48ad614SDennis Dalessandro fm_set_table(ppd, FM_TBL_SC2VLNT, vp); 1714f48ad614SDennis Dalessandro 1715f48ad614SDennis Dalessandro return __subn_get_opa_sc_to_vlnt(smp, am, data, ibdev, port, 1716f48ad614SDennis Dalessandro resp_len); 1717f48ad614SDennis Dalessandro } 1718f48ad614SDennis Dalessandro 1719f48ad614SDennis Dalessandro static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data, 1720f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1721f48ad614SDennis Dalessandro u32 *resp_len) 1722f48ad614SDennis Dalessandro { 1723f48ad614SDennis Dalessandro u32 nports = OPA_AM_NPORT(am); 1724f48ad614SDennis Dalessandro u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); 1725f48ad614SDennis Dalessandro u32 lstate; 1726f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 1727f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1728f48ad614SDennis Dalessandro struct opa_port_state_info *psi = (struct opa_port_state_info *)data; 1729f48ad614SDennis Dalessandro 1730f48ad614SDennis Dalessandro if (nports != 1) { 1731f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1732f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1733f48ad614SDennis Dalessandro } 1734f48ad614SDennis Dalessandro 1735f48ad614SDennis Dalessandro ibp = to_iport(ibdev, port); 1736f48ad614SDennis Dalessandro ppd = ppd_from_ibp(ibp); 1737f48ad614SDennis Dalessandro 1738f48ad614SDennis Dalessandro lstate = driver_lstate(ppd); 1739f48ad614SDennis Dalessandro 1740f48ad614SDennis Dalessandro if (start_of_sm_config && (lstate == IB_PORT_INIT)) 1741f48ad614SDennis Dalessandro ppd->is_sm_config_started = 1; 1742f48ad614SDennis Dalessandro 1743f48ad614SDennis Dalessandro psi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4; 1744f48ad614SDennis Dalessandro psi->port_states.ledenable_offlinereason |= 1745f48ad614SDennis Dalessandro ppd->is_sm_config_started << 5; 1746f48ad614SDennis Dalessandro psi->port_states.ledenable_offlinereason |= 1747f48ad614SDennis Dalessandro ppd->offline_disabled_reason; 1748f48ad614SDennis Dalessandro 1749f48ad614SDennis Dalessandro psi->port_states.portphysstate_portstate = 1750f48ad614SDennis Dalessandro (hfi1_ibphys_portstate(ppd) << 4) | (lstate & 0xf); 1751f48ad614SDennis Dalessandro psi->link_width_downgrade_tx_active = 1752f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_tx_active); 1753f48ad614SDennis Dalessandro psi->link_width_downgrade_rx_active = 1754f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_rx_active); 1755f48ad614SDennis Dalessandro if (resp_len) 1756f48ad614SDennis Dalessandro *resp_len += sizeof(struct opa_port_state_info); 1757f48ad614SDennis Dalessandro 1758f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1759f48ad614SDennis Dalessandro } 1760f48ad614SDennis Dalessandro 1761f48ad614SDennis Dalessandro static int __subn_set_opa_psi(struct opa_smp *smp, u32 am, u8 *data, 1762f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1763f48ad614SDennis Dalessandro u32 *resp_len) 1764f48ad614SDennis Dalessandro { 1765f48ad614SDennis Dalessandro u32 nports = OPA_AM_NPORT(am); 1766f48ad614SDennis Dalessandro u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); 1767f48ad614SDennis Dalessandro u32 ls_old; 1768f48ad614SDennis Dalessandro u8 ls_new, ps_new; 1769f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 1770f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1771f48ad614SDennis Dalessandro struct opa_port_state_info *psi = (struct opa_port_state_info *)data; 1772f48ad614SDennis Dalessandro int ret, invalid = 0; 1773f48ad614SDennis Dalessandro 1774f48ad614SDennis Dalessandro if (nports != 1) { 1775f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1776f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1777f48ad614SDennis Dalessandro } 1778f48ad614SDennis Dalessandro 1779f48ad614SDennis Dalessandro ibp = to_iport(ibdev, port); 1780f48ad614SDennis Dalessandro ppd = ppd_from_ibp(ibp); 1781f48ad614SDennis Dalessandro 1782f48ad614SDennis Dalessandro ls_old = driver_lstate(ppd); 1783f48ad614SDennis Dalessandro 1784f48ad614SDennis Dalessandro ls_new = port_states_to_logical_state(&psi->port_states); 1785f48ad614SDennis Dalessandro ps_new = port_states_to_phys_state(&psi->port_states); 1786f48ad614SDennis Dalessandro 1787f48ad614SDennis Dalessandro if (ls_old == IB_PORT_INIT) { 1788f48ad614SDennis Dalessandro if (start_of_sm_config) { 1789f48ad614SDennis Dalessandro if (ls_new == ls_old || (ls_new == IB_PORT_ARMED)) 1790f48ad614SDennis Dalessandro ppd->is_sm_config_started = 1; 1791f48ad614SDennis Dalessandro } else if (ls_new == IB_PORT_ARMED) { 1792f48ad614SDennis Dalessandro if (ppd->is_sm_config_started == 0) 1793f48ad614SDennis Dalessandro invalid = 1; 1794f48ad614SDennis Dalessandro } 1795f48ad614SDennis Dalessandro } 1796f48ad614SDennis Dalessandro 1797f48ad614SDennis Dalessandro ret = set_port_states(ppd, smp, ls_new, ps_new, invalid); 1798f48ad614SDennis Dalessandro if (ret) 1799f48ad614SDennis Dalessandro return ret; 1800f48ad614SDennis Dalessandro 1801f48ad614SDennis Dalessandro if (invalid) 1802f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1803f48ad614SDennis Dalessandro 1804f48ad614SDennis Dalessandro return __subn_get_opa_psi(smp, am, data, ibdev, port, resp_len); 1805f48ad614SDennis Dalessandro } 1806f48ad614SDennis Dalessandro 1807f48ad614SDennis Dalessandro static int __subn_get_opa_cable_info(struct opa_smp *smp, u32 am, u8 *data, 1808f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1809f48ad614SDennis Dalessandro u32 *resp_len) 1810f48ad614SDennis Dalessandro { 1811f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1812f48ad614SDennis Dalessandro u32 addr = OPA_AM_CI_ADDR(am); 1813f48ad614SDennis Dalessandro u32 len = OPA_AM_CI_LEN(am) + 1; 1814f48ad614SDennis Dalessandro int ret; 1815f48ad614SDennis Dalessandro 1816f29a08dcSEaswar Hariharan if (dd->pport->port_type != PORT_TYPE_QSFP) { 1817f29a08dcSEaswar Hariharan smp->status |= IB_SMP_INVALID_FIELD; 1818f29a08dcSEaswar Hariharan return reply((struct ib_mad_hdr *)smp); 1819f29a08dcSEaswar Hariharan } 1820f29a08dcSEaswar Hariharan 1821f48ad614SDennis Dalessandro #define __CI_PAGE_SIZE BIT(7) /* 128 bytes */ 1822f48ad614SDennis Dalessandro #define __CI_PAGE_MASK ~(__CI_PAGE_SIZE - 1) 1823f48ad614SDennis Dalessandro #define __CI_PAGE_NUM(a) ((a) & __CI_PAGE_MASK) 1824f48ad614SDennis Dalessandro 1825f48ad614SDennis Dalessandro /* 1826f48ad614SDennis Dalessandro * check that addr is within spec, and 1827f48ad614SDennis Dalessandro * addr and (addr + len - 1) are on the same "page" 1828f48ad614SDennis Dalessandro */ 1829f48ad614SDennis Dalessandro if (addr >= 4096 || 1830f48ad614SDennis Dalessandro (__CI_PAGE_NUM(addr) != __CI_PAGE_NUM(addr + len - 1))) { 1831f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1832f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1833f48ad614SDennis Dalessandro } 1834f48ad614SDennis Dalessandro 1835f48ad614SDennis Dalessandro ret = get_cable_info(dd, port, addr, len, data); 1836f48ad614SDennis Dalessandro 1837f48ad614SDennis Dalessandro if (ret == -ENODEV) { 1838f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 1839f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1840f48ad614SDennis Dalessandro } 1841f48ad614SDennis Dalessandro 1842f48ad614SDennis Dalessandro /* The address range for the CableInfo SMA query is wider than the 1843f48ad614SDennis Dalessandro * memory available on the QSFP cable. We want to return a valid 1844f48ad614SDennis Dalessandro * response, albeit zeroed out, for address ranges beyond available 1845f48ad614SDennis Dalessandro * memory but that are within the CableInfo query spec 1846f48ad614SDennis Dalessandro */ 1847f48ad614SDennis Dalessandro if (ret < 0 && ret != -ERANGE) { 1848f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1849f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1850f48ad614SDennis Dalessandro } 1851f48ad614SDennis Dalessandro 1852f48ad614SDennis Dalessandro if (resp_len) 1853f48ad614SDennis Dalessandro *resp_len += len; 1854f48ad614SDennis Dalessandro 1855f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1856f48ad614SDennis Dalessandro } 1857f48ad614SDennis Dalessandro 1858f48ad614SDennis Dalessandro static int __subn_get_opa_bct(struct opa_smp *smp, u32 am, u8 *data, 1859f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, u32 *resp_len) 1860f48ad614SDennis Dalessandro { 1861f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 1862f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1863f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1864f48ad614SDennis Dalessandro struct buffer_control *p = (struct buffer_control *)data; 1865f48ad614SDennis Dalessandro int size; 1866f48ad614SDennis Dalessandro 1867f48ad614SDennis Dalessandro if (num_ports != 1) { 1868f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1869f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1870f48ad614SDennis Dalessandro } 1871f48ad614SDennis Dalessandro 1872f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1873f48ad614SDennis Dalessandro size = fm_get_table(ppd, FM_TBL_BUFFER_CONTROL, p); 1874f48ad614SDennis Dalessandro trace_bct_get(dd, p); 1875f48ad614SDennis Dalessandro if (resp_len) 1876f48ad614SDennis Dalessandro *resp_len += size; 1877f48ad614SDennis Dalessandro 1878f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1879f48ad614SDennis Dalessandro } 1880f48ad614SDennis Dalessandro 1881f48ad614SDennis Dalessandro static int __subn_set_opa_bct(struct opa_smp *smp, u32 am, u8 *data, 1882f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, u32 *resp_len) 1883f48ad614SDennis Dalessandro { 1884f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 1885f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1886f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1887f48ad614SDennis Dalessandro struct buffer_control *p = (struct buffer_control *)data; 1888f48ad614SDennis Dalessandro 1889f48ad614SDennis Dalessandro if (num_ports != 1) { 1890f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1891f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1892f48ad614SDennis Dalessandro } 1893f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1894f48ad614SDennis Dalessandro trace_bct_set(dd, p); 1895f48ad614SDennis Dalessandro if (fm_set_table(ppd, FM_TBL_BUFFER_CONTROL, p) < 0) { 1896f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1897f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1898f48ad614SDennis Dalessandro } 1899f48ad614SDennis Dalessandro 1900f48ad614SDennis Dalessandro return __subn_get_opa_bct(smp, am, data, ibdev, port, resp_len); 1901f48ad614SDennis Dalessandro } 1902f48ad614SDennis Dalessandro 1903f48ad614SDennis Dalessandro static int __subn_get_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data, 1904f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1905f48ad614SDennis Dalessandro u32 *resp_len) 1906f48ad614SDennis Dalessandro { 1907f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port)); 1908f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 1909f48ad614SDennis Dalessandro u8 section = (am & 0x00ff0000) >> 16; 1910f48ad614SDennis Dalessandro u8 *p = data; 1911f48ad614SDennis Dalessandro int size = 0; 1912f48ad614SDennis Dalessandro 1913f48ad614SDennis Dalessandro if (num_ports != 1) { 1914f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1915f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1916f48ad614SDennis Dalessandro } 1917f48ad614SDennis Dalessandro 1918f48ad614SDennis Dalessandro switch (section) { 1919f48ad614SDennis Dalessandro case OPA_VLARB_LOW_ELEMENTS: 1920f48ad614SDennis Dalessandro size = fm_get_table(ppd, FM_TBL_VL_LOW_ARB, p); 1921f48ad614SDennis Dalessandro break; 1922f48ad614SDennis Dalessandro case OPA_VLARB_HIGH_ELEMENTS: 1923f48ad614SDennis Dalessandro size = fm_get_table(ppd, FM_TBL_VL_HIGH_ARB, p); 1924f48ad614SDennis Dalessandro break; 1925f48ad614SDennis Dalessandro case OPA_VLARB_PREEMPT_ELEMENTS: 1926f48ad614SDennis Dalessandro size = fm_get_table(ppd, FM_TBL_VL_PREEMPT_ELEMS, p); 1927f48ad614SDennis Dalessandro break; 1928f48ad614SDennis Dalessandro case OPA_VLARB_PREEMPT_MATRIX: 1929f48ad614SDennis Dalessandro size = fm_get_table(ppd, FM_TBL_VL_PREEMPT_MATRIX, p); 1930f48ad614SDennis Dalessandro break; 1931f48ad614SDennis Dalessandro default: 1932f48ad614SDennis Dalessandro pr_warn("OPA SubnGet(VL Arb) AM Invalid : 0x%x\n", 1933f48ad614SDennis Dalessandro be32_to_cpu(smp->attr_mod)); 1934f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1935f48ad614SDennis Dalessandro break; 1936f48ad614SDennis Dalessandro } 1937f48ad614SDennis Dalessandro 1938f48ad614SDennis Dalessandro if (size > 0 && resp_len) 1939f48ad614SDennis Dalessandro *resp_len += size; 1940f48ad614SDennis Dalessandro 1941f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1942f48ad614SDennis Dalessandro } 1943f48ad614SDennis Dalessandro 1944f48ad614SDennis Dalessandro static int __subn_set_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data, 1945f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1946f48ad614SDennis Dalessandro u32 *resp_len) 1947f48ad614SDennis Dalessandro { 1948f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port)); 1949f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 1950f48ad614SDennis Dalessandro u8 section = (am & 0x00ff0000) >> 16; 1951f48ad614SDennis Dalessandro u8 *p = data; 1952f48ad614SDennis Dalessandro 1953f48ad614SDennis Dalessandro if (num_ports != 1) { 1954f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1955f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1956f48ad614SDennis Dalessandro } 1957f48ad614SDennis Dalessandro 1958f48ad614SDennis Dalessandro switch (section) { 1959f48ad614SDennis Dalessandro case OPA_VLARB_LOW_ELEMENTS: 1960f48ad614SDennis Dalessandro (void)fm_set_table(ppd, FM_TBL_VL_LOW_ARB, p); 1961f48ad614SDennis Dalessandro break; 1962f48ad614SDennis Dalessandro case OPA_VLARB_HIGH_ELEMENTS: 1963f48ad614SDennis Dalessandro (void)fm_set_table(ppd, FM_TBL_VL_HIGH_ARB, p); 1964f48ad614SDennis Dalessandro break; 1965f48ad614SDennis Dalessandro /* 1966f48ad614SDennis Dalessandro * neither OPA_VLARB_PREEMPT_ELEMENTS, or OPA_VLARB_PREEMPT_MATRIX 1967f48ad614SDennis Dalessandro * can be changed from the default values 1968f48ad614SDennis Dalessandro */ 1969f48ad614SDennis Dalessandro case OPA_VLARB_PREEMPT_ELEMENTS: 1970f48ad614SDennis Dalessandro /* FALLTHROUGH */ 1971f48ad614SDennis Dalessandro case OPA_VLARB_PREEMPT_MATRIX: 1972f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 1973f48ad614SDennis Dalessandro break; 1974f48ad614SDennis Dalessandro default: 1975f48ad614SDennis Dalessandro pr_warn("OPA SubnSet(VL Arb) AM Invalid : 0x%x\n", 1976f48ad614SDennis Dalessandro be32_to_cpu(smp->attr_mod)); 1977f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1978f48ad614SDennis Dalessandro break; 1979f48ad614SDennis Dalessandro } 1980f48ad614SDennis Dalessandro 1981f48ad614SDennis Dalessandro return __subn_get_opa_vl_arb(smp, am, data, ibdev, port, resp_len); 1982f48ad614SDennis Dalessandro } 1983f48ad614SDennis Dalessandro 1984f48ad614SDennis Dalessandro struct opa_pma_mad { 1985f48ad614SDennis Dalessandro struct ib_mad_hdr mad_hdr; 1986f48ad614SDennis Dalessandro u8 data[2024]; 1987f48ad614SDennis Dalessandro } __packed; 1988f48ad614SDennis Dalessandro 1989f48ad614SDennis Dalessandro struct opa_class_port_info { 1990f48ad614SDennis Dalessandro u8 base_version; 1991f48ad614SDennis Dalessandro u8 class_version; 1992f48ad614SDennis Dalessandro __be16 cap_mask; 1993f48ad614SDennis Dalessandro __be32 cap_mask2_resp_time; 1994f48ad614SDennis Dalessandro 1995f48ad614SDennis Dalessandro u8 redirect_gid[16]; 1996f48ad614SDennis Dalessandro __be32 redirect_tc_fl; 1997f48ad614SDennis Dalessandro __be32 redirect_lid; 1998f48ad614SDennis Dalessandro __be32 redirect_sl_qp; 1999f48ad614SDennis Dalessandro __be32 redirect_qkey; 2000f48ad614SDennis Dalessandro 2001f48ad614SDennis Dalessandro u8 trap_gid[16]; 2002f48ad614SDennis Dalessandro __be32 trap_tc_fl; 2003f48ad614SDennis Dalessandro __be32 trap_lid; 2004f48ad614SDennis Dalessandro __be32 trap_hl_qp; 2005f48ad614SDennis Dalessandro __be32 trap_qkey; 2006f48ad614SDennis Dalessandro 2007f48ad614SDennis Dalessandro __be16 trap_pkey; 2008f48ad614SDennis Dalessandro __be16 redirect_pkey; 2009f48ad614SDennis Dalessandro 2010f48ad614SDennis Dalessandro u8 trap_sl_rsvd; 2011f48ad614SDennis Dalessandro u8 reserved[3]; 2012f48ad614SDennis Dalessandro } __packed; 2013f48ad614SDennis Dalessandro 2014f48ad614SDennis Dalessandro struct opa_port_status_req { 2015f48ad614SDennis Dalessandro __u8 port_num; 2016f48ad614SDennis Dalessandro __u8 reserved[3]; 2017f48ad614SDennis Dalessandro __be32 vl_select_mask; 2018f48ad614SDennis Dalessandro }; 2019f48ad614SDennis Dalessandro 2020f48ad614SDennis Dalessandro #define VL_MASK_ALL 0x000080ff 2021f48ad614SDennis Dalessandro 2022f48ad614SDennis Dalessandro struct opa_port_status_rsp { 2023f48ad614SDennis Dalessandro __u8 port_num; 2024f48ad614SDennis Dalessandro __u8 reserved[3]; 2025f48ad614SDennis Dalessandro __be32 vl_select_mask; 2026f48ad614SDennis Dalessandro 2027f48ad614SDennis Dalessandro /* Data counters */ 2028f48ad614SDennis Dalessandro __be64 port_xmit_data; 2029f48ad614SDennis Dalessandro __be64 port_rcv_data; 2030f48ad614SDennis Dalessandro __be64 port_xmit_pkts; 2031f48ad614SDennis Dalessandro __be64 port_rcv_pkts; 2032f48ad614SDennis Dalessandro __be64 port_multicast_xmit_pkts; 2033f48ad614SDennis Dalessandro __be64 port_multicast_rcv_pkts; 2034f48ad614SDennis Dalessandro __be64 port_xmit_wait; 2035f48ad614SDennis Dalessandro __be64 sw_port_congestion; 2036f48ad614SDennis Dalessandro __be64 port_rcv_fecn; 2037f48ad614SDennis Dalessandro __be64 port_rcv_becn; 2038f48ad614SDennis Dalessandro __be64 port_xmit_time_cong; 2039f48ad614SDennis Dalessandro __be64 port_xmit_wasted_bw; 2040f48ad614SDennis Dalessandro __be64 port_xmit_wait_data; 2041f48ad614SDennis Dalessandro __be64 port_rcv_bubble; 2042f48ad614SDennis Dalessandro __be64 port_mark_fecn; 2043f48ad614SDennis Dalessandro /* Error counters */ 2044f48ad614SDennis Dalessandro __be64 port_rcv_constraint_errors; 2045f48ad614SDennis Dalessandro __be64 port_rcv_switch_relay_errors; 2046f48ad614SDennis Dalessandro __be64 port_xmit_discards; 2047f48ad614SDennis Dalessandro __be64 port_xmit_constraint_errors; 2048f48ad614SDennis Dalessandro __be64 port_rcv_remote_physical_errors; 2049f48ad614SDennis Dalessandro __be64 local_link_integrity_errors; 2050f48ad614SDennis Dalessandro __be64 port_rcv_errors; 2051f48ad614SDennis Dalessandro __be64 excessive_buffer_overruns; 2052f48ad614SDennis Dalessandro __be64 fm_config_errors; 2053f48ad614SDennis Dalessandro __be32 link_error_recovery; 2054f48ad614SDennis Dalessandro __be32 link_downed; 2055f48ad614SDennis Dalessandro u8 uncorrectable_errors; 2056f48ad614SDennis Dalessandro 2057f48ad614SDennis Dalessandro u8 link_quality_indicator; /* 5res, 3bit */ 2058f48ad614SDennis Dalessandro u8 res2[6]; 2059f48ad614SDennis Dalessandro struct _vls_pctrs { 2060f48ad614SDennis Dalessandro /* per-VL Data counters */ 2061f48ad614SDennis Dalessandro __be64 port_vl_xmit_data; 2062f48ad614SDennis Dalessandro __be64 port_vl_rcv_data; 2063f48ad614SDennis Dalessandro __be64 port_vl_xmit_pkts; 2064f48ad614SDennis Dalessandro __be64 port_vl_rcv_pkts; 2065f48ad614SDennis Dalessandro __be64 port_vl_xmit_wait; 2066f48ad614SDennis Dalessandro __be64 sw_port_vl_congestion; 2067f48ad614SDennis Dalessandro __be64 port_vl_rcv_fecn; 2068f48ad614SDennis Dalessandro __be64 port_vl_rcv_becn; 2069f48ad614SDennis Dalessandro __be64 port_xmit_time_cong; 2070f48ad614SDennis Dalessandro __be64 port_vl_xmit_wasted_bw; 2071f48ad614SDennis Dalessandro __be64 port_vl_xmit_wait_data; 2072f48ad614SDennis Dalessandro __be64 port_vl_rcv_bubble; 2073f48ad614SDennis Dalessandro __be64 port_vl_mark_fecn; 2074f48ad614SDennis Dalessandro __be64 port_vl_xmit_discards; 2075f48ad614SDennis Dalessandro } vls[0]; /* real array size defined by # bits set in vl_select_mask */ 2076f48ad614SDennis Dalessandro }; 2077f48ad614SDennis Dalessandro 2078f48ad614SDennis Dalessandro enum counter_selects { 2079f48ad614SDennis Dalessandro CS_PORT_XMIT_DATA = (1 << 31), 2080f48ad614SDennis Dalessandro CS_PORT_RCV_DATA = (1 << 30), 2081f48ad614SDennis Dalessandro CS_PORT_XMIT_PKTS = (1 << 29), 2082f48ad614SDennis Dalessandro CS_PORT_RCV_PKTS = (1 << 28), 2083f48ad614SDennis Dalessandro CS_PORT_MCAST_XMIT_PKTS = (1 << 27), 2084f48ad614SDennis Dalessandro CS_PORT_MCAST_RCV_PKTS = (1 << 26), 2085f48ad614SDennis Dalessandro CS_PORT_XMIT_WAIT = (1 << 25), 2086f48ad614SDennis Dalessandro CS_SW_PORT_CONGESTION = (1 << 24), 2087f48ad614SDennis Dalessandro CS_PORT_RCV_FECN = (1 << 23), 2088f48ad614SDennis Dalessandro CS_PORT_RCV_BECN = (1 << 22), 2089f48ad614SDennis Dalessandro CS_PORT_XMIT_TIME_CONG = (1 << 21), 2090f48ad614SDennis Dalessandro CS_PORT_XMIT_WASTED_BW = (1 << 20), 2091f48ad614SDennis Dalessandro CS_PORT_XMIT_WAIT_DATA = (1 << 19), 2092f48ad614SDennis Dalessandro CS_PORT_RCV_BUBBLE = (1 << 18), 2093f48ad614SDennis Dalessandro CS_PORT_MARK_FECN = (1 << 17), 2094f48ad614SDennis Dalessandro CS_PORT_RCV_CONSTRAINT_ERRORS = (1 << 16), 2095f48ad614SDennis Dalessandro CS_PORT_RCV_SWITCH_RELAY_ERRORS = (1 << 15), 2096f48ad614SDennis Dalessandro CS_PORT_XMIT_DISCARDS = (1 << 14), 2097f48ad614SDennis Dalessandro CS_PORT_XMIT_CONSTRAINT_ERRORS = (1 << 13), 2098f48ad614SDennis Dalessandro CS_PORT_RCV_REMOTE_PHYSICAL_ERRORS = (1 << 12), 2099f48ad614SDennis Dalessandro CS_LOCAL_LINK_INTEGRITY_ERRORS = (1 << 11), 2100f48ad614SDennis Dalessandro CS_PORT_RCV_ERRORS = (1 << 10), 2101f48ad614SDennis Dalessandro CS_EXCESSIVE_BUFFER_OVERRUNS = (1 << 9), 2102f48ad614SDennis Dalessandro CS_FM_CONFIG_ERRORS = (1 << 8), 2103f48ad614SDennis Dalessandro CS_LINK_ERROR_RECOVERY = (1 << 7), 2104f48ad614SDennis Dalessandro CS_LINK_DOWNED = (1 << 6), 2105f48ad614SDennis Dalessandro CS_UNCORRECTABLE_ERRORS = (1 << 5), 2106f48ad614SDennis Dalessandro }; 2107f48ad614SDennis Dalessandro 2108f48ad614SDennis Dalessandro struct opa_clear_port_status { 2109f48ad614SDennis Dalessandro __be64 port_select_mask[4]; 2110f48ad614SDennis Dalessandro __be32 counter_select_mask; 2111f48ad614SDennis Dalessandro }; 2112f48ad614SDennis Dalessandro 2113f48ad614SDennis Dalessandro struct opa_aggregate { 2114f48ad614SDennis Dalessandro __be16 attr_id; 2115f48ad614SDennis Dalessandro __be16 err_reqlength; /* 1 bit, 8 res, 7 bit */ 2116f48ad614SDennis Dalessandro __be32 attr_mod; 2117f48ad614SDennis Dalessandro u8 data[0]; 2118f48ad614SDennis Dalessandro }; 2119f48ad614SDennis Dalessandro 2120f48ad614SDennis Dalessandro #define MSK_LLI 0x000000f0 2121f48ad614SDennis Dalessandro #define MSK_LLI_SFT 4 2122f48ad614SDennis Dalessandro #define MSK_LER 0x0000000f 2123f48ad614SDennis Dalessandro #define MSK_LER_SFT 0 2124f48ad614SDennis Dalessandro #define ADD_LLI 8 2125f48ad614SDennis Dalessandro #define ADD_LER 2 2126f48ad614SDennis Dalessandro 2127f48ad614SDennis Dalessandro /* Request contains first three fields, response contains those plus the rest */ 2128f48ad614SDennis Dalessandro struct opa_port_data_counters_msg { 2129f48ad614SDennis Dalessandro __be64 port_select_mask[4]; 2130f48ad614SDennis Dalessandro __be32 vl_select_mask; 2131f48ad614SDennis Dalessandro __be32 resolution; 2132f48ad614SDennis Dalessandro 2133f48ad614SDennis Dalessandro /* Response fields follow */ 2134f48ad614SDennis Dalessandro struct _port_dctrs { 2135f48ad614SDennis Dalessandro u8 port_number; 2136f48ad614SDennis Dalessandro u8 reserved2[3]; 2137f48ad614SDennis Dalessandro __be32 link_quality_indicator; /* 29res, 3bit */ 2138f48ad614SDennis Dalessandro 2139f48ad614SDennis Dalessandro /* Data counters */ 2140f48ad614SDennis Dalessandro __be64 port_xmit_data; 2141f48ad614SDennis Dalessandro __be64 port_rcv_data; 2142f48ad614SDennis Dalessandro __be64 port_xmit_pkts; 2143f48ad614SDennis Dalessandro __be64 port_rcv_pkts; 2144f48ad614SDennis Dalessandro __be64 port_multicast_xmit_pkts; 2145f48ad614SDennis Dalessandro __be64 port_multicast_rcv_pkts; 2146f48ad614SDennis Dalessandro __be64 port_xmit_wait; 2147f48ad614SDennis Dalessandro __be64 sw_port_congestion; 2148f48ad614SDennis Dalessandro __be64 port_rcv_fecn; 2149f48ad614SDennis Dalessandro __be64 port_rcv_becn; 2150f48ad614SDennis Dalessandro __be64 port_xmit_time_cong; 2151f48ad614SDennis Dalessandro __be64 port_xmit_wasted_bw; 2152f48ad614SDennis Dalessandro __be64 port_xmit_wait_data; 2153f48ad614SDennis Dalessandro __be64 port_rcv_bubble; 2154f48ad614SDennis Dalessandro __be64 port_mark_fecn; 2155f48ad614SDennis Dalessandro 2156f48ad614SDennis Dalessandro __be64 port_error_counter_summary; 2157f48ad614SDennis Dalessandro /* Sum of error counts/port */ 2158f48ad614SDennis Dalessandro 2159f48ad614SDennis Dalessandro struct _vls_dctrs { 2160f48ad614SDennis Dalessandro /* per-VL Data counters */ 2161f48ad614SDennis Dalessandro __be64 port_vl_xmit_data; 2162f48ad614SDennis Dalessandro __be64 port_vl_rcv_data; 2163f48ad614SDennis Dalessandro __be64 port_vl_xmit_pkts; 2164f48ad614SDennis Dalessandro __be64 port_vl_rcv_pkts; 2165f48ad614SDennis Dalessandro __be64 port_vl_xmit_wait; 2166f48ad614SDennis Dalessandro __be64 sw_port_vl_congestion; 2167f48ad614SDennis Dalessandro __be64 port_vl_rcv_fecn; 2168f48ad614SDennis Dalessandro __be64 port_vl_rcv_becn; 2169f48ad614SDennis Dalessandro __be64 port_xmit_time_cong; 2170f48ad614SDennis Dalessandro __be64 port_vl_xmit_wasted_bw; 2171f48ad614SDennis Dalessandro __be64 port_vl_xmit_wait_data; 2172f48ad614SDennis Dalessandro __be64 port_vl_rcv_bubble; 2173f48ad614SDennis Dalessandro __be64 port_vl_mark_fecn; 2174f48ad614SDennis Dalessandro } vls[0]; 2175f48ad614SDennis Dalessandro /* array size defined by #bits set in vl_select_mask*/ 2176f48ad614SDennis Dalessandro } port[1]; /* array size defined by #ports in attribute modifier */ 2177f48ad614SDennis Dalessandro }; 2178f48ad614SDennis Dalessandro 2179f48ad614SDennis Dalessandro struct opa_port_error_counters64_msg { 2180f48ad614SDennis Dalessandro /* 2181f48ad614SDennis Dalessandro * Request contains first two fields, response contains the 2182f48ad614SDennis Dalessandro * whole magilla 2183f48ad614SDennis Dalessandro */ 2184f48ad614SDennis Dalessandro __be64 port_select_mask[4]; 2185f48ad614SDennis Dalessandro __be32 vl_select_mask; 2186f48ad614SDennis Dalessandro 2187f48ad614SDennis Dalessandro /* Response-only fields follow */ 2188f48ad614SDennis Dalessandro __be32 reserved1; 2189f48ad614SDennis Dalessandro struct _port_ectrs { 2190f48ad614SDennis Dalessandro u8 port_number; 2191f48ad614SDennis Dalessandro u8 reserved2[7]; 2192f48ad614SDennis Dalessandro __be64 port_rcv_constraint_errors; 2193f48ad614SDennis Dalessandro __be64 port_rcv_switch_relay_errors; 2194f48ad614SDennis Dalessandro __be64 port_xmit_discards; 2195f48ad614SDennis Dalessandro __be64 port_xmit_constraint_errors; 2196f48ad614SDennis Dalessandro __be64 port_rcv_remote_physical_errors; 2197f48ad614SDennis Dalessandro __be64 local_link_integrity_errors; 2198f48ad614SDennis Dalessandro __be64 port_rcv_errors; 2199f48ad614SDennis Dalessandro __be64 excessive_buffer_overruns; 2200f48ad614SDennis Dalessandro __be64 fm_config_errors; 2201f48ad614SDennis Dalessandro __be32 link_error_recovery; 2202f48ad614SDennis Dalessandro __be32 link_downed; 2203f48ad614SDennis Dalessandro u8 uncorrectable_errors; 2204f48ad614SDennis Dalessandro u8 reserved3[7]; 2205f48ad614SDennis Dalessandro struct _vls_ectrs { 2206f48ad614SDennis Dalessandro __be64 port_vl_xmit_discards; 2207f48ad614SDennis Dalessandro } vls[0]; 2208f48ad614SDennis Dalessandro /* array size defined by #bits set in vl_select_mask */ 2209f48ad614SDennis Dalessandro } port[1]; /* array size defined by #ports in attribute modifier */ 2210f48ad614SDennis Dalessandro }; 2211f48ad614SDennis Dalessandro 2212f48ad614SDennis Dalessandro struct opa_port_error_info_msg { 2213f48ad614SDennis Dalessandro __be64 port_select_mask[4]; 2214f48ad614SDennis Dalessandro __be32 error_info_select_mask; 2215f48ad614SDennis Dalessandro __be32 reserved1; 2216f48ad614SDennis Dalessandro struct _port_ei { 2217f48ad614SDennis Dalessandro u8 port_number; 2218f48ad614SDennis Dalessandro u8 reserved2[7]; 2219f48ad614SDennis Dalessandro 2220f48ad614SDennis Dalessandro /* PortRcvErrorInfo */ 2221f48ad614SDennis Dalessandro struct { 2222f48ad614SDennis Dalessandro u8 status_and_code; 2223f48ad614SDennis Dalessandro union { 2224f48ad614SDennis Dalessandro u8 raw[17]; 2225f48ad614SDennis Dalessandro struct { 2226f48ad614SDennis Dalessandro /* EI1to12 format */ 2227f48ad614SDennis Dalessandro u8 packet_flit1[8]; 2228f48ad614SDennis Dalessandro u8 packet_flit2[8]; 2229f48ad614SDennis Dalessandro u8 remaining_flit_bits12; 2230f48ad614SDennis Dalessandro } ei1to12; 2231f48ad614SDennis Dalessandro struct { 2232f48ad614SDennis Dalessandro u8 packet_bytes[8]; 2233f48ad614SDennis Dalessandro u8 remaining_flit_bits; 2234f48ad614SDennis Dalessandro } ei13; 2235f48ad614SDennis Dalessandro } ei; 2236f48ad614SDennis Dalessandro u8 reserved3[6]; 2237f48ad614SDennis Dalessandro } __packed port_rcv_ei; 2238f48ad614SDennis Dalessandro 2239f48ad614SDennis Dalessandro /* ExcessiveBufferOverrunInfo */ 2240f48ad614SDennis Dalessandro struct { 2241f48ad614SDennis Dalessandro u8 status_and_sc; 2242f48ad614SDennis Dalessandro u8 reserved4[7]; 2243f48ad614SDennis Dalessandro } __packed excessive_buffer_overrun_ei; 2244f48ad614SDennis Dalessandro 2245f48ad614SDennis Dalessandro /* PortXmitConstraintErrorInfo */ 2246f48ad614SDennis Dalessandro struct { 2247f48ad614SDennis Dalessandro u8 status; 2248f48ad614SDennis Dalessandro u8 reserved5; 2249f48ad614SDennis Dalessandro __be16 pkey; 2250f48ad614SDennis Dalessandro __be32 slid; 2251f48ad614SDennis Dalessandro } __packed port_xmit_constraint_ei; 2252f48ad614SDennis Dalessandro 2253f48ad614SDennis Dalessandro /* PortRcvConstraintErrorInfo */ 2254f48ad614SDennis Dalessandro struct { 2255f48ad614SDennis Dalessandro u8 status; 2256f48ad614SDennis Dalessandro u8 reserved6; 2257f48ad614SDennis Dalessandro __be16 pkey; 2258f48ad614SDennis Dalessandro __be32 slid; 2259f48ad614SDennis Dalessandro } __packed port_rcv_constraint_ei; 2260f48ad614SDennis Dalessandro 2261f48ad614SDennis Dalessandro /* PortRcvSwitchRelayErrorInfo */ 2262f48ad614SDennis Dalessandro struct { 2263f48ad614SDennis Dalessandro u8 status_and_code; 2264f48ad614SDennis Dalessandro u8 reserved7[3]; 2265f48ad614SDennis Dalessandro __u32 error_info; 2266f48ad614SDennis Dalessandro } __packed port_rcv_switch_relay_ei; 2267f48ad614SDennis Dalessandro 2268f48ad614SDennis Dalessandro /* UncorrectableErrorInfo */ 2269f48ad614SDennis Dalessandro struct { 2270f48ad614SDennis Dalessandro u8 status_and_code; 2271f48ad614SDennis Dalessandro u8 reserved8; 2272f48ad614SDennis Dalessandro } __packed uncorrectable_ei; 2273f48ad614SDennis Dalessandro 2274f48ad614SDennis Dalessandro /* FMConfigErrorInfo */ 2275f48ad614SDennis Dalessandro struct { 2276f48ad614SDennis Dalessandro u8 status_and_code; 2277f48ad614SDennis Dalessandro u8 error_info; 2278f48ad614SDennis Dalessandro } __packed fm_config_ei; 2279f48ad614SDennis Dalessandro __u32 reserved9; 2280f48ad614SDennis Dalessandro } port[1]; /* actual array size defined by #ports in attr modifier */ 2281f48ad614SDennis Dalessandro }; 2282f48ad614SDennis Dalessandro 2283f48ad614SDennis Dalessandro /* opa_port_error_info_msg error_info_select_mask bit definitions */ 2284f48ad614SDennis Dalessandro enum error_info_selects { 2285f48ad614SDennis Dalessandro ES_PORT_RCV_ERROR_INFO = (1 << 31), 2286f48ad614SDennis Dalessandro ES_EXCESSIVE_BUFFER_OVERRUN_INFO = (1 << 30), 2287f48ad614SDennis Dalessandro ES_PORT_XMIT_CONSTRAINT_ERROR_INFO = (1 << 29), 2288f48ad614SDennis Dalessandro ES_PORT_RCV_CONSTRAINT_ERROR_INFO = (1 << 28), 2289f48ad614SDennis Dalessandro ES_PORT_RCV_SWITCH_RELAY_ERROR_INFO = (1 << 27), 2290f48ad614SDennis Dalessandro ES_UNCORRECTABLE_ERROR_INFO = (1 << 26), 2291f48ad614SDennis Dalessandro ES_FM_CONFIG_ERROR_INFO = (1 << 25) 2292f48ad614SDennis Dalessandro }; 2293f48ad614SDennis Dalessandro 2294f48ad614SDennis Dalessandro static int pma_get_opa_classportinfo(struct opa_pma_mad *pmp, 2295f48ad614SDennis Dalessandro struct ib_device *ibdev, u32 *resp_len) 2296f48ad614SDennis Dalessandro { 2297f48ad614SDennis Dalessandro struct opa_class_port_info *p = 2298f48ad614SDennis Dalessandro (struct opa_class_port_info *)pmp->data; 2299f48ad614SDennis Dalessandro 2300f48ad614SDennis Dalessandro memset(pmp->data, 0, sizeof(pmp->data)); 2301f48ad614SDennis Dalessandro 2302f48ad614SDennis Dalessandro if (pmp->mad_hdr.attr_mod != 0) 2303f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2304f48ad614SDennis Dalessandro 2305f48ad614SDennis Dalessandro p->base_version = OPA_MGMT_BASE_VERSION; 23069fa240bbSHal Rosenstock p->class_version = OPA_SM_CLASS_VERSION; 2307f48ad614SDennis Dalessandro /* 2308f48ad614SDennis Dalessandro * Expected response time is 4.096 usec. * 2^18 == 1.073741824 sec. 2309f48ad614SDennis Dalessandro */ 2310f48ad614SDennis Dalessandro p->cap_mask2_resp_time = cpu_to_be32(18); 2311f48ad614SDennis Dalessandro 2312f48ad614SDennis Dalessandro if (resp_len) 2313f48ad614SDennis Dalessandro *resp_len += sizeof(*p); 2314f48ad614SDennis Dalessandro 2315f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2316f48ad614SDennis Dalessandro } 2317f48ad614SDennis Dalessandro 2318f48ad614SDennis Dalessandro static void a0_portstatus(struct hfi1_pportdata *ppd, 2319f48ad614SDennis Dalessandro struct opa_port_status_rsp *rsp, u32 vl_select_mask) 2320f48ad614SDennis Dalessandro { 2321f48ad614SDennis Dalessandro if (!is_bx(ppd->dd)) { 2322f48ad614SDennis Dalessandro unsigned long vl; 2323f48ad614SDennis Dalessandro u64 sum_vl_xmit_wait = 0; 2324f48ad614SDennis Dalessandro u32 vl_all_mask = VL_MASK_ALL; 2325f48ad614SDennis Dalessandro 2326f48ad614SDennis Dalessandro for_each_set_bit(vl, (unsigned long *)&(vl_all_mask), 2327f48ad614SDennis Dalessandro 8 * sizeof(vl_all_mask)) { 2328f48ad614SDennis Dalessandro u64 tmp = sum_vl_xmit_wait + 2329f48ad614SDennis Dalessandro read_port_cntr(ppd, C_TX_WAIT_VL, 2330f48ad614SDennis Dalessandro idx_from_vl(vl)); 2331f48ad614SDennis Dalessandro if (tmp < sum_vl_xmit_wait) { 2332f48ad614SDennis Dalessandro /* we wrapped */ 2333f48ad614SDennis Dalessandro sum_vl_xmit_wait = (u64)~0; 2334f48ad614SDennis Dalessandro break; 2335f48ad614SDennis Dalessandro } 2336f48ad614SDennis Dalessandro sum_vl_xmit_wait = tmp; 2337f48ad614SDennis Dalessandro } 2338f48ad614SDennis Dalessandro if (be64_to_cpu(rsp->port_xmit_wait) > sum_vl_xmit_wait) 2339f48ad614SDennis Dalessandro rsp->port_xmit_wait = cpu_to_be64(sum_vl_xmit_wait); 2340f48ad614SDennis Dalessandro } 2341f48ad614SDennis Dalessandro } 2342f48ad614SDennis Dalessandro 2343f48ad614SDennis Dalessandro static int pma_get_opa_portstatus(struct opa_pma_mad *pmp, 2344f48ad614SDennis Dalessandro struct ib_device *ibdev, 2345f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 2346f48ad614SDennis Dalessandro { 2347f48ad614SDennis Dalessandro struct opa_port_status_req *req = 2348f48ad614SDennis Dalessandro (struct opa_port_status_req *)pmp->data; 2349f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2350f48ad614SDennis Dalessandro struct opa_port_status_rsp *rsp; 2351f48ad614SDennis Dalessandro u32 vl_select_mask = be32_to_cpu(req->vl_select_mask); 2352f48ad614SDennis Dalessandro unsigned long vl; 2353f48ad614SDennis Dalessandro size_t response_data_size; 2354f48ad614SDennis Dalessandro u32 nports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; 2355f48ad614SDennis Dalessandro u8 port_num = req->port_num; 2356f48ad614SDennis Dalessandro u8 num_vls = hweight32(vl_select_mask); 2357f48ad614SDennis Dalessandro struct _vls_pctrs *vlinfo; 2358f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 2359f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 2360f48ad614SDennis Dalessandro int vfi; 2361f48ad614SDennis Dalessandro u64 tmp, tmp2; 2362f48ad614SDennis Dalessandro 2363f48ad614SDennis Dalessandro response_data_size = sizeof(struct opa_port_status_rsp) + 2364f48ad614SDennis Dalessandro num_vls * sizeof(struct _vls_pctrs); 2365f48ad614SDennis Dalessandro if (response_data_size > sizeof(pmp->data)) { 2366f48ad614SDennis Dalessandro pmp->mad_hdr.status |= OPA_PM_STATUS_REQUEST_TOO_LARGE; 2367f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2368f48ad614SDennis Dalessandro } 2369f48ad614SDennis Dalessandro 2370f48ad614SDennis Dalessandro if (nports != 1 || (port_num && port_num != port) || 2371f48ad614SDennis Dalessandro num_vls > OPA_MAX_VLS || (vl_select_mask & ~VL_MASK_ALL)) { 2372f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2373f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2374f48ad614SDennis Dalessandro } 2375f48ad614SDennis Dalessandro 2376f48ad614SDennis Dalessandro memset(pmp->data, 0, sizeof(pmp->data)); 2377f48ad614SDennis Dalessandro 2378f48ad614SDennis Dalessandro rsp = (struct opa_port_status_rsp *)pmp->data; 2379f48ad614SDennis Dalessandro if (port_num) 2380f48ad614SDennis Dalessandro rsp->port_num = port_num; 2381f48ad614SDennis Dalessandro else 2382f48ad614SDennis Dalessandro rsp->port_num = port; 2383f48ad614SDennis Dalessandro 2384f48ad614SDennis Dalessandro rsp->port_rcv_constraint_errors = 2385f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, 2386f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2387f48ad614SDennis Dalessandro 2388f48ad614SDennis Dalessandro hfi1_read_link_quality(dd, &rsp->link_quality_indicator); 2389f48ad614SDennis Dalessandro 2390f48ad614SDennis Dalessandro rsp->vl_select_mask = cpu_to_be32(vl_select_mask); 2391f48ad614SDennis Dalessandro rsp->port_xmit_data = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_FLITS, 2392f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2393f48ad614SDennis Dalessandro rsp->port_rcv_data = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FLITS, 2394f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2395f48ad614SDennis Dalessandro rsp->port_xmit_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_PKTS, 2396f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2397f48ad614SDennis Dalessandro rsp->port_rcv_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_PKTS, 2398f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2399f48ad614SDennis Dalessandro rsp->port_multicast_xmit_pkts = 2400f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_MC_XMIT_PKTS, 2401f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2402f48ad614SDennis Dalessandro rsp->port_multicast_rcv_pkts = 2403f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_MC_RCV_PKTS, 2404f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2405f48ad614SDennis Dalessandro rsp->port_xmit_wait = 2406f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_WAIT, CNTR_INVALID_VL)); 2407f48ad614SDennis Dalessandro rsp->port_rcv_fecn = 2408f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN, CNTR_INVALID_VL)); 2409f48ad614SDennis Dalessandro rsp->port_rcv_becn = 2410f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL)); 2411f48ad614SDennis Dalessandro rsp->port_xmit_discards = 2412f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD, 2413f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2414f48ad614SDennis Dalessandro rsp->port_xmit_constraint_errors = 2415f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, 2416f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2417f48ad614SDennis Dalessandro rsp->port_rcv_remote_physical_errors = 2418f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR, 2419f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 24203210314aSJakub Pawlak rsp->local_link_integrity_errors = 24213210314aSJakub Pawlak cpu_to_be64(read_dev_cntr(dd, C_DC_RX_REPLAY, 24223210314aSJakub Pawlak CNTR_INVALID_VL)); 2423f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); 2424f48ad614SDennis Dalessandro tmp2 = tmp + read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, 2425f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2426f48ad614SDennis Dalessandro if (tmp2 > (u32)UINT_MAX || tmp2 < tmp) { 2427f48ad614SDennis Dalessandro /* overflow/wrapped */ 2428f48ad614SDennis Dalessandro rsp->link_error_recovery = cpu_to_be32(~0); 2429f48ad614SDennis Dalessandro } else { 2430f48ad614SDennis Dalessandro rsp->link_error_recovery = cpu_to_be32(tmp2); 2431f48ad614SDennis Dalessandro } 2432f48ad614SDennis Dalessandro rsp->port_rcv_errors = 2433f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL)); 2434f48ad614SDennis Dalessandro rsp->excessive_buffer_overruns = 2435f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL)); 2436f48ad614SDennis Dalessandro rsp->fm_config_errors = 2437f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_FM_CFG_ERR, 2438f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2439f48ad614SDennis Dalessandro rsp->link_downed = cpu_to_be32(read_port_cntr(ppd, C_SW_LINK_DOWN, 2440f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2441f48ad614SDennis Dalessandro 2442f48ad614SDennis Dalessandro /* rsp->uncorrectable_errors is 8 bits wide, and it pegs at 0xff */ 2443f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); 2444f48ad614SDennis Dalessandro rsp->uncorrectable_errors = tmp < 0x100 ? (tmp & 0xff) : 0xff; 2445f48ad614SDennis Dalessandro 2446f48ad614SDennis Dalessandro vlinfo = &rsp->vls[0]; 2447f48ad614SDennis Dalessandro vfi = 0; 2448f48ad614SDennis Dalessandro /* The vl_select_mask has been checked above, and we know 2449f48ad614SDennis Dalessandro * that it contains only entries which represent valid VLs. 2450f48ad614SDennis Dalessandro * So in the for_each_set_bit() loop below, we don't need 2451f48ad614SDennis Dalessandro * any additional checks for vl. 2452f48ad614SDennis Dalessandro */ 2453f48ad614SDennis Dalessandro for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), 2454f48ad614SDennis Dalessandro 8 * sizeof(vl_select_mask)) { 2455f48ad614SDennis Dalessandro memset(vlinfo, 0, sizeof(*vlinfo)); 2456f48ad614SDennis Dalessandro 2457f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_RX_FLIT_VL, idx_from_vl(vl)); 2458f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_data = cpu_to_be64(tmp); 2459f48ad614SDennis Dalessandro 2460f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_pkts = 2461f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RX_PKT_VL, 2462f48ad614SDennis Dalessandro idx_from_vl(vl))); 2463f48ad614SDennis Dalessandro 2464f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_data = 2465f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_FLIT_VL, 2466f48ad614SDennis Dalessandro idx_from_vl(vl))); 2467f48ad614SDennis Dalessandro 2468f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_pkts = 2469f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_PKT_VL, 2470f48ad614SDennis Dalessandro idx_from_vl(vl))); 2471f48ad614SDennis Dalessandro 2472f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_wait = 2473f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_WAIT_VL, 2474f48ad614SDennis Dalessandro idx_from_vl(vl))); 2475f48ad614SDennis Dalessandro 2476f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_fecn = 2477f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN_VL, 2478f48ad614SDennis Dalessandro idx_from_vl(vl))); 2479f48ad614SDennis Dalessandro 2480f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_becn = 2481f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN_VL, 2482f48ad614SDennis Dalessandro idx_from_vl(vl))); 2483f48ad614SDennis Dalessandro 2484583eb8b8SJakub Pawlak rsp->vls[vfi].port_vl_xmit_discards = 2485583eb8b8SJakub Pawlak cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD_VL, 2486583eb8b8SJakub Pawlak idx_from_vl(vl))); 2487f48ad614SDennis Dalessandro vlinfo++; 2488f48ad614SDennis Dalessandro vfi++; 2489f48ad614SDennis Dalessandro } 2490f48ad614SDennis Dalessandro 2491f48ad614SDennis Dalessandro a0_portstatus(ppd, rsp, vl_select_mask); 2492f48ad614SDennis Dalessandro 2493f48ad614SDennis Dalessandro if (resp_len) 2494f48ad614SDennis Dalessandro *resp_len += response_data_size; 2495f48ad614SDennis Dalessandro 2496f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2497f48ad614SDennis Dalessandro } 2498f48ad614SDennis Dalessandro 2499f48ad614SDennis Dalessandro static u64 get_error_counter_summary(struct ib_device *ibdev, u8 port, 2500f48ad614SDennis Dalessandro u8 res_lli, u8 res_ler) 2501f48ad614SDennis Dalessandro { 2502f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2503f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 2504f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 2505f48ad614SDennis Dalessandro u64 error_counter_summary = 0, tmp; 2506f48ad614SDennis Dalessandro 2507f48ad614SDennis Dalessandro error_counter_summary += read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, 2508f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2509f48ad614SDennis Dalessandro /* port_rcv_switch_relay_errors is 0 for HFIs */ 2510f48ad614SDennis Dalessandro error_counter_summary += read_port_cntr(ppd, C_SW_XMIT_DSCD, 2511f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2512f48ad614SDennis Dalessandro error_counter_summary += read_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, 2513f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2514f48ad614SDennis Dalessandro error_counter_summary += read_dev_cntr(dd, C_DC_RMT_PHY_ERR, 2515f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2516f48ad614SDennis Dalessandro /* local link integrity must be right-shifted by the lli resolution */ 25173210314aSJakub Pawlak error_counter_summary += (read_dev_cntr(dd, C_DC_RX_REPLAY, 25183210314aSJakub Pawlak CNTR_INVALID_VL) >> res_lli); 2519f48ad614SDennis Dalessandro /* link error recovery must b right-shifted by the ler resolution */ 2520f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); 2521f48ad614SDennis Dalessandro tmp += read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL); 2522f48ad614SDennis Dalessandro error_counter_summary += (tmp >> res_ler); 2523f48ad614SDennis Dalessandro error_counter_summary += read_dev_cntr(dd, C_DC_RCV_ERR, 2524f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2525f48ad614SDennis Dalessandro error_counter_summary += read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL); 2526f48ad614SDennis Dalessandro error_counter_summary += read_dev_cntr(dd, C_DC_FM_CFG_ERR, 2527f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2528f48ad614SDennis Dalessandro /* ppd->link_downed is a 32-bit value */ 2529f48ad614SDennis Dalessandro error_counter_summary += read_port_cntr(ppd, C_SW_LINK_DOWN, 2530f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2531f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); 2532f48ad614SDennis Dalessandro /* this is an 8-bit quantity */ 2533f48ad614SDennis Dalessandro error_counter_summary += tmp < 0x100 ? (tmp & 0xff) : 0xff; 2534f48ad614SDennis Dalessandro 2535f48ad614SDennis Dalessandro return error_counter_summary; 2536f48ad614SDennis Dalessandro } 2537f48ad614SDennis Dalessandro 2538f48ad614SDennis Dalessandro static void a0_datacounters(struct hfi1_pportdata *ppd, struct _port_dctrs *rsp, 2539f48ad614SDennis Dalessandro u32 vl_select_mask) 2540f48ad614SDennis Dalessandro { 2541f48ad614SDennis Dalessandro if (!is_bx(ppd->dd)) { 2542f48ad614SDennis Dalessandro unsigned long vl; 2543f48ad614SDennis Dalessandro u64 sum_vl_xmit_wait = 0; 2544f48ad614SDennis Dalessandro u32 vl_all_mask = VL_MASK_ALL; 2545f48ad614SDennis Dalessandro 2546f48ad614SDennis Dalessandro for_each_set_bit(vl, (unsigned long *)&(vl_all_mask), 2547f48ad614SDennis Dalessandro 8 * sizeof(vl_all_mask)) { 2548f48ad614SDennis Dalessandro u64 tmp = sum_vl_xmit_wait + 2549f48ad614SDennis Dalessandro read_port_cntr(ppd, C_TX_WAIT_VL, 2550f48ad614SDennis Dalessandro idx_from_vl(vl)); 2551f48ad614SDennis Dalessandro if (tmp < sum_vl_xmit_wait) { 2552f48ad614SDennis Dalessandro /* we wrapped */ 2553f48ad614SDennis Dalessandro sum_vl_xmit_wait = (u64)~0; 2554f48ad614SDennis Dalessandro break; 2555f48ad614SDennis Dalessandro } 2556f48ad614SDennis Dalessandro sum_vl_xmit_wait = tmp; 2557f48ad614SDennis Dalessandro } 2558f48ad614SDennis Dalessandro if (be64_to_cpu(rsp->port_xmit_wait) > sum_vl_xmit_wait) 2559f48ad614SDennis Dalessandro rsp->port_xmit_wait = cpu_to_be64(sum_vl_xmit_wait); 2560f48ad614SDennis Dalessandro } 2561f48ad614SDennis Dalessandro } 2562f48ad614SDennis Dalessandro 2563f48ad614SDennis Dalessandro static void pma_get_opa_port_dctrs(struct ib_device *ibdev, 2564f48ad614SDennis Dalessandro struct _port_dctrs *rsp) 2565f48ad614SDennis Dalessandro { 2566f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2567f48ad614SDennis Dalessandro 2568f48ad614SDennis Dalessandro rsp->port_xmit_data = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_FLITS, 2569f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2570f48ad614SDennis Dalessandro rsp->port_rcv_data = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FLITS, 2571f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2572f48ad614SDennis Dalessandro rsp->port_xmit_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_PKTS, 2573f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2574f48ad614SDennis Dalessandro rsp->port_rcv_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_PKTS, 2575f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2576f48ad614SDennis Dalessandro rsp->port_multicast_xmit_pkts = 2577f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_MC_XMIT_PKTS, 2578f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2579f48ad614SDennis Dalessandro rsp->port_multicast_rcv_pkts = 2580f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_MC_RCV_PKTS, 2581f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2582f48ad614SDennis Dalessandro } 2583f48ad614SDennis Dalessandro 2584f48ad614SDennis Dalessandro static int pma_get_opa_datacounters(struct opa_pma_mad *pmp, 2585f48ad614SDennis Dalessandro struct ib_device *ibdev, 2586f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 2587f48ad614SDennis Dalessandro { 2588f48ad614SDennis Dalessandro struct opa_port_data_counters_msg *req = 2589f48ad614SDennis Dalessandro (struct opa_port_data_counters_msg *)pmp->data; 2590f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2591f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 2592f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 2593f48ad614SDennis Dalessandro struct _port_dctrs *rsp; 2594f48ad614SDennis Dalessandro struct _vls_dctrs *vlinfo; 2595f48ad614SDennis Dalessandro size_t response_data_size; 2596f48ad614SDennis Dalessandro u32 num_ports; 2597f48ad614SDennis Dalessandro u8 num_pslm; 2598f48ad614SDennis Dalessandro u8 lq, num_vls; 2599f48ad614SDennis Dalessandro u8 res_lli, res_ler; 2600f48ad614SDennis Dalessandro u64 port_mask; 260161a28d2bSChristophe Jaillet u8 port_num; 2602f48ad614SDennis Dalessandro unsigned long vl; 2603f48ad614SDennis Dalessandro u32 vl_select_mask; 2604f48ad614SDennis Dalessandro int vfi; 2605f48ad614SDennis Dalessandro 2606f48ad614SDennis Dalessandro num_ports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; 2607f48ad614SDennis Dalessandro num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); 2608f48ad614SDennis Dalessandro num_vls = hweight32(be32_to_cpu(req->vl_select_mask)); 2609f48ad614SDennis Dalessandro vl_select_mask = be32_to_cpu(req->vl_select_mask); 2610f48ad614SDennis Dalessandro res_lli = (u8)(be32_to_cpu(req->resolution) & MSK_LLI) >> MSK_LLI_SFT; 2611f48ad614SDennis Dalessandro res_lli = res_lli ? res_lli + ADD_LLI : 0; 2612f48ad614SDennis Dalessandro res_ler = (u8)(be32_to_cpu(req->resolution) & MSK_LER) >> MSK_LER_SFT; 2613f48ad614SDennis Dalessandro res_ler = res_ler ? res_ler + ADD_LER : 0; 2614f48ad614SDennis Dalessandro 2615f48ad614SDennis Dalessandro if (num_ports != 1 || (vl_select_mask & ~VL_MASK_ALL)) { 2616f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2617f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2618f48ad614SDennis Dalessandro } 2619f48ad614SDennis Dalessandro 2620f48ad614SDennis Dalessandro /* Sanity check */ 2621f48ad614SDennis Dalessandro response_data_size = sizeof(struct opa_port_data_counters_msg) + 2622f48ad614SDennis Dalessandro num_vls * sizeof(struct _vls_dctrs); 2623f48ad614SDennis Dalessandro 2624f48ad614SDennis Dalessandro if (response_data_size > sizeof(pmp->data)) { 2625f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2626f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2627f48ad614SDennis Dalessandro } 2628f48ad614SDennis Dalessandro 2629f48ad614SDennis Dalessandro /* 2630f48ad614SDennis Dalessandro * The bit set in the mask needs to be consistent with the 2631f48ad614SDennis Dalessandro * port the request came in on. 2632f48ad614SDennis Dalessandro */ 2633f48ad614SDennis Dalessandro port_mask = be64_to_cpu(req->port_select_mask[3]); 2634f48ad614SDennis Dalessandro port_num = find_first_bit((unsigned long *)&port_mask, 26356aaa382fSChristophe Jaillet sizeof(port_mask) * 8); 2636f48ad614SDennis Dalessandro 263761a28d2bSChristophe Jaillet if (port_num != port) { 2638f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2639f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2640f48ad614SDennis Dalessandro } 2641f48ad614SDennis Dalessandro 2642f48ad614SDennis Dalessandro rsp = &req->port[0]; 2643f48ad614SDennis Dalessandro memset(rsp, 0, sizeof(*rsp)); 2644f48ad614SDennis Dalessandro 2645f48ad614SDennis Dalessandro rsp->port_number = port; 2646f48ad614SDennis Dalessandro /* 2647f48ad614SDennis Dalessandro * Note that link_quality_indicator is a 32 bit quantity in 2648f48ad614SDennis Dalessandro * 'datacounters' queries (as opposed to 'portinfo' queries, 2649f48ad614SDennis Dalessandro * where it's a byte). 2650f48ad614SDennis Dalessandro */ 2651f48ad614SDennis Dalessandro hfi1_read_link_quality(dd, &lq); 2652f48ad614SDennis Dalessandro rsp->link_quality_indicator = cpu_to_be32((u32)lq); 2653f48ad614SDennis Dalessandro pma_get_opa_port_dctrs(ibdev, rsp); 2654f48ad614SDennis Dalessandro 2655f48ad614SDennis Dalessandro rsp->port_xmit_wait = 2656f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_WAIT, CNTR_INVALID_VL)); 2657f48ad614SDennis Dalessandro rsp->port_rcv_fecn = 2658f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN, CNTR_INVALID_VL)); 2659f48ad614SDennis Dalessandro rsp->port_rcv_becn = 2660f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL)); 2661f48ad614SDennis Dalessandro rsp->port_error_counter_summary = 2662f48ad614SDennis Dalessandro cpu_to_be64(get_error_counter_summary(ibdev, port, 2663f48ad614SDennis Dalessandro res_lli, res_ler)); 2664f48ad614SDennis Dalessandro 2665f48ad614SDennis Dalessandro vlinfo = &rsp->vls[0]; 2666f48ad614SDennis Dalessandro vfi = 0; 2667f48ad614SDennis Dalessandro /* The vl_select_mask has been checked above, and we know 2668f48ad614SDennis Dalessandro * that it contains only entries which represent valid VLs. 2669f48ad614SDennis Dalessandro * So in the for_each_set_bit() loop below, we don't need 2670f48ad614SDennis Dalessandro * any additional checks for vl. 2671f48ad614SDennis Dalessandro */ 2672f48ad614SDennis Dalessandro for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), 2673f48ad614SDennis Dalessandro 8 * sizeof(req->vl_select_mask)) { 2674f48ad614SDennis Dalessandro memset(vlinfo, 0, sizeof(*vlinfo)); 2675f48ad614SDennis Dalessandro 2676f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_data = 2677f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_FLIT_VL, 2678f48ad614SDennis Dalessandro idx_from_vl(vl))); 2679f48ad614SDennis Dalessandro 2680f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_data = 2681f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RX_FLIT_VL, 2682f48ad614SDennis Dalessandro idx_from_vl(vl))); 2683f48ad614SDennis Dalessandro 2684f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_pkts = 2685f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_PKT_VL, 2686f48ad614SDennis Dalessandro idx_from_vl(vl))); 2687f48ad614SDennis Dalessandro 2688f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_pkts = 2689f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RX_PKT_VL, 2690f48ad614SDennis Dalessandro idx_from_vl(vl))); 2691f48ad614SDennis Dalessandro 2692f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_wait = 2693f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_WAIT_VL, 2694f48ad614SDennis Dalessandro idx_from_vl(vl))); 2695f48ad614SDennis Dalessandro 2696f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_fecn = 2697f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN_VL, 2698f48ad614SDennis Dalessandro idx_from_vl(vl))); 2699f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_becn = 2700f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN_VL, 2701f48ad614SDennis Dalessandro idx_from_vl(vl))); 2702f48ad614SDennis Dalessandro 2703f48ad614SDennis Dalessandro /* rsp->port_vl_xmit_time_cong is 0 for HFIs */ 2704f48ad614SDennis Dalessandro /* rsp->port_vl_xmit_wasted_bw ??? */ 2705f48ad614SDennis Dalessandro /* port_vl_xmit_wait_data - TXE (table 13-9 HFI spec) ??? 2706f48ad614SDennis Dalessandro * does this differ from rsp->vls[vfi].port_vl_xmit_wait 2707f48ad614SDennis Dalessandro */ 2708f48ad614SDennis Dalessandro /*rsp->vls[vfi].port_vl_mark_fecn = 2709f48ad614SDennis Dalessandro * cpu_to_be64(read_csr(dd, DCC_PRF_PORT_VL_MARK_FECN_CNT 2710f48ad614SDennis Dalessandro * + offset)); 2711f48ad614SDennis Dalessandro */ 2712f48ad614SDennis Dalessandro vlinfo++; 2713f48ad614SDennis Dalessandro vfi++; 2714f48ad614SDennis Dalessandro } 2715f48ad614SDennis Dalessandro 2716f48ad614SDennis Dalessandro a0_datacounters(ppd, rsp, vl_select_mask); 2717f48ad614SDennis Dalessandro 2718f48ad614SDennis Dalessandro if (resp_len) 2719f48ad614SDennis Dalessandro *resp_len += response_data_size; 2720f48ad614SDennis Dalessandro 2721f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2722f48ad614SDennis Dalessandro } 2723f48ad614SDennis Dalessandro 2724f48ad614SDennis Dalessandro static int pma_get_ib_portcounters_ext(struct ib_pma_mad *pmp, 2725f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port) 2726f48ad614SDennis Dalessandro { 2727f48ad614SDennis Dalessandro struct ib_pma_portcounters_ext *p = (struct ib_pma_portcounters_ext *) 2728f48ad614SDennis Dalessandro pmp->data; 2729f48ad614SDennis Dalessandro struct _port_dctrs rsp; 2730f48ad614SDennis Dalessandro 2731f48ad614SDennis Dalessandro if (pmp->mad_hdr.attr_mod != 0 || p->port_select != port) { 2732f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2733f48ad614SDennis Dalessandro goto bail; 2734f48ad614SDennis Dalessandro } 2735f48ad614SDennis Dalessandro 2736f48ad614SDennis Dalessandro memset(&rsp, 0, sizeof(rsp)); 2737f48ad614SDennis Dalessandro pma_get_opa_port_dctrs(ibdev, &rsp); 2738f48ad614SDennis Dalessandro 2739f48ad614SDennis Dalessandro p->port_xmit_data = rsp.port_xmit_data; 2740f48ad614SDennis Dalessandro p->port_rcv_data = rsp.port_rcv_data; 2741f48ad614SDennis Dalessandro p->port_xmit_packets = rsp.port_xmit_pkts; 2742f48ad614SDennis Dalessandro p->port_rcv_packets = rsp.port_rcv_pkts; 2743f48ad614SDennis Dalessandro p->port_unicast_xmit_packets = 0; 2744f48ad614SDennis Dalessandro p->port_unicast_rcv_packets = 0; 2745f48ad614SDennis Dalessandro p->port_multicast_xmit_packets = rsp.port_multicast_xmit_pkts; 2746f48ad614SDennis Dalessandro p->port_multicast_rcv_packets = rsp.port_multicast_rcv_pkts; 2747f48ad614SDennis Dalessandro 2748f48ad614SDennis Dalessandro bail: 2749f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2750f48ad614SDennis Dalessandro } 2751f48ad614SDennis Dalessandro 2752f48ad614SDennis Dalessandro static void pma_get_opa_port_ectrs(struct ib_device *ibdev, 2753f48ad614SDennis Dalessandro struct _port_ectrs *rsp, u8 port) 2754f48ad614SDennis Dalessandro { 2755f48ad614SDennis Dalessandro u64 tmp, tmp2; 2756f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2757f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 2758f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 2759f48ad614SDennis Dalessandro 2760f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); 2761f48ad614SDennis Dalessandro tmp2 = tmp + read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, 2762f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2763f48ad614SDennis Dalessandro if (tmp2 > (u32)UINT_MAX || tmp2 < tmp) { 2764f48ad614SDennis Dalessandro /* overflow/wrapped */ 2765f48ad614SDennis Dalessandro rsp->link_error_recovery = cpu_to_be32(~0); 2766f48ad614SDennis Dalessandro } else { 2767f48ad614SDennis Dalessandro rsp->link_error_recovery = cpu_to_be32(tmp2); 2768f48ad614SDennis Dalessandro } 2769f48ad614SDennis Dalessandro 2770f48ad614SDennis Dalessandro rsp->link_downed = cpu_to_be32(read_port_cntr(ppd, C_SW_LINK_DOWN, 2771f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2772f48ad614SDennis Dalessandro rsp->port_rcv_errors = 2773f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL)); 2774f48ad614SDennis Dalessandro rsp->port_rcv_remote_physical_errors = 2775f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR, 2776f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2777f48ad614SDennis Dalessandro rsp->port_rcv_switch_relay_errors = 0; 2778f48ad614SDennis Dalessandro rsp->port_xmit_discards = 2779f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD, 2780f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2781f48ad614SDennis Dalessandro rsp->port_xmit_constraint_errors = 2782f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, 2783f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2784f48ad614SDennis Dalessandro rsp->port_rcv_constraint_errors = 2785f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, 2786f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 27873210314aSJakub Pawlak rsp->local_link_integrity_errors = 27883210314aSJakub Pawlak cpu_to_be64(read_dev_cntr(dd, C_DC_RX_REPLAY, 27893210314aSJakub Pawlak CNTR_INVALID_VL)); 2790f48ad614SDennis Dalessandro rsp->excessive_buffer_overruns = 2791f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL)); 2792f48ad614SDennis Dalessandro } 2793f48ad614SDennis Dalessandro 2794f48ad614SDennis Dalessandro static int pma_get_opa_porterrors(struct opa_pma_mad *pmp, 2795f48ad614SDennis Dalessandro struct ib_device *ibdev, 2796f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 2797f48ad614SDennis Dalessandro { 2798f48ad614SDennis Dalessandro size_t response_data_size; 2799f48ad614SDennis Dalessandro struct _port_ectrs *rsp; 2800f48ad614SDennis Dalessandro u8 port_num; 2801f48ad614SDennis Dalessandro struct opa_port_error_counters64_msg *req; 2802f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2803f48ad614SDennis Dalessandro u32 num_ports; 2804f48ad614SDennis Dalessandro u8 num_pslm; 2805f48ad614SDennis Dalessandro u8 num_vls; 2806f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 2807f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 2808f48ad614SDennis Dalessandro struct _vls_ectrs *vlinfo; 2809f48ad614SDennis Dalessandro unsigned long vl; 2810f48ad614SDennis Dalessandro u64 port_mask, tmp; 2811f48ad614SDennis Dalessandro u32 vl_select_mask; 2812f48ad614SDennis Dalessandro int vfi; 2813f48ad614SDennis Dalessandro 2814f48ad614SDennis Dalessandro req = (struct opa_port_error_counters64_msg *)pmp->data; 2815f48ad614SDennis Dalessandro 2816f48ad614SDennis Dalessandro num_ports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; 2817f48ad614SDennis Dalessandro 2818f48ad614SDennis Dalessandro num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); 2819f48ad614SDennis Dalessandro num_vls = hweight32(be32_to_cpu(req->vl_select_mask)); 2820f48ad614SDennis Dalessandro 2821f48ad614SDennis Dalessandro if (num_ports != 1 || num_ports != num_pslm) { 2822f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2823f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2824f48ad614SDennis Dalessandro } 2825f48ad614SDennis Dalessandro 2826f48ad614SDennis Dalessandro response_data_size = sizeof(struct opa_port_error_counters64_msg) + 2827f48ad614SDennis Dalessandro num_vls * sizeof(struct _vls_ectrs); 2828f48ad614SDennis Dalessandro 2829f48ad614SDennis Dalessandro if (response_data_size > sizeof(pmp->data)) { 2830f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2831f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2832f48ad614SDennis Dalessandro } 2833f48ad614SDennis Dalessandro /* 2834f48ad614SDennis Dalessandro * The bit set in the mask needs to be consistent with the 2835f48ad614SDennis Dalessandro * port the request came in on. 2836f48ad614SDennis Dalessandro */ 2837f48ad614SDennis Dalessandro port_mask = be64_to_cpu(req->port_select_mask[3]); 2838f48ad614SDennis Dalessandro port_num = find_first_bit((unsigned long *)&port_mask, 28396aaa382fSChristophe Jaillet sizeof(port_mask) * 8); 2840f48ad614SDennis Dalessandro 2841f48ad614SDennis Dalessandro if (port_num != port) { 2842f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2843f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2844f48ad614SDennis Dalessandro } 2845f48ad614SDennis Dalessandro 2846f48ad614SDennis Dalessandro rsp = &req->port[0]; 2847f48ad614SDennis Dalessandro 2848f48ad614SDennis Dalessandro ibp = to_iport(ibdev, port_num); 2849f48ad614SDennis Dalessandro ppd = ppd_from_ibp(ibp); 2850f48ad614SDennis Dalessandro 2851f48ad614SDennis Dalessandro memset(rsp, 0, sizeof(*rsp)); 2852f48ad614SDennis Dalessandro rsp->port_number = port_num; 2853f48ad614SDennis Dalessandro 2854f48ad614SDennis Dalessandro pma_get_opa_port_ectrs(ibdev, rsp, port_num); 2855f48ad614SDennis Dalessandro 2856f48ad614SDennis Dalessandro rsp->port_rcv_remote_physical_errors = 2857f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR, 2858f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2859f48ad614SDennis Dalessandro rsp->fm_config_errors = 2860f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_FM_CFG_ERR, 2861f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2862f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); 2863f48ad614SDennis Dalessandro 2864f48ad614SDennis Dalessandro rsp->uncorrectable_errors = tmp < 0x100 ? (tmp & 0xff) : 0xff; 28652b719046SJakub Pawlak rsp->port_rcv_errors = 28662b719046SJakub Pawlak cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL)); 2867f48ad614SDennis Dalessandro vlinfo = &rsp->vls[0]; 2868f48ad614SDennis Dalessandro vfi = 0; 2869f48ad614SDennis Dalessandro vl_select_mask = be32_to_cpu(req->vl_select_mask); 2870f48ad614SDennis Dalessandro for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), 2871f48ad614SDennis Dalessandro 8 * sizeof(req->vl_select_mask)) { 2872f48ad614SDennis Dalessandro memset(vlinfo, 0, sizeof(*vlinfo)); 2873583eb8b8SJakub Pawlak rsp->vls[vfi].port_vl_xmit_discards = 2874583eb8b8SJakub Pawlak cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD_VL, 2875583eb8b8SJakub Pawlak idx_from_vl(vl))); 2876f48ad614SDennis Dalessandro vlinfo += 1; 2877f48ad614SDennis Dalessandro vfi++; 2878f48ad614SDennis Dalessandro } 2879f48ad614SDennis Dalessandro 2880f48ad614SDennis Dalessandro if (resp_len) 2881f48ad614SDennis Dalessandro *resp_len += response_data_size; 2882f48ad614SDennis Dalessandro 2883f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2884f48ad614SDennis Dalessandro } 2885f48ad614SDennis Dalessandro 2886f48ad614SDennis Dalessandro static int pma_get_ib_portcounters(struct ib_pma_mad *pmp, 2887f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port) 2888f48ad614SDennis Dalessandro { 2889f48ad614SDennis Dalessandro struct ib_pma_portcounters *p = (struct ib_pma_portcounters *) 2890f48ad614SDennis Dalessandro pmp->data; 2891f48ad614SDennis Dalessandro struct _port_ectrs rsp; 2892f48ad614SDennis Dalessandro u64 temp_link_overrun_errors; 2893f48ad614SDennis Dalessandro u64 temp_64; 2894f48ad614SDennis Dalessandro u32 temp_32; 2895f48ad614SDennis Dalessandro 2896f48ad614SDennis Dalessandro memset(&rsp, 0, sizeof(rsp)); 2897f48ad614SDennis Dalessandro pma_get_opa_port_ectrs(ibdev, &rsp, port); 2898f48ad614SDennis Dalessandro 2899f48ad614SDennis Dalessandro if (pmp->mad_hdr.attr_mod != 0 || p->port_select != port) { 2900f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2901f48ad614SDennis Dalessandro goto bail; 2902f48ad614SDennis Dalessandro } 2903f48ad614SDennis Dalessandro 2904f48ad614SDennis Dalessandro p->symbol_error_counter = 0; /* N/A for OPA */ 2905f48ad614SDennis Dalessandro 2906f48ad614SDennis Dalessandro temp_32 = be32_to_cpu(rsp.link_error_recovery); 2907f48ad614SDennis Dalessandro if (temp_32 > 0xFFUL) 2908f48ad614SDennis Dalessandro p->link_error_recovery_counter = 0xFF; 2909f48ad614SDennis Dalessandro else 2910f48ad614SDennis Dalessandro p->link_error_recovery_counter = (u8)temp_32; 2911f48ad614SDennis Dalessandro 2912f48ad614SDennis Dalessandro temp_32 = be32_to_cpu(rsp.link_downed); 2913f48ad614SDennis Dalessandro if (temp_32 > 0xFFUL) 2914f48ad614SDennis Dalessandro p->link_downed_counter = 0xFF; 2915f48ad614SDennis Dalessandro else 2916f48ad614SDennis Dalessandro p->link_downed_counter = (u8)temp_32; 2917f48ad614SDennis Dalessandro 2918f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_rcv_errors); 2919f48ad614SDennis Dalessandro if (temp_64 > 0xFFFFUL) 2920f48ad614SDennis Dalessandro p->port_rcv_errors = cpu_to_be16(0xFFFF); 2921f48ad614SDennis Dalessandro else 2922f48ad614SDennis Dalessandro p->port_rcv_errors = cpu_to_be16((u16)temp_64); 2923f48ad614SDennis Dalessandro 2924f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_rcv_remote_physical_errors); 2925f48ad614SDennis Dalessandro if (temp_64 > 0xFFFFUL) 2926f48ad614SDennis Dalessandro p->port_rcv_remphys_errors = cpu_to_be16(0xFFFF); 2927f48ad614SDennis Dalessandro else 2928f48ad614SDennis Dalessandro p->port_rcv_remphys_errors = cpu_to_be16((u16)temp_64); 2929f48ad614SDennis Dalessandro 2930f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_rcv_switch_relay_errors); 2931f48ad614SDennis Dalessandro p->port_rcv_switch_relay_errors = cpu_to_be16((u16)temp_64); 2932f48ad614SDennis Dalessandro 2933f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_xmit_discards); 2934f48ad614SDennis Dalessandro if (temp_64 > 0xFFFFUL) 2935f48ad614SDennis Dalessandro p->port_xmit_discards = cpu_to_be16(0xFFFF); 2936f48ad614SDennis Dalessandro else 2937f48ad614SDennis Dalessandro p->port_xmit_discards = cpu_to_be16((u16)temp_64); 2938f48ad614SDennis Dalessandro 2939f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_xmit_constraint_errors); 2940f48ad614SDennis Dalessandro if (temp_64 > 0xFFUL) 2941f48ad614SDennis Dalessandro p->port_xmit_constraint_errors = 0xFF; 2942f48ad614SDennis Dalessandro else 2943f48ad614SDennis Dalessandro p->port_xmit_constraint_errors = (u8)temp_64; 2944f48ad614SDennis Dalessandro 2945f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_rcv_constraint_errors); 2946f48ad614SDennis Dalessandro if (temp_64 > 0xFFUL) 2947f48ad614SDennis Dalessandro p->port_rcv_constraint_errors = 0xFFUL; 2948f48ad614SDennis Dalessandro else 2949f48ad614SDennis Dalessandro p->port_rcv_constraint_errors = (u8)temp_64; 2950f48ad614SDennis Dalessandro 2951f48ad614SDennis Dalessandro /* LocalLink: 7:4, BufferOverrun: 3:0 */ 2952f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.local_link_integrity_errors); 2953f48ad614SDennis Dalessandro if (temp_64 > 0xFUL) 2954f48ad614SDennis Dalessandro temp_64 = 0xFUL; 2955f48ad614SDennis Dalessandro 2956f48ad614SDennis Dalessandro temp_link_overrun_errors = temp_64 << 4; 2957f48ad614SDennis Dalessandro 2958f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.excessive_buffer_overruns); 2959f48ad614SDennis Dalessandro if (temp_64 > 0xFUL) 2960f48ad614SDennis Dalessandro temp_64 = 0xFUL; 2961f48ad614SDennis Dalessandro temp_link_overrun_errors |= temp_64; 2962f48ad614SDennis Dalessandro 2963f48ad614SDennis Dalessandro p->link_overrun_errors = (u8)temp_link_overrun_errors; 2964f48ad614SDennis Dalessandro 2965f48ad614SDennis Dalessandro p->vl15_dropped = 0; /* N/A for OPA */ 2966f48ad614SDennis Dalessandro 2967f48ad614SDennis Dalessandro bail: 2968f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2969f48ad614SDennis Dalessandro } 2970f48ad614SDennis Dalessandro 2971f48ad614SDennis Dalessandro static int pma_get_opa_errorinfo(struct opa_pma_mad *pmp, 2972f48ad614SDennis Dalessandro struct ib_device *ibdev, 2973f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 2974f48ad614SDennis Dalessandro { 2975f48ad614SDennis Dalessandro size_t response_data_size; 2976f48ad614SDennis Dalessandro struct _port_ei *rsp; 2977f48ad614SDennis Dalessandro struct opa_port_error_info_msg *req; 2978f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2979f48ad614SDennis Dalessandro u64 port_mask; 2980f48ad614SDennis Dalessandro u32 num_ports; 2981f48ad614SDennis Dalessandro u8 port_num; 2982f48ad614SDennis Dalessandro u8 num_pslm; 2983f48ad614SDennis Dalessandro u64 reg; 2984f48ad614SDennis Dalessandro 2985f48ad614SDennis Dalessandro req = (struct opa_port_error_info_msg *)pmp->data; 2986f48ad614SDennis Dalessandro rsp = &req->port[0]; 2987f48ad614SDennis Dalessandro 2988f48ad614SDennis Dalessandro num_ports = OPA_AM_NPORT(be32_to_cpu(pmp->mad_hdr.attr_mod)); 2989f48ad614SDennis Dalessandro num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); 2990f48ad614SDennis Dalessandro 2991f48ad614SDennis Dalessandro memset(rsp, 0, sizeof(*rsp)); 2992f48ad614SDennis Dalessandro 2993f48ad614SDennis Dalessandro if (num_ports != 1 || num_ports != num_pslm) { 2994f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2995f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2996f48ad614SDennis Dalessandro } 2997f48ad614SDennis Dalessandro 2998f48ad614SDennis Dalessandro /* Sanity check */ 2999f48ad614SDennis Dalessandro response_data_size = sizeof(struct opa_port_error_info_msg); 3000f48ad614SDennis Dalessandro 3001f48ad614SDennis Dalessandro if (response_data_size > sizeof(pmp->data)) { 3002f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3003f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3004f48ad614SDennis Dalessandro } 3005f48ad614SDennis Dalessandro 3006f48ad614SDennis Dalessandro /* 3007f48ad614SDennis Dalessandro * The bit set in the mask needs to be consistent with the port 3008f48ad614SDennis Dalessandro * the request came in on. 3009f48ad614SDennis Dalessandro */ 3010f48ad614SDennis Dalessandro port_mask = be64_to_cpu(req->port_select_mask[3]); 3011f48ad614SDennis Dalessandro port_num = find_first_bit((unsigned long *)&port_mask, 30126aaa382fSChristophe Jaillet sizeof(port_mask) * 8); 3013f48ad614SDennis Dalessandro 3014f48ad614SDennis Dalessandro if (port_num != port) { 3015f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3016f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3017f48ad614SDennis Dalessandro } 3018f48ad614SDennis Dalessandro 3019f48ad614SDennis Dalessandro /* PortRcvErrorInfo */ 3020f48ad614SDennis Dalessandro rsp->port_rcv_ei.status_and_code = 3021f48ad614SDennis Dalessandro dd->err_info_rcvport.status_and_code; 3022f48ad614SDennis Dalessandro memcpy(&rsp->port_rcv_ei.ei.ei1to12.packet_flit1, 3023f48ad614SDennis Dalessandro &dd->err_info_rcvport.packet_flit1, sizeof(u64)); 3024f48ad614SDennis Dalessandro memcpy(&rsp->port_rcv_ei.ei.ei1to12.packet_flit2, 3025f48ad614SDennis Dalessandro &dd->err_info_rcvport.packet_flit2, sizeof(u64)); 3026f48ad614SDennis Dalessandro 3027f48ad614SDennis Dalessandro /* ExcessiverBufferOverrunInfo */ 3028f48ad614SDennis Dalessandro reg = read_csr(dd, RCV_ERR_INFO); 3029f48ad614SDennis Dalessandro if (reg & RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SMASK) { 3030f48ad614SDennis Dalessandro /* 3031f48ad614SDennis Dalessandro * if the RcvExcessBufferOverrun bit is set, save SC of 3032f48ad614SDennis Dalessandro * first pkt that encountered an excess buffer overrun 3033f48ad614SDennis Dalessandro */ 3034f48ad614SDennis Dalessandro u8 tmp = (u8)reg; 3035f48ad614SDennis Dalessandro 3036f48ad614SDennis Dalessandro tmp &= RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SC_SMASK; 3037f48ad614SDennis Dalessandro tmp <<= 2; 3038f48ad614SDennis Dalessandro rsp->excessive_buffer_overrun_ei.status_and_sc = tmp; 3039f48ad614SDennis Dalessandro /* set the status bit */ 3040f48ad614SDennis Dalessandro rsp->excessive_buffer_overrun_ei.status_and_sc |= 0x80; 3041f48ad614SDennis Dalessandro } 3042f48ad614SDennis Dalessandro 3043f48ad614SDennis Dalessandro rsp->port_xmit_constraint_ei.status = 3044f48ad614SDennis Dalessandro dd->err_info_xmit_constraint.status; 3045f48ad614SDennis Dalessandro rsp->port_xmit_constraint_ei.pkey = 3046f48ad614SDennis Dalessandro cpu_to_be16(dd->err_info_xmit_constraint.pkey); 3047f48ad614SDennis Dalessandro rsp->port_xmit_constraint_ei.slid = 3048f48ad614SDennis Dalessandro cpu_to_be32(dd->err_info_xmit_constraint.slid); 3049f48ad614SDennis Dalessandro 3050f48ad614SDennis Dalessandro rsp->port_rcv_constraint_ei.status = 3051f48ad614SDennis Dalessandro dd->err_info_rcv_constraint.status; 3052f48ad614SDennis Dalessandro rsp->port_rcv_constraint_ei.pkey = 3053f48ad614SDennis Dalessandro cpu_to_be16(dd->err_info_rcv_constraint.pkey); 3054f48ad614SDennis Dalessandro rsp->port_rcv_constraint_ei.slid = 3055f48ad614SDennis Dalessandro cpu_to_be32(dd->err_info_rcv_constraint.slid); 3056f48ad614SDennis Dalessandro 3057f48ad614SDennis Dalessandro /* UncorrectableErrorInfo */ 3058f48ad614SDennis Dalessandro rsp->uncorrectable_ei.status_and_code = dd->err_info_uncorrectable; 3059f48ad614SDennis Dalessandro 3060f48ad614SDennis Dalessandro /* FMConfigErrorInfo */ 3061f48ad614SDennis Dalessandro rsp->fm_config_ei.status_and_code = dd->err_info_fmconfig; 3062f48ad614SDennis Dalessandro 3063f48ad614SDennis Dalessandro if (resp_len) 3064f48ad614SDennis Dalessandro *resp_len += response_data_size; 3065f48ad614SDennis Dalessandro 3066f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3067f48ad614SDennis Dalessandro } 3068f48ad614SDennis Dalessandro 3069f48ad614SDennis Dalessandro static int pma_set_opa_portstatus(struct opa_pma_mad *pmp, 3070f48ad614SDennis Dalessandro struct ib_device *ibdev, 3071f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 3072f48ad614SDennis Dalessandro { 3073f48ad614SDennis Dalessandro struct opa_clear_port_status *req = 3074f48ad614SDennis Dalessandro (struct opa_clear_port_status *)pmp->data; 3075f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 3076f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3077f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3078f48ad614SDennis Dalessandro u32 nports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; 3079f48ad614SDennis Dalessandro u64 portn = be64_to_cpu(req->port_select_mask[3]); 3080f48ad614SDennis Dalessandro u32 counter_select = be32_to_cpu(req->counter_select_mask); 3081f48ad614SDennis Dalessandro u32 vl_select_mask = VL_MASK_ALL; /* clear all per-vl cnts */ 3082f48ad614SDennis Dalessandro unsigned long vl; 3083f48ad614SDennis Dalessandro 3084f48ad614SDennis Dalessandro if ((nports != 1) || (portn != 1 << port)) { 3085f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3086f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3087f48ad614SDennis Dalessandro } 3088f48ad614SDennis Dalessandro /* 3089f48ad614SDennis Dalessandro * only counters returned by pma_get_opa_portstatus() are 3090f48ad614SDennis Dalessandro * handled, so when pma_get_opa_portstatus() gets a fix, 3091f48ad614SDennis Dalessandro * the corresponding change should be made here as well. 3092f48ad614SDennis Dalessandro */ 3093f48ad614SDennis Dalessandro 3094f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_DATA) 3095f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_XMIT_FLITS, CNTR_INVALID_VL, 0); 3096f48ad614SDennis Dalessandro 3097f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_DATA) 3098f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_FLITS, CNTR_INVALID_VL, 0); 3099f48ad614SDennis Dalessandro 3100f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_PKTS) 3101f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_XMIT_PKTS, CNTR_INVALID_VL, 0); 3102f48ad614SDennis Dalessandro 3103f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_PKTS) 3104f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_PKTS, CNTR_INVALID_VL, 0); 3105f48ad614SDennis Dalessandro 3106f48ad614SDennis Dalessandro if (counter_select & CS_PORT_MCAST_XMIT_PKTS) 3107f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_MC_XMIT_PKTS, CNTR_INVALID_VL, 0); 3108f48ad614SDennis Dalessandro 3109f48ad614SDennis Dalessandro if (counter_select & CS_PORT_MCAST_RCV_PKTS) 3110f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_MC_RCV_PKTS, CNTR_INVALID_VL, 0); 3111f48ad614SDennis Dalessandro 3112f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_WAIT) 3113f48ad614SDennis Dalessandro write_port_cntr(ppd, C_TX_WAIT, CNTR_INVALID_VL, 0); 3114f48ad614SDennis Dalessandro 3115f48ad614SDennis Dalessandro /* ignore cs_sw_portCongestion for HFIs */ 3116f48ad614SDennis Dalessandro 3117f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_FECN) 3118f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_FCN, CNTR_INVALID_VL, 0); 3119f48ad614SDennis Dalessandro 3120f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_BECN) 3121f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL, 0); 3122f48ad614SDennis Dalessandro 3123f48ad614SDennis Dalessandro /* ignore cs_port_xmit_time_cong for HFIs */ 3124f48ad614SDennis Dalessandro /* ignore cs_port_xmit_wasted_bw for now */ 3125f48ad614SDennis Dalessandro /* ignore cs_port_xmit_wait_data for now */ 3126f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_BUBBLE) 3127f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_BBL, CNTR_INVALID_VL, 0); 3128f48ad614SDennis Dalessandro 3129f48ad614SDennis Dalessandro /* Only applicable for switch */ 3130f48ad614SDennis Dalessandro /* if (counter_select & CS_PORT_MARK_FECN) 3131f48ad614SDennis Dalessandro * write_csr(dd, DCC_PRF_PORT_MARK_FECN_CNT, 0); 3132f48ad614SDennis Dalessandro */ 3133f48ad614SDennis Dalessandro 3134f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_CONSTRAINT_ERRORS) 3135f48ad614SDennis Dalessandro write_port_cntr(ppd, C_SW_RCV_CSTR_ERR, CNTR_INVALID_VL, 0); 3136f48ad614SDennis Dalessandro 3137f48ad614SDennis Dalessandro /* ignore cs_port_rcv_switch_relay_errors for HFIs */ 3138f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_DISCARDS) 3139f48ad614SDennis Dalessandro write_port_cntr(ppd, C_SW_XMIT_DSCD, CNTR_INVALID_VL, 0); 3140f48ad614SDennis Dalessandro 3141f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_CONSTRAINT_ERRORS) 3142f48ad614SDennis Dalessandro write_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, CNTR_INVALID_VL, 0); 3143f48ad614SDennis Dalessandro 3144f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_REMOTE_PHYSICAL_ERRORS) 3145f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RMT_PHY_ERR, CNTR_INVALID_VL, 0); 3146f48ad614SDennis Dalessandro 31473210314aSJakub Pawlak if (counter_select & CS_LOCAL_LINK_INTEGRITY_ERRORS) 3148f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0); 3149f48ad614SDennis Dalessandro 3150f48ad614SDennis Dalessandro if (counter_select & CS_LINK_ERROR_RECOVERY) { 3151f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0); 3152f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, 3153f48ad614SDennis Dalessandro CNTR_INVALID_VL, 0); 3154f48ad614SDennis Dalessandro } 3155f48ad614SDennis Dalessandro 3156f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_ERRORS) 3157f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL, 0); 3158f48ad614SDennis Dalessandro 3159f48ad614SDennis Dalessandro if (counter_select & CS_EXCESSIVE_BUFFER_OVERRUNS) { 3160f48ad614SDennis Dalessandro write_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL, 0); 3161f48ad614SDennis Dalessandro dd->rcv_ovfl_cnt = 0; 3162f48ad614SDennis Dalessandro } 3163f48ad614SDennis Dalessandro 3164f48ad614SDennis Dalessandro if (counter_select & CS_FM_CONFIG_ERRORS) 3165f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_FM_CFG_ERR, CNTR_INVALID_VL, 0); 3166f48ad614SDennis Dalessandro 3167f48ad614SDennis Dalessandro if (counter_select & CS_LINK_DOWNED) 3168f48ad614SDennis Dalessandro write_port_cntr(ppd, C_SW_LINK_DOWN, CNTR_INVALID_VL, 0); 3169f48ad614SDennis Dalessandro 3170f48ad614SDennis Dalessandro if (counter_select & CS_UNCORRECTABLE_ERRORS) 3171f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL, 0); 3172f48ad614SDennis Dalessandro 3173f48ad614SDennis Dalessandro for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), 3174f48ad614SDennis Dalessandro 8 * sizeof(vl_select_mask)) { 3175f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_DATA) 3176f48ad614SDennis Dalessandro write_port_cntr(ppd, C_TX_FLIT_VL, idx_from_vl(vl), 0); 3177f48ad614SDennis Dalessandro 3178f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_DATA) 3179f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RX_FLIT_VL, idx_from_vl(vl), 0); 3180f48ad614SDennis Dalessandro 3181f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_PKTS) 3182f48ad614SDennis Dalessandro write_port_cntr(ppd, C_TX_PKT_VL, idx_from_vl(vl), 0); 3183f48ad614SDennis Dalessandro 3184f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_PKTS) 3185f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RX_PKT_VL, idx_from_vl(vl), 0); 3186f48ad614SDennis Dalessandro 3187f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_WAIT) 3188f48ad614SDennis Dalessandro write_port_cntr(ppd, C_TX_WAIT_VL, idx_from_vl(vl), 0); 3189f48ad614SDennis Dalessandro 3190f48ad614SDennis Dalessandro /* sw_port_vl_congestion is 0 for HFIs */ 3191f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_FECN) 3192f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_FCN_VL, idx_from_vl(vl), 0); 3193f48ad614SDennis Dalessandro 3194f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_BECN) 3195f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_BCN_VL, idx_from_vl(vl), 0); 3196f48ad614SDennis Dalessandro 3197f48ad614SDennis Dalessandro /* port_vl_xmit_time_cong is 0 for HFIs */ 3198f48ad614SDennis Dalessandro /* port_vl_xmit_wasted_bw ??? */ 3199f48ad614SDennis Dalessandro /* port_vl_xmit_wait_data - TXE (table 13-9 HFI spec) ??? */ 3200f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_BUBBLE) 3201f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_BBL_VL, idx_from_vl(vl), 0); 3202f48ad614SDennis Dalessandro 3203f48ad614SDennis Dalessandro /* if (counter_select & CS_PORT_MARK_FECN) 3204f48ad614SDennis Dalessandro * write_csr(dd, DCC_PRF_PORT_VL_MARK_FECN_CNT + offset, 0); 3205f48ad614SDennis Dalessandro */ 3206583eb8b8SJakub Pawlak if (counter_select & C_SW_XMIT_DSCD_VL) 3207583eb8b8SJakub Pawlak write_port_cntr(ppd, C_SW_XMIT_DSCD_VL, 3208583eb8b8SJakub Pawlak idx_from_vl(vl), 0); 3209f48ad614SDennis Dalessandro } 3210f48ad614SDennis Dalessandro 3211f48ad614SDennis Dalessandro if (resp_len) 3212f48ad614SDennis Dalessandro *resp_len += sizeof(*req); 3213f48ad614SDennis Dalessandro 3214f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3215f48ad614SDennis Dalessandro } 3216f48ad614SDennis Dalessandro 3217f48ad614SDennis Dalessandro static int pma_set_opa_errorinfo(struct opa_pma_mad *pmp, 3218f48ad614SDennis Dalessandro struct ib_device *ibdev, 3219f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 3220f48ad614SDennis Dalessandro { 3221f48ad614SDennis Dalessandro struct _port_ei *rsp; 3222f48ad614SDennis Dalessandro struct opa_port_error_info_msg *req; 3223f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 3224f48ad614SDennis Dalessandro u64 port_mask; 3225f48ad614SDennis Dalessandro u32 num_ports; 3226f48ad614SDennis Dalessandro u8 port_num; 3227f48ad614SDennis Dalessandro u8 num_pslm; 3228f48ad614SDennis Dalessandro u32 error_info_select; 3229f48ad614SDennis Dalessandro 3230f48ad614SDennis Dalessandro req = (struct opa_port_error_info_msg *)pmp->data; 3231f48ad614SDennis Dalessandro rsp = &req->port[0]; 3232f48ad614SDennis Dalessandro 3233f48ad614SDennis Dalessandro num_ports = OPA_AM_NPORT(be32_to_cpu(pmp->mad_hdr.attr_mod)); 3234f48ad614SDennis Dalessandro num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); 3235f48ad614SDennis Dalessandro 3236f48ad614SDennis Dalessandro memset(rsp, 0, sizeof(*rsp)); 3237f48ad614SDennis Dalessandro 3238f48ad614SDennis Dalessandro if (num_ports != 1 || num_ports != num_pslm) { 3239f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3240f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3241f48ad614SDennis Dalessandro } 3242f48ad614SDennis Dalessandro 3243f48ad614SDennis Dalessandro /* 3244f48ad614SDennis Dalessandro * The bit set in the mask needs to be consistent with the port 3245f48ad614SDennis Dalessandro * the request came in on. 3246f48ad614SDennis Dalessandro */ 3247f48ad614SDennis Dalessandro port_mask = be64_to_cpu(req->port_select_mask[3]); 3248f48ad614SDennis Dalessandro port_num = find_first_bit((unsigned long *)&port_mask, 32496aaa382fSChristophe Jaillet sizeof(port_mask) * 8); 3250f48ad614SDennis Dalessandro 3251f48ad614SDennis Dalessandro if (port_num != port) { 3252f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3253f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3254f48ad614SDennis Dalessandro } 3255f48ad614SDennis Dalessandro 3256f48ad614SDennis Dalessandro error_info_select = be32_to_cpu(req->error_info_select_mask); 3257f48ad614SDennis Dalessandro 3258f48ad614SDennis Dalessandro /* PortRcvErrorInfo */ 3259f48ad614SDennis Dalessandro if (error_info_select & ES_PORT_RCV_ERROR_INFO) 3260f48ad614SDennis Dalessandro /* turn off status bit */ 3261f48ad614SDennis Dalessandro dd->err_info_rcvport.status_and_code &= ~OPA_EI_STATUS_SMASK; 3262f48ad614SDennis Dalessandro 3263f48ad614SDennis Dalessandro /* ExcessiverBufferOverrunInfo */ 3264f48ad614SDennis Dalessandro if (error_info_select & ES_EXCESSIVE_BUFFER_OVERRUN_INFO) 3265f48ad614SDennis Dalessandro /* 3266f48ad614SDennis Dalessandro * status bit is essentially kept in the h/w - bit 5 of 3267f48ad614SDennis Dalessandro * RCV_ERR_INFO 3268f48ad614SDennis Dalessandro */ 3269f48ad614SDennis Dalessandro write_csr(dd, RCV_ERR_INFO, 3270f48ad614SDennis Dalessandro RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SMASK); 3271f48ad614SDennis Dalessandro 3272f48ad614SDennis Dalessandro if (error_info_select & ES_PORT_XMIT_CONSTRAINT_ERROR_INFO) 3273f48ad614SDennis Dalessandro dd->err_info_xmit_constraint.status &= ~OPA_EI_STATUS_SMASK; 3274f48ad614SDennis Dalessandro 3275f48ad614SDennis Dalessandro if (error_info_select & ES_PORT_RCV_CONSTRAINT_ERROR_INFO) 3276f48ad614SDennis Dalessandro dd->err_info_rcv_constraint.status &= ~OPA_EI_STATUS_SMASK; 3277f48ad614SDennis Dalessandro 3278f48ad614SDennis Dalessandro /* UncorrectableErrorInfo */ 3279f48ad614SDennis Dalessandro if (error_info_select & ES_UNCORRECTABLE_ERROR_INFO) 3280f48ad614SDennis Dalessandro /* turn off status bit */ 3281f48ad614SDennis Dalessandro dd->err_info_uncorrectable &= ~OPA_EI_STATUS_SMASK; 3282f48ad614SDennis Dalessandro 3283f48ad614SDennis Dalessandro /* FMConfigErrorInfo */ 3284f48ad614SDennis Dalessandro if (error_info_select & ES_FM_CONFIG_ERROR_INFO) 3285f48ad614SDennis Dalessandro /* turn off status bit */ 3286f48ad614SDennis Dalessandro dd->err_info_fmconfig &= ~OPA_EI_STATUS_SMASK; 3287f48ad614SDennis Dalessandro 3288f48ad614SDennis Dalessandro if (resp_len) 3289f48ad614SDennis Dalessandro *resp_len += sizeof(*req); 3290f48ad614SDennis Dalessandro 3291f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3292f48ad614SDennis Dalessandro } 3293f48ad614SDennis Dalessandro 3294f48ad614SDennis Dalessandro struct opa_congestion_info_attr { 3295f48ad614SDennis Dalessandro __be16 congestion_info; 3296f48ad614SDennis Dalessandro u8 control_table_cap; /* Multiple of 64 entry unit CCTs */ 3297f48ad614SDennis Dalessandro u8 congestion_log_length; 3298f48ad614SDennis Dalessandro } __packed; 3299f48ad614SDennis Dalessandro 3300f48ad614SDennis Dalessandro static int __subn_get_opa_cong_info(struct opa_smp *smp, u32 am, u8 *data, 3301f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3302f48ad614SDennis Dalessandro u32 *resp_len) 3303f48ad614SDennis Dalessandro { 3304f48ad614SDennis Dalessandro struct opa_congestion_info_attr *p = 3305f48ad614SDennis Dalessandro (struct opa_congestion_info_attr *)data; 3306f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3307f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3308f48ad614SDennis Dalessandro 3309f48ad614SDennis Dalessandro p->congestion_info = 0; 3310f48ad614SDennis Dalessandro p->control_table_cap = ppd->cc_max_table_entries; 3311f48ad614SDennis Dalessandro p->congestion_log_length = OPA_CONG_LOG_ELEMS; 3312f48ad614SDennis Dalessandro 3313f48ad614SDennis Dalessandro if (resp_len) 3314f48ad614SDennis Dalessandro *resp_len += sizeof(*p); 3315f48ad614SDennis Dalessandro 3316f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3317f48ad614SDennis Dalessandro } 3318f48ad614SDennis Dalessandro 3319f48ad614SDennis Dalessandro static int __subn_get_opa_cong_setting(struct opa_smp *smp, u32 am, 3320f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, 3321f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 3322f48ad614SDennis Dalessandro { 3323f48ad614SDennis Dalessandro int i; 3324f48ad614SDennis Dalessandro struct opa_congestion_setting_attr *p = 3325f48ad614SDennis Dalessandro (struct opa_congestion_setting_attr *)data; 3326f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3327f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3328f48ad614SDennis Dalessandro struct opa_congestion_setting_entry_shadow *entries; 3329f48ad614SDennis Dalessandro struct cc_state *cc_state; 3330f48ad614SDennis Dalessandro 3331f48ad614SDennis Dalessandro rcu_read_lock(); 3332f48ad614SDennis Dalessandro 3333f48ad614SDennis Dalessandro cc_state = get_cc_state(ppd); 3334f48ad614SDennis Dalessandro 3335f48ad614SDennis Dalessandro if (!cc_state) { 3336f48ad614SDennis Dalessandro rcu_read_unlock(); 3337f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3338f48ad614SDennis Dalessandro } 3339f48ad614SDennis Dalessandro 3340f48ad614SDennis Dalessandro entries = cc_state->cong_setting.entries; 3341f48ad614SDennis Dalessandro p->port_control = cpu_to_be16(cc_state->cong_setting.port_control); 3342f48ad614SDennis Dalessandro p->control_map = cpu_to_be32(cc_state->cong_setting.control_map); 3343f48ad614SDennis Dalessandro for (i = 0; i < OPA_MAX_SLS; i++) { 3344f48ad614SDennis Dalessandro p->entries[i].ccti_increase = entries[i].ccti_increase; 3345f48ad614SDennis Dalessandro p->entries[i].ccti_timer = cpu_to_be16(entries[i].ccti_timer); 3346f48ad614SDennis Dalessandro p->entries[i].trigger_threshold = 3347f48ad614SDennis Dalessandro entries[i].trigger_threshold; 3348f48ad614SDennis Dalessandro p->entries[i].ccti_min = entries[i].ccti_min; 3349f48ad614SDennis Dalessandro } 3350f48ad614SDennis Dalessandro 3351f48ad614SDennis Dalessandro rcu_read_unlock(); 3352f48ad614SDennis Dalessandro 3353f48ad614SDennis Dalessandro if (resp_len) 3354f48ad614SDennis Dalessandro *resp_len += sizeof(*p); 3355f48ad614SDennis Dalessandro 3356f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3357f48ad614SDennis Dalessandro } 3358f48ad614SDennis Dalessandro 3359f48ad614SDennis Dalessandro /* 3360f48ad614SDennis Dalessandro * Apply congestion control information stored in the ppd to the 3361f48ad614SDennis Dalessandro * active structure. 3362f48ad614SDennis Dalessandro */ 3363f48ad614SDennis Dalessandro static void apply_cc_state(struct hfi1_pportdata *ppd) 3364f48ad614SDennis Dalessandro { 3365f48ad614SDennis Dalessandro struct cc_state *old_cc_state, *new_cc_state; 3366f48ad614SDennis Dalessandro 3367f48ad614SDennis Dalessandro new_cc_state = kzalloc(sizeof(*new_cc_state), GFP_KERNEL); 3368f48ad614SDennis Dalessandro if (!new_cc_state) 3369f48ad614SDennis Dalessandro return; 3370f48ad614SDennis Dalessandro 3371f48ad614SDennis Dalessandro /* 3372f48ad614SDennis Dalessandro * Hold the lock for updating *and* to prevent ppd information 3373f48ad614SDennis Dalessandro * from changing during the update. 3374f48ad614SDennis Dalessandro */ 3375f48ad614SDennis Dalessandro spin_lock(&ppd->cc_state_lock); 3376f48ad614SDennis Dalessandro 33778adf71faSJianxin Xiong old_cc_state = get_cc_state_protected(ppd); 3378f48ad614SDennis Dalessandro if (!old_cc_state) { 3379f48ad614SDennis Dalessandro /* never active, or shutting down */ 3380f48ad614SDennis Dalessandro spin_unlock(&ppd->cc_state_lock); 3381f48ad614SDennis Dalessandro kfree(new_cc_state); 3382f48ad614SDennis Dalessandro return; 3383f48ad614SDennis Dalessandro } 3384f48ad614SDennis Dalessandro 3385f48ad614SDennis Dalessandro *new_cc_state = *old_cc_state; 3386f48ad614SDennis Dalessandro 3387f48ad614SDennis Dalessandro new_cc_state->cct.ccti_limit = ppd->total_cct_entry - 1; 3388f48ad614SDennis Dalessandro memcpy(new_cc_state->cct.entries, ppd->ccti_entries, 3389f48ad614SDennis Dalessandro ppd->total_cct_entry * sizeof(struct ib_cc_table_entry)); 3390f48ad614SDennis Dalessandro 3391f48ad614SDennis Dalessandro new_cc_state->cong_setting.port_control = IB_CC_CCS_PC_SL_BASED; 3392f48ad614SDennis Dalessandro new_cc_state->cong_setting.control_map = ppd->cc_sl_control_map; 3393f48ad614SDennis Dalessandro memcpy(new_cc_state->cong_setting.entries, ppd->congestion_entries, 3394f48ad614SDennis Dalessandro OPA_MAX_SLS * sizeof(struct opa_congestion_setting_entry)); 3395f48ad614SDennis Dalessandro 3396f48ad614SDennis Dalessandro rcu_assign_pointer(ppd->cc_state, new_cc_state); 3397f48ad614SDennis Dalessandro 3398f48ad614SDennis Dalessandro spin_unlock(&ppd->cc_state_lock); 3399f48ad614SDennis Dalessandro 3400476d95bdSWei Yongjun kfree_rcu(old_cc_state, rcu); 3401f48ad614SDennis Dalessandro } 3402f48ad614SDennis Dalessandro 3403f48ad614SDennis Dalessandro static int __subn_set_opa_cong_setting(struct opa_smp *smp, u32 am, u8 *data, 3404f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3405f48ad614SDennis Dalessandro u32 *resp_len) 3406f48ad614SDennis Dalessandro { 3407f48ad614SDennis Dalessandro struct opa_congestion_setting_attr *p = 3408f48ad614SDennis Dalessandro (struct opa_congestion_setting_attr *)data; 3409f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3410f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3411f48ad614SDennis Dalessandro struct opa_congestion_setting_entry_shadow *entries; 3412f48ad614SDennis Dalessandro int i; 3413f48ad614SDennis Dalessandro 3414f48ad614SDennis Dalessandro /* 3415f48ad614SDennis Dalessandro * Save details from packet into the ppd. Hold the cc_state_lock so 3416f48ad614SDennis Dalessandro * our information is consistent with anyone trying to apply the state. 3417f48ad614SDennis Dalessandro */ 3418f48ad614SDennis Dalessandro spin_lock(&ppd->cc_state_lock); 3419f48ad614SDennis Dalessandro ppd->cc_sl_control_map = be32_to_cpu(p->control_map); 3420f48ad614SDennis Dalessandro 3421f48ad614SDennis Dalessandro entries = ppd->congestion_entries; 3422f48ad614SDennis Dalessandro for (i = 0; i < OPA_MAX_SLS; i++) { 3423f48ad614SDennis Dalessandro entries[i].ccti_increase = p->entries[i].ccti_increase; 3424f48ad614SDennis Dalessandro entries[i].ccti_timer = be16_to_cpu(p->entries[i].ccti_timer); 3425f48ad614SDennis Dalessandro entries[i].trigger_threshold = 3426f48ad614SDennis Dalessandro p->entries[i].trigger_threshold; 3427f48ad614SDennis Dalessandro entries[i].ccti_min = p->entries[i].ccti_min; 3428f48ad614SDennis Dalessandro } 3429f48ad614SDennis Dalessandro spin_unlock(&ppd->cc_state_lock); 3430f48ad614SDennis Dalessandro 3431f48ad614SDennis Dalessandro /* now apply the information */ 3432f48ad614SDennis Dalessandro apply_cc_state(ppd); 3433f48ad614SDennis Dalessandro 3434f48ad614SDennis Dalessandro return __subn_get_opa_cong_setting(smp, am, data, ibdev, port, 3435f48ad614SDennis Dalessandro resp_len); 3436f48ad614SDennis Dalessandro } 3437f48ad614SDennis Dalessandro 3438f48ad614SDennis Dalessandro static int __subn_get_opa_hfi1_cong_log(struct opa_smp *smp, u32 am, 3439f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, 3440f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 3441f48ad614SDennis Dalessandro { 3442f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3443f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3444f48ad614SDennis Dalessandro struct opa_hfi1_cong_log *cong_log = (struct opa_hfi1_cong_log *)data; 3445f48ad614SDennis Dalessandro s64 ts; 3446f48ad614SDennis Dalessandro int i; 3447f48ad614SDennis Dalessandro 3448f48ad614SDennis Dalessandro if (am != 0) { 3449f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3450f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3451f48ad614SDennis Dalessandro } 3452f48ad614SDennis Dalessandro 3453f48ad614SDennis Dalessandro spin_lock_irq(&ppd->cc_log_lock); 3454f48ad614SDennis Dalessandro 3455f48ad614SDennis Dalessandro cong_log->log_type = OPA_CC_LOG_TYPE_HFI; 3456f48ad614SDennis Dalessandro cong_log->congestion_flags = 0; 3457f48ad614SDennis Dalessandro cong_log->threshold_event_counter = 3458f48ad614SDennis Dalessandro cpu_to_be16(ppd->threshold_event_counter); 3459f48ad614SDennis Dalessandro memcpy(cong_log->threshold_cong_event_map, 3460f48ad614SDennis Dalessandro ppd->threshold_cong_event_map, 3461f48ad614SDennis Dalessandro sizeof(cong_log->threshold_cong_event_map)); 3462f48ad614SDennis Dalessandro /* keep timestamp in units of 1.024 usec */ 3463f48ad614SDennis Dalessandro ts = ktime_to_ns(ktime_get()) / 1024; 3464f48ad614SDennis Dalessandro cong_log->current_time_stamp = cpu_to_be32(ts); 3465f48ad614SDennis Dalessandro for (i = 0; i < OPA_CONG_LOG_ELEMS; i++) { 3466f48ad614SDennis Dalessandro struct opa_hfi1_cong_log_event_internal *cce = 3467f48ad614SDennis Dalessandro &ppd->cc_events[ppd->cc_mad_idx++]; 3468f48ad614SDennis Dalessandro if (ppd->cc_mad_idx == OPA_CONG_LOG_ELEMS) 3469f48ad614SDennis Dalessandro ppd->cc_mad_idx = 0; 3470f48ad614SDennis Dalessandro /* 3471f48ad614SDennis Dalessandro * Entries which are older than twice the time 3472f48ad614SDennis Dalessandro * required to wrap the counter are supposed to 3473f48ad614SDennis Dalessandro * be zeroed (CA10-49 IBTA, release 1.2.1, V1). 3474f48ad614SDennis Dalessandro */ 3475f48ad614SDennis Dalessandro if ((u64)(ts - cce->timestamp) > (2 * UINT_MAX)) 3476f48ad614SDennis Dalessandro continue; 3477f48ad614SDennis Dalessandro memcpy(cong_log->events[i].local_qp_cn_entry, &cce->lqpn, 3); 3478f48ad614SDennis Dalessandro memcpy(cong_log->events[i].remote_qp_number_cn_entry, 3479f48ad614SDennis Dalessandro &cce->rqpn, 3); 3480f48ad614SDennis Dalessandro cong_log->events[i].sl_svc_type_cn_entry = 3481f48ad614SDennis Dalessandro ((cce->sl & 0x1f) << 3) | (cce->svc_type & 0x7); 3482f48ad614SDennis Dalessandro cong_log->events[i].remote_lid_cn_entry = 3483f48ad614SDennis Dalessandro cpu_to_be32(cce->rlid); 3484f48ad614SDennis Dalessandro cong_log->events[i].timestamp_cn_entry = 3485f48ad614SDennis Dalessandro cpu_to_be32(cce->timestamp); 3486f48ad614SDennis Dalessandro } 3487f48ad614SDennis Dalessandro 3488f48ad614SDennis Dalessandro /* 3489f48ad614SDennis Dalessandro * Reset threshold_cong_event_map, and threshold_event_counter 3490f48ad614SDennis Dalessandro * to 0 when log is read. 3491f48ad614SDennis Dalessandro */ 3492f48ad614SDennis Dalessandro memset(ppd->threshold_cong_event_map, 0x0, 3493f48ad614SDennis Dalessandro sizeof(ppd->threshold_cong_event_map)); 3494f48ad614SDennis Dalessandro ppd->threshold_event_counter = 0; 3495f48ad614SDennis Dalessandro 3496f48ad614SDennis Dalessandro spin_unlock_irq(&ppd->cc_log_lock); 3497f48ad614SDennis Dalessandro 3498f48ad614SDennis Dalessandro if (resp_len) 3499f48ad614SDennis Dalessandro *resp_len += sizeof(struct opa_hfi1_cong_log); 3500f48ad614SDennis Dalessandro 3501f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3502f48ad614SDennis Dalessandro } 3503f48ad614SDennis Dalessandro 3504f48ad614SDennis Dalessandro static int __subn_get_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data, 3505f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3506f48ad614SDennis Dalessandro u32 *resp_len) 3507f48ad614SDennis Dalessandro { 3508f48ad614SDennis Dalessandro struct ib_cc_table_attr *cc_table_attr = 3509f48ad614SDennis Dalessandro (struct ib_cc_table_attr *)data; 3510f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3511f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3512f48ad614SDennis Dalessandro u32 start_block = OPA_AM_START_BLK(am); 3513f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NBLK(am); 3514f48ad614SDennis Dalessandro struct ib_cc_table_entry_shadow *entries; 3515f48ad614SDennis Dalessandro int i, j; 3516f48ad614SDennis Dalessandro u32 sentry, eentry; 3517f48ad614SDennis Dalessandro struct cc_state *cc_state; 3518f48ad614SDennis Dalessandro 3519f48ad614SDennis Dalessandro /* sanity check n_blocks, start_block */ 3520f48ad614SDennis Dalessandro if (n_blocks == 0 || 3521f48ad614SDennis Dalessandro start_block + n_blocks > ppd->cc_max_table_entries) { 3522f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3523f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3524f48ad614SDennis Dalessandro } 3525f48ad614SDennis Dalessandro 3526f48ad614SDennis Dalessandro rcu_read_lock(); 3527f48ad614SDennis Dalessandro 3528f48ad614SDennis Dalessandro cc_state = get_cc_state(ppd); 3529f48ad614SDennis Dalessandro 3530f48ad614SDennis Dalessandro if (!cc_state) { 3531f48ad614SDennis Dalessandro rcu_read_unlock(); 3532f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3533f48ad614SDennis Dalessandro } 3534f48ad614SDennis Dalessandro 3535f48ad614SDennis Dalessandro sentry = start_block * IB_CCT_ENTRIES; 3536f48ad614SDennis Dalessandro eentry = sentry + (IB_CCT_ENTRIES * n_blocks); 3537f48ad614SDennis Dalessandro 3538f48ad614SDennis Dalessandro cc_table_attr->ccti_limit = cpu_to_be16(cc_state->cct.ccti_limit); 3539f48ad614SDennis Dalessandro 3540f48ad614SDennis Dalessandro entries = cc_state->cct.entries; 3541f48ad614SDennis Dalessandro 3542f48ad614SDennis Dalessandro /* return n_blocks, though the last block may not be full */ 3543f48ad614SDennis Dalessandro for (j = 0, i = sentry; i < eentry; j++, i++) 3544f48ad614SDennis Dalessandro cc_table_attr->ccti_entries[j].entry = 3545f48ad614SDennis Dalessandro cpu_to_be16(entries[i].entry); 3546f48ad614SDennis Dalessandro 3547f48ad614SDennis Dalessandro rcu_read_unlock(); 3548f48ad614SDennis Dalessandro 3549f48ad614SDennis Dalessandro if (resp_len) 3550f48ad614SDennis Dalessandro *resp_len += sizeof(u16) * (IB_CCT_ENTRIES * n_blocks + 1); 3551f48ad614SDennis Dalessandro 3552f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3553f48ad614SDennis Dalessandro } 3554f48ad614SDennis Dalessandro 3555f48ad614SDennis Dalessandro static int __subn_set_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data, 3556f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3557f48ad614SDennis Dalessandro u32 *resp_len) 3558f48ad614SDennis Dalessandro { 3559f48ad614SDennis Dalessandro struct ib_cc_table_attr *p = (struct ib_cc_table_attr *)data; 3560f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3561f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3562f48ad614SDennis Dalessandro u32 start_block = OPA_AM_START_BLK(am); 3563f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NBLK(am); 3564f48ad614SDennis Dalessandro struct ib_cc_table_entry_shadow *entries; 3565f48ad614SDennis Dalessandro int i, j; 3566f48ad614SDennis Dalessandro u32 sentry, eentry; 3567f48ad614SDennis Dalessandro u16 ccti_limit; 3568f48ad614SDennis Dalessandro 3569f48ad614SDennis Dalessandro /* sanity check n_blocks, start_block */ 3570f48ad614SDennis Dalessandro if (n_blocks == 0 || 3571f48ad614SDennis Dalessandro start_block + n_blocks > ppd->cc_max_table_entries) { 3572f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3573f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3574f48ad614SDennis Dalessandro } 3575f48ad614SDennis Dalessandro 3576f48ad614SDennis Dalessandro sentry = start_block * IB_CCT_ENTRIES; 3577f48ad614SDennis Dalessandro eentry = sentry + ((n_blocks - 1) * IB_CCT_ENTRIES) + 3578f48ad614SDennis Dalessandro (be16_to_cpu(p->ccti_limit)) % IB_CCT_ENTRIES + 1; 3579f48ad614SDennis Dalessandro 3580f48ad614SDennis Dalessandro /* sanity check ccti_limit */ 3581f48ad614SDennis Dalessandro ccti_limit = be16_to_cpu(p->ccti_limit); 3582f48ad614SDennis Dalessandro if (ccti_limit + 1 > eentry) { 3583f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3584f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3585f48ad614SDennis Dalessandro } 3586f48ad614SDennis Dalessandro 3587f48ad614SDennis Dalessandro /* 3588f48ad614SDennis Dalessandro * Save details from packet into the ppd. Hold the cc_state_lock so 3589f48ad614SDennis Dalessandro * our information is consistent with anyone trying to apply the state. 3590f48ad614SDennis Dalessandro */ 3591f48ad614SDennis Dalessandro spin_lock(&ppd->cc_state_lock); 3592f48ad614SDennis Dalessandro ppd->total_cct_entry = ccti_limit + 1; 3593f48ad614SDennis Dalessandro entries = ppd->ccti_entries; 3594f48ad614SDennis Dalessandro for (j = 0, i = sentry; i < eentry; j++, i++) 3595f48ad614SDennis Dalessandro entries[i].entry = be16_to_cpu(p->ccti_entries[j].entry); 3596f48ad614SDennis Dalessandro spin_unlock(&ppd->cc_state_lock); 3597f48ad614SDennis Dalessandro 3598f48ad614SDennis Dalessandro /* now apply the information */ 3599f48ad614SDennis Dalessandro apply_cc_state(ppd); 3600f48ad614SDennis Dalessandro 3601f48ad614SDennis Dalessandro return __subn_get_opa_cc_table(smp, am, data, ibdev, port, resp_len); 3602f48ad614SDennis Dalessandro } 3603f48ad614SDennis Dalessandro 3604f48ad614SDennis Dalessandro struct opa_led_info { 3605f48ad614SDennis Dalessandro __be32 rsvd_led_mask; 3606f48ad614SDennis Dalessandro __be32 rsvd; 3607f48ad614SDennis Dalessandro }; 3608f48ad614SDennis Dalessandro 3609f48ad614SDennis Dalessandro #define OPA_LED_SHIFT 31 3610f48ad614SDennis Dalessandro #define OPA_LED_MASK BIT(OPA_LED_SHIFT) 3611f48ad614SDennis Dalessandro 3612f48ad614SDennis Dalessandro static int __subn_get_opa_led_info(struct opa_smp *smp, u32 am, u8 *data, 3613f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3614f48ad614SDennis Dalessandro u32 *resp_len) 3615f48ad614SDennis Dalessandro { 3616f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 3617f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = dd->pport; 3618f48ad614SDennis Dalessandro struct opa_led_info *p = (struct opa_led_info *)data; 3619f48ad614SDennis Dalessandro u32 nport = OPA_AM_NPORT(am); 3620f48ad614SDennis Dalessandro u32 is_beaconing_active; 3621f48ad614SDennis Dalessandro 3622f48ad614SDennis Dalessandro if (nport != 1) { 3623f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3624f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3625f48ad614SDennis Dalessandro } 3626f48ad614SDennis Dalessandro 3627f48ad614SDennis Dalessandro /* 3628f48ad614SDennis Dalessandro * This pairs with the memory barrier in hfi1_start_led_override to 3629f48ad614SDennis Dalessandro * ensure that we read the correct state of LED beaconing represented 3630f48ad614SDennis Dalessandro * by led_override_timer_active 3631f48ad614SDennis Dalessandro */ 3632f48ad614SDennis Dalessandro smp_rmb(); 3633f48ad614SDennis Dalessandro is_beaconing_active = !!atomic_read(&ppd->led_override_timer_active); 3634f48ad614SDennis Dalessandro p->rsvd_led_mask = cpu_to_be32(is_beaconing_active << OPA_LED_SHIFT); 3635f48ad614SDennis Dalessandro 3636f48ad614SDennis Dalessandro if (resp_len) 3637f48ad614SDennis Dalessandro *resp_len += sizeof(struct opa_led_info); 3638f48ad614SDennis Dalessandro 3639f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3640f48ad614SDennis Dalessandro } 3641f48ad614SDennis Dalessandro 3642f48ad614SDennis Dalessandro static int __subn_set_opa_led_info(struct opa_smp *smp, u32 am, u8 *data, 3643f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3644f48ad614SDennis Dalessandro u32 *resp_len) 3645f48ad614SDennis Dalessandro { 3646f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 3647f48ad614SDennis Dalessandro struct opa_led_info *p = (struct opa_led_info *)data; 3648f48ad614SDennis Dalessandro u32 nport = OPA_AM_NPORT(am); 3649f48ad614SDennis Dalessandro int on = !!(be32_to_cpu(p->rsvd_led_mask) & OPA_LED_MASK); 3650f48ad614SDennis Dalessandro 3651f48ad614SDennis Dalessandro if (nport != 1) { 3652f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3653f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3654f48ad614SDennis Dalessandro } 3655f48ad614SDennis Dalessandro 3656f48ad614SDennis Dalessandro if (on) 3657f48ad614SDennis Dalessandro hfi1_start_led_override(dd->pport, 2000, 1500); 3658f48ad614SDennis Dalessandro else 3659f48ad614SDennis Dalessandro shutdown_led_override(dd->pport); 3660f48ad614SDennis Dalessandro 3661f48ad614SDennis Dalessandro return __subn_get_opa_led_info(smp, am, data, ibdev, port, resp_len); 3662f48ad614SDennis Dalessandro } 3663f48ad614SDennis Dalessandro 3664f48ad614SDennis Dalessandro static int subn_get_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am, 3665f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, u8 port, 3666f48ad614SDennis Dalessandro u32 *resp_len) 3667f48ad614SDennis Dalessandro { 3668f48ad614SDennis Dalessandro int ret; 3669f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3670f48ad614SDennis Dalessandro 3671f48ad614SDennis Dalessandro switch (attr_id) { 3672f48ad614SDennis Dalessandro case IB_SMP_ATTR_NODE_DESC: 3673f48ad614SDennis Dalessandro ret = __subn_get_opa_nodedesc(smp, am, data, ibdev, port, 3674f48ad614SDennis Dalessandro resp_len); 3675f48ad614SDennis Dalessandro break; 3676f48ad614SDennis Dalessandro case IB_SMP_ATTR_NODE_INFO: 3677f48ad614SDennis Dalessandro ret = __subn_get_opa_nodeinfo(smp, am, data, ibdev, port, 3678f48ad614SDennis Dalessandro resp_len); 3679f48ad614SDennis Dalessandro break; 3680f48ad614SDennis Dalessandro case IB_SMP_ATTR_PORT_INFO: 3681f48ad614SDennis Dalessandro ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port, 3682f48ad614SDennis Dalessandro resp_len); 3683f48ad614SDennis Dalessandro break; 3684f48ad614SDennis Dalessandro case IB_SMP_ATTR_PKEY_TABLE: 3685f48ad614SDennis Dalessandro ret = __subn_get_opa_pkeytable(smp, am, data, ibdev, port, 3686f48ad614SDennis Dalessandro resp_len); 3687f48ad614SDennis Dalessandro break; 3688f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SL_TO_SC_MAP: 3689f48ad614SDennis Dalessandro ret = __subn_get_opa_sl_to_sc(smp, am, data, ibdev, port, 3690f48ad614SDennis Dalessandro resp_len); 3691f48ad614SDennis Dalessandro break; 3692f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_SL_MAP: 3693f48ad614SDennis Dalessandro ret = __subn_get_opa_sc_to_sl(smp, am, data, ibdev, port, 3694f48ad614SDennis Dalessandro resp_len); 3695f48ad614SDennis Dalessandro break; 3696f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_VLT_MAP: 3697f48ad614SDennis Dalessandro ret = __subn_get_opa_sc_to_vlt(smp, am, data, ibdev, port, 3698f48ad614SDennis Dalessandro resp_len); 3699f48ad614SDennis Dalessandro break; 3700f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_VLNT_MAP: 3701f48ad614SDennis Dalessandro ret = __subn_get_opa_sc_to_vlnt(smp, am, data, ibdev, port, 3702f48ad614SDennis Dalessandro resp_len); 3703f48ad614SDennis Dalessandro break; 3704f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_PORT_STATE_INFO: 3705f48ad614SDennis Dalessandro ret = __subn_get_opa_psi(smp, am, data, ibdev, port, 3706f48ad614SDennis Dalessandro resp_len); 3707f48ad614SDennis Dalessandro break; 3708f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_BUFFER_CONTROL_TABLE: 3709f48ad614SDennis Dalessandro ret = __subn_get_opa_bct(smp, am, data, ibdev, port, 3710f48ad614SDennis Dalessandro resp_len); 3711f48ad614SDennis Dalessandro break; 3712f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_CABLE_INFO: 3713f48ad614SDennis Dalessandro ret = __subn_get_opa_cable_info(smp, am, data, ibdev, port, 3714f48ad614SDennis Dalessandro resp_len); 3715f48ad614SDennis Dalessandro break; 3716f48ad614SDennis Dalessandro case IB_SMP_ATTR_VL_ARB_TABLE: 3717f48ad614SDennis Dalessandro ret = __subn_get_opa_vl_arb(smp, am, data, ibdev, port, 3718f48ad614SDennis Dalessandro resp_len); 3719f48ad614SDennis Dalessandro break; 3720f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_CONGESTION_INFO: 3721f48ad614SDennis Dalessandro ret = __subn_get_opa_cong_info(smp, am, data, ibdev, port, 3722f48ad614SDennis Dalessandro resp_len); 3723f48ad614SDennis Dalessandro break; 3724f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_HFI_CONGESTION_SETTING: 3725f48ad614SDennis Dalessandro ret = __subn_get_opa_cong_setting(smp, am, data, ibdev, 3726f48ad614SDennis Dalessandro port, resp_len); 3727f48ad614SDennis Dalessandro break; 3728f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_HFI_CONGESTION_LOG: 3729f48ad614SDennis Dalessandro ret = __subn_get_opa_hfi1_cong_log(smp, am, data, ibdev, 3730f48ad614SDennis Dalessandro port, resp_len); 3731f48ad614SDennis Dalessandro break; 3732f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_CONGESTION_CONTROL_TABLE: 3733f48ad614SDennis Dalessandro ret = __subn_get_opa_cc_table(smp, am, data, ibdev, port, 3734f48ad614SDennis Dalessandro resp_len); 3735f48ad614SDennis Dalessandro break; 3736f48ad614SDennis Dalessandro case IB_SMP_ATTR_LED_INFO: 3737f48ad614SDennis Dalessandro ret = __subn_get_opa_led_info(smp, am, data, ibdev, port, 3738f48ad614SDennis Dalessandro resp_len); 3739f48ad614SDennis Dalessandro break; 3740f48ad614SDennis Dalessandro case IB_SMP_ATTR_SM_INFO: 3741f48ad614SDennis Dalessandro if (ibp->rvp.port_cap_flags & IB_PORT_SM_DISABLED) 3742f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 3743f48ad614SDennis Dalessandro if (ibp->rvp.port_cap_flags & IB_PORT_SM) 3744f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS; 3745f48ad614SDennis Dalessandro /* FALLTHROUGH */ 3746f48ad614SDennis Dalessandro default: 3747f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 3748f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 3749f48ad614SDennis Dalessandro break; 3750f48ad614SDennis Dalessandro } 3751f48ad614SDennis Dalessandro return ret; 3752f48ad614SDennis Dalessandro } 3753f48ad614SDennis Dalessandro 3754f48ad614SDennis Dalessandro static int subn_set_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am, 3755f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, u8 port, 3756f48ad614SDennis Dalessandro u32 *resp_len) 3757f48ad614SDennis Dalessandro { 3758f48ad614SDennis Dalessandro int ret; 3759f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3760f48ad614SDennis Dalessandro 3761f48ad614SDennis Dalessandro switch (attr_id) { 3762f48ad614SDennis Dalessandro case IB_SMP_ATTR_PORT_INFO: 3763f48ad614SDennis Dalessandro ret = __subn_set_opa_portinfo(smp, am, data, ibdev, port, 3764f48ad614SDennis Dalessandro resp_len); 3765f48ad614SDennis Dalessandro break; 3766f48ad614SDennis Dalessandro case IB_SMP_ATTR_PKEY_TABLE: 3767f48ad614SDennis Dalessandro ret = __subn_set_opa_pkeytable(smp, am, data, ibdev, port, 3768f48ad614SDennis Dalessandro resp_len); 3769f48ad614SDennis Dalessandro break; 3770f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SL_TO_SC_MAP: 3771f48ad614SDennis Dalessandro ret = __subn_set_opa_sl_to_sc(smp, am, data, ibdev, port, 3772f48ad614SDennis Dalessandro resp_len); 3773f48ad614SDennis Dalessandro break; 3774f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_SL_MAP: 3775f48ad614SDennis Dalessandro ret = __subn_set_opa_sc_to_sl(smp, am, data, ibdev, port, 3776f48ad614SDennis Dalessandro resp_len); 3777f48ad614SDennis Dalessandro break; 3778f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_VLT_MAP: 3779f48ad614SDennis Dalessandro ret = __subn_set_opa_sc_to_vlt(smp, am, data, ibdev, port, 3780f48ad614SDennis Dalessandro resp_len); 3781f48ad614SDennis Dalessandro break; 3782f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_VLNT_MAP: 3783f48ad614SDennis Dalessandro ret = __subn_set_opa_sc_to_vlnt(smp, am, data, ibdev, port, 3784f48ad614SDennis Dalessandro resp_len); 3785f48ad614SDennis Dalessandro break; 3786f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_PORT_STATE_INFO: 3787f48ad614SDennis Dalessandro ret = __subn_set_opa_psi(smp, am, data, ibdev, port, 3788f48ad614SDennis Dalessandro resp_len); 3789f48ad614SDennis Dalessandro break; 3790f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_BUFFER_CONTROL_TABLE: 3791f48ad614SDennis Dalessandro ret = __subn_set_opa_bct(smp, am, data, ibdev, port, 3792f48ad614SDennis Dalessandro resp_len); 3793f48ad614SDennis Dalessandro break; 3794f48ad614SDennis Dalessandro case IB_SMP_ATTR_VL_ARB_TABLE: 3795f48ad614SDennis Dalessandro ret = __subn_set_opa_vl_arb(smp, am, data, ibdev, port, 3796f48ad614SDennis Dalessandro resp_len); 3797f48ad614SDennis Dalessandro break; 3798f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_HFI_CONGESTION_SETTING: 3799f48ad614SDennis Dalessandro ret = __subn_set_opa_cong_setting(smp, am, data, ibdev, 3800f48ad614SDennis Dalessandro port, resp_len); 3801f48ad614SDennis Dalessandro break; 3802f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_CONGESTION_CONTROL_TABLE: 3803f48ad614SDennis Dalessandro ret = __subn_set_opa_cc_table(smp, am, data, ibdev, port, 3804f48ad614SDennis Dalessandro resp_len); 3805f48ad614SDennis Dalessandro break; 3806f48ad614SDennis Dalessandro case IB_SMP_ATTR_LED_INFO: 3807f48ad614SDennis Dalessandro ret = __subn_set_opa_led_info(smp, am, data, ibdev, port, 3808f48ad614SDennis Dalessandro resp_len); 3809f48ad614SDennis Dalessandro break; 3810f48ad614SDennis Dalessandro case IB_SMP_ATTR_SM_INFO: 3811f48ad614SDennis Dalessandro if (ibp->rvp.port_cap_flags & IB_PORT_SM_DISABLED) 3812f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 3813f48ad614SDennis Dalessandro if (ibp->rvp.port_cap_flags & IB_PORT_SM) 3814f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS; 3815f48ad614SDennis Dalessandro /* FALLTHROUGH */ 3816f48ad614SDennis Dalessandro default: 3817f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 3818f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 3819f48ad614SDennis Dalessandro break; 3820f48ad614SDennis Dalessandro } 3821f48ad614SDennis Dalessandro return ret; 3822f48ad614SDennis Dalessandro } 3823f48ad614SDennis Dalessandro 3824f48ad614SDennis Dalessandro static inline void set_aggr_error(struct opa_aggregate *ag) 3825f48ad614SDennis Dalessandro { 3826f48ad614SDennis Dalessandro ag->err_reqlength |= cpu_to_be16(0x8000); 3827f48ad614SDennis Dalessandro } 3828f48ad614SDennis Dalessandro 3829f48ad614SDennis Dalessandro static int subn_get_opa_aggregate(struct opa_smp *smp, 3830f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3831f48ad614SDennis Dalessandro u32 *resp_len) 3832f48ad614SDennis Dalessandro { 3833f48ad614SDennis Dalessandro int i; 3834f48ad614SDennis Dalessandro u32 num_attr = be32_to_cpu(smp->attr_mod) & 0x000000ff; 3835f48ad614SDennis Dalessandro u8 *next_smp = opa_get_smp_data(smp); 3836f48ad614SDennis Dalessandro 3837f48ad614SDennis Dalessandro if (num_attr < 1 || num_attr > 117) { 3838f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3839f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3840f48ad614SDennis Dalessandro } 3841f48ad614SDennis Dalessandro 3842f48ad614SDennis Dalessandro for (i = 0; i < num_attr; i++) { 3843f48ad614SDennis Dalessandro struct opa_aggregate *agg; 3844f48ad614SDennis Dalessandro size_t agg_data_len; 3845f48ad614SDennis Dalessandro size_t agg_size; 3846f48ad614SDennis Dalessandro u32 am; 3847f48ad614SDennis Dalessandro 3848f48ad614SDennis Dalessandro agg = (struct opa_aggregate *)next_smp; 3849f48ad614SDennis Dalessandro agg_data_len = (be16_to_cpu(agg->err_reqlength) & 0x007f) * 8; 3850f48ad614SDennis Dalessandro agg_size = sizeof(*agg) + agg_data_len; 3851f48ad614SDennis Dalessandro am = be32_to_cpu(agg->attr_mod); 3852f48ad614SDennis Dalessandro 3853f48ad614SDennis Dalessandro *resp_len += agg_size; 3854f48ad614SDennis Dalessandro 3855f48ad614SDennis Dalessandro if (next_smp + agg_size > ((u8 *)smp) + sizeof(*smp)) { 3856f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3857f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3858f48ad614SDennis Dalessandro } 3859f48ad614SDennis Dalessandro 3860f48ad614SDennis Dalessandro /* zero the payload for this segment */ 3861f48ad614SDennis Dalessandro memset(next_smp + sizeof(*agg), 0, agg_data_len); 3862f48ad614SDennis Dalessandro 3863f48ad614SDennis Dalessandro (void)subn_get_opa_sma(agg->attr_id, smp, am, agg->data, 3864f48ad614SDennis Dalessandro ibdev, port, NULL); 3865f48ad614SDennis Dalessandro if (smp->status & ~IB_SMP_DIRECTION) { 3866f48ad614SDennis Dalessandro set_aggr_error(agg); 3867f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3868f48ad614SDennis Dalessandro } 3869f48ad614SDennis Dalessandro next_smp += agg_size; 3870f48ad614SDennis Dalessandro } 3871f48ad614SDennis Dalessandro 3872f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3873f48ad614SDennis Dalessandro } 3874f48ad614SDennis Dalessandro 3875f48ad614SDennis Dalessandro static int subn_set_opa_aggregate(struct opa_smp *smp, 3876f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3877f48ad614SDennis Dalessandro u32 *resp_len) 3878f48ad614SDennis Dalessandro { 3879f48ad614SDennis Dalessandro int i; 3880f48ad614SDennis Dalessandro u32 num_attr = be32_to_cpu(smp->attr_mod) & 0x000000ff; 3881f48ad614SDennis Dalessandro u8 *next_smp = opa_get_smp_data(smp); 3882f48ad614SDennis Dalessandro 3883f48ad614SDennis Dalessandro if (num_attr < 1 || num_attr > 117) { 3884f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3885f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3886f48ad614SDennis Dalessandro } 3887f48ad614SDennis Dalessandro 3888f48ad614SDennis Dalessandro for (i = 0; i < num_attr; i++) { 3889f48ad614SDennis Dalessandro struct opa_aggregate *agg; 3890f48ad614SDennis Dalessandro size_t agg_data_len; 3891f48ad614SDennis Dalessandro size_t agg_size; 3892f48ad614SDennis Dalessandro u32 am; 3893f48ad614SDennis Dalessandro 3894f48ad614SDennis Dalessandro agg = (struct opa_aggregate *)next_smp; 3895f48ad614SDennis Dalessandro agg_data_len = (be16_to_cpu(agg->err_reqlength) & 0x007f) * 8; 3896f48ad614SDennis Dalessandro agg_size = sizeof(*agg) + agg_data_len; 3897f48ad614SDennis Dalessandro am = be32_to_cpu(agg->attr_mod); 3898f48ad614SDennis Dalessandro 3899f48ad614SDennis Dalessandro *resp_len += agg_size; 3900f48ad614SDennis Dalessandro 3901f48ad614SDennis Dalessandro if (next_smp + agg_size > ((u8 *)smp) + sizeof(*smp)) { 3902f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3903f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3904f48ad614SDennis Dalessandro } 3905f48ad614SDennis Dalessandro 3906f48ad614SDennis Dalessandro (void)subn_set_opa_sma(agg->attr_id, smp, am, agg->data, 3907f48ad614SDennis Dalessandro ibdev, port, NULL); 3908f48ad614SDennis Dalessandro if (smp->status & ~IB_SMP_DIRECTION) { 3909f48ad614SDennis Dalessandro set_aggr_error(agg); 3910f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3911f48ad614SDennis Dalessandro } 3912f48ad614SDennis Dalessandro next_smp += agg_size; 3913f48ad614SDennis Dalessandro } 3914f48ad614SDennis Dalessandro 3915f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3916f48ad614SDennis Dalessandro } 3917f48ad614SDennis Dalessandro 3918f48ad614SDennis Dalessandro /* 3919f48ad614SDennis Dalessandro * OPAv1 specifies that, on the transition to link up, these counters 3920f48ad614SDennis Dalessandro * are cleared: 3921f48ad614SDennis Dalessandro * PortRcvErrors [*] 3922f48ad614SDennis Dalessandro * LinkErrorRecovery 3923f48ad614SDennis Dalessandro * LocalLinkIntegrityErrors 3924f48ad614SDennis Dalessandro * ExcessiveBufferOverruns [*] 3925f48ad614SDennis Dalessandro * 3926f48ad614SDennis Dalessandro * [*] Error info associated with these counters is retained, but the 3927f48ad614SDennis Dalessandro * error info status is reset to 0. 3928f48ad614SDennis Dalessandro */ 3929f48ad614SDennis Dalessandro void clear_linkup_counters(struct hfi1_devdata *dd) 3930f48ad614SDennis Dalessandro { 3931f48ad614SDennis Dalessandro /* PortRcvErrors */ 3932f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL, 0); 3933f48ad614SDennis Dalessandro dd->err_info_rcvport.status_and_code &= ~OPA_EI_STATUS_SMASK; 3934f48ad614SDennis Dalessandro /* LinkErrorRecovery */ 3935f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0); 3936f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL, 0); 3937f48ad614SDennis Dalessandro /* LocalLinkIntegrityErrors */ 3938f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0); 3939f48ad614SDennis Dalessandro /* ExcessiveBufferOverruns */ 3940f48ad614SDennis Dalessandro write_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL, 0); 3941f48ad614SDennis Dalessandro dd->rcv_ovfl_cnt = 0; 3942f48ad614SDennis Dalessandro dd->err_info_xmit_constraint.status &= ~OPA_EI_STATUS_SMASK; 3943f48ad614SDennis Dalessandro } 3944f48ad614SDennis Dalessandro 3945f48ad614SDennis Dalessandro /* 3946f48ad614SDennis Dalessandro * is_local_mad() returns 1 if 'mad' is sent from, and destined to the 3947f48ad614SDennis Dalessandro * local node, 0 otherwise. 3948f48ad614SDennis Dalessandro */ 3949f48ad614SDennis Dalessandro static int is_local_mad(struct hfi1_ibport *ibp, const struct opa_mad *mad, 3950f48ad614SDennis Dalessandro const struct ib_wc *in_wc) 3951f48ad614SDennis Dalessandro { 3952f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3953f48ad614SDennis Dalessandro const struct opa_smp *smp = (const struct opa_smp *)mad; 3954f48ad614SDennis Dalessandro 3955f48ad614SDennis Dalessandro if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 3956f48ad614SDennis Dalessandro return (smp->hop_cnt == 0 && 3957f48ad614SDennis Dalessandro smp->route.dr.dr_slid == OPA_LID_PERMISSIVE && 3958f48ad614SDennis Dalessandro smp->route.dr.dr_dlid == OPA_LID_PERMISSIVE); 3959f48ad614SDennis Dalessandro } 3960f48ad614SDennis Dalessandro 3961f48ad614SDennis Dalessandro return (in_wc->slid == ppd->lid); 3962f48ad614SDennis Dalessandro } 3963f48ad614SDennis Dalessandro 3964f48ad614SDennis Dalessandro /* 3965f48ad614SDennis Dalessandro * opa_local_smp_check() should only be called on MADs for which 3966f48ad614SDennis Dalessandro * is_local_mad() returns true. It applies the SMP checks that are 3967f48ad614SDennis Dalessandro * specific to SMPs which are sent from, and destined to this node. 3968f48ad614SDennis Dalessandro * opa_local_smp_check() returns 0 if the SMP passes its checks, 1 3969f48ad614SDennis Dalessandro * otherwise. 3970f48ad614SDennis Dalessandro * 3971f48ad614SDennis Dalessandro * SMPs which arrive from other nodes are instead checked by 3972f48ad614SDennis Dalessandro * opa_smp_check(). 3973f48ad614SDennis Dalessandro */ 3974f48ad614SDennis Dalessandro static int opa_local_smp_check(struct hfi1_ibport *ibp, 3975f48ad614SDennis Dalessandro const struct ib_wc *in_wc) 3976f48ad614SDennis Dalessandro { 3977f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3978f48ad614SDennis Dalessandro u16 slid = in_wc->slid; 3979f48ad614SDennis Dalessandro u16 pkey; 3980f48ad614SDennis Dalessandro 3981f48ad614SDennis Dalessandro if (in_wc->pkey_index >= ARRAY_SIZE(ppd->pkeys)) 3982f48ad614SDennis Dalessandro return 1; 3983f48ad614SDennis Dalessandro 3984f48ad614SDennis Dalessandro pkey = ppd->pkeys[in_wc->pkey_index]; 3985f48ad614SDennis Dalessandro /* 3986f48ad614SDennis Dalessandro * We need to do the "node-local" checks specified in OPAv1, 3987f48ad614SDennis Dalessandro * rev 0.90, section 9.10.26, which are: 3988f48ad614SDennis Dalessandro * - pkey is 0x7fff, or 0xffff 3989f48ad614SDennis Dalessandro * - Source QPN == 0 || Destination QPN == 0 3990f48ad614SDennis Dalessandro * - the MAD header's management class is either 3991f48ad614SDennis Dalessandro * IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE or 3992f48ad614SDennis Dalessandro * IB_MGMT_CLASS_SUBN_LID_ROUTED 3993f48ad614SDennis Dalessandro * - SLID != 0 3994f48ad614SDennis Dalessandro * 3995f48ad614SDennis Dalessandro * However, we know (and so don't need to check again) that, 3996f48ad614SDennis Dalessandro * for local SMPs, the MAD stack passes MADs with: 3997f48ad614SDennis Dalessandro * - Source QPN of 0 3998f48ad614SDennis Dalessandro * - MAD mgmt_class is IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 3999f48ad614SDennis Dalessandro * - SLID is either: OPA_LID_PERMISSIVE (0xFFFFFFFF), or 4000f48ad614SDennis Dalessandro * our own port's lid 4001f48ad614SDennis Dalessandro * 4002f48ad614SDennis Dalessandro */ 4003f48ad614SDennis Dalessandro if (pkey == LIM_MGMT_P_KEY || pkey == FULL_MGMT_P_KEY) 4004f48ad614SDennis Dalessandro return 0; 4005f48ad614SDennis Dalessandro ingress_pkey_table_fail(ppd, pkey, slid); 4006f48ad614SDennis Dalessandro return 1; 4007f48ad614SDennis Dalessandro } 4008f48ad614SDennis Dalessandro 4009f48ad614SDennis Dalessandro static int process_subn_opa(struct ib_device *ibdev, int mad_flags, 4010f48ad614SDennis Dalessandro u8 port, const struct opa_mad *in_mad, 4011f48ad614SDennis Dalessandro struct opa_mad *out_mad, 4012f48ad614SDennis Dalessandro u32 *resp_len) 4013f48ad614SDennis Dalessandro { 4014f48ad614SDennis Dalessandro struct opa_smp *smp = (struct opa_smp *)out_mad; 4015f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 4016f48ad614SDennis Dalessandro u8 *data; 4017f48ad614SDennis Dalessandro u32 am; 4018f48ad614SDennis Dalessandro __be16 attr_id; 4019f48ad614SDennis Dalessandro int ret; 4020f48ad614SDennis Dalessandro 4021f48ad614SDennis Dalessandro *out_mad = *in_mad; 4022f48ad614SDennis Dalessandro data = opa_get_smp_data(smp); 4023f48ad614SDennis Dalessandro 4024f48ad614SDennis Dalessandro am = be32_to_cpu(smp->attr_mod); 4025f48ad614SDennis Dalessandro attr_id = smp->attr_id; 40269fa240bbSHal Rosenstock if (smp->class_version != OPA_SM_CLASS_VERSION) { 4027f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_VERSION; 4028f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4029f48ad614SDennis Dalessandro return ret; 4030f48ad614SDennis Dalessandro } 4031f48ad614SDennis Dalessandro ret = check_mkey(ibp, (struct ib_mad_hdr *)smp, mad_flags, smp->mkey, 4032f48ad614SDennis Dalessandro smp->route.dr.dr_slid, smp->route.dr.return_path, 4033f48ad614SDennis Dalessandro smp->hop_cnt); 4034f48ad614SDennis Dalessandro if (ret) { 4035f48ad614SDennis Dalessandro u32 port_num = be32_to_cpu(smp->attr_mod); 4036f48ad614SDennis Dalessandro 4037f48ad614SDennis Dalessandro /* 4038f48ad614SDennis Dalessandro * If this is a get/set portinfo, we already check the 4039f48ad614SDennis Dalessandro * M_Key if the MAD is for another port and the M_Key 4040f48ad614SDennis Dalessandro * is OK on the receiving port. This check is needed 4041f48ad614SDennis Dalessandro * to increment the error counters when the M_Key 4042f48ad614SDennis Dalessandro * fails to match on *both* ports. 4043f48ad614SDennis Dalessandro */ 4044f48ad614SDennis Dalessandro if (attr_id == IB_SMP_ATTR_PORT_INFO && 4045f48ad614SDennis Dalessandro (smp->method == IB_MGMT_METHOD_GET || 4046f48ad614SDennis Dalessandro smp->method == IB_MGMT_METHOD_SET) && 4047f48ad614SDennis Dalessandro port_num && port_num <= ibdev->phys_port_cnt && 4048f48ad614SDennis Dalessandro port != port_num) 4049f48ad614SDennis Dalessandro (void)check_mkey(to_iport(ibdev, port_num), 4050f48ad614SDennis Dalessandro (struct ib_mad_hdr *)smp, 0, 4051f48ad614SDennis Dalessandro smp->mkey, smp->route.dr.dr_slid, 4052f48ad614SDennis Dalessandro smp->route.dr.return_path, 4053f48ad614SDennis Dalessandro smp->hop_cnt); 4054f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_FAILURE; 4055f48ad614SDennis Dalessandro return ret; 4056f48ad614SDennis Dalessandro } 4057f48ad614SDennis Dalessandro 4058f48ad614SDennis Dalessandro *resp_len = opa_get_smp_header_size(smp); 4059f48ad614SDennis Dalessandro 4060f48ad614SDennis Dalessandro switch (smp->method) { 4061f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 4062f48ad614SDennis Dalessandro switch (attr_id) { 4063f48ad614SDennis Dalessandro default: 4064f48ad614SDennis Dalessandro clear_opa_smp_data(smp); 4065f48ad614SDennis Dalessandro ret = subn_get_opa_sma(attr_id, smp, am, data, 4066f48ad614SDennis Dalessandro ibdev, port, resp_len); 4067f48ad614SDennis Dalessandro break; 4068f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_AGGREGATE: 4069f48ad614SDennis Dalessandro ret = subn_get_opa_aggregate(smp, ibdev, port, 4070f48ad614SDennis Dalessandro resp_len); 4071f48ad614SDennis Dalessandro break; 4072f48ad614SDennis Dalessandro } 4073f48ad614SDennis Dalessandro break; 4074f48ad614SDennis Dalessandro case IB_MGMT_METHOD_SET: 4075f48ad614SDennis Dalessandro switch (attr_id) { 4076f48ad614SDennis Dalessandro default: 4077f48ad614SDennis Dalessandro ret = subn_set_opa_sma(attr_id, smp, am, data, 4078f48ad614SDennis Dalessandro ibdev, port, resp_len); 4079f48ad614SDennis Dalessandro break; 4080f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_AGGREGATE: 4081f48ad614SDennis Dalessandro ret = subn_set_opa_aggregate(smp, ibdev, port, 4082f48ad614SDennis Dalessandro resp_len); 4083f48ad614SDennis Dalessandro break; 4084f48ad614SDennis Dalessandro } 4085f48ad614SDennis Dalessandro break; 4086f48ad614SDennis Dalessandro case IB_MGMT_METHOD_TRAP: 4087f48ad614SDennis Dalessandro case IB_MGMT_METHOD_REPORT: 4088f48ad614SDennis Dalessandro case IB_MGMT_METHOD_REPORT_RESP: 4089f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET_RESP: 4090f48ad614SDennis Dalessandro /* 4091f48ad614SDennis Dalessandro * The ib_mad module will call us to process responses 4092f48ad614SDennis Dalessandro * before checking for other consumers. 4093f48ad614SDennis Dalessandro * Just tell the caller to process it normally. 4094f48ad614SDennis Dalessandro */ 4095f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4096f48ad614SDennis Dalessandro break; 4097f48ad614SDennis Dalessandro default: 4098f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METHOD; 4099f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4100f48ad614SDennis Dalessandro break; 4101f48ad614SDennis Dalessandro } 4102f48ad614SDennis Dalessandro 4103f48ad614SDennis Dalessandro return ret; 4104f48ad614SDennis Dalessandro } 4105f48ad614SDennis Dalessandro 4106f48ad614SDennis Dalessandro static int process_subn(struct ib_device *ibdev, int mad_flags, 4107f48ad614SDennis Dalessandro u8 port, const struct ib_mad *in_mad, 4108f48ad614SDennis Dalessandro struct ib_mad *out_mad) 4109f48ad614SDennis Dalessandro { 4110f48ad614SDennis Dalessandro struct ib_smp *smp = (struct ib_smp *)out_mad; 4111f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 4112f48ad614SDennis Dalessandro int ret; 4113f48ad614SDennis Dalessandro 4114f48ad614SDennis Dalessandro *out_mad = *in_mad; 4115f48ad614SDennis Dalessandro if (smp->class_version != 1) { 4116f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_VERSION; 4117f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4118f48ad614SDennis Dalessandro return ret; 4119f48ad614SDennis Dalessandro } 4120f48ad614SDennis Dalessandro 4121f48ad614SDennis Dalessandro ret = check_mkey(ibp, (struct ib_mad_hdr *)smp, mad_flags, 4122f48ad614SDennis Dalessandro smp->mkey, (__force __be32)smp->dr_slid, 4123f48ad614SDennis Dalessandro smp->return_path, smp->hop_cnt); 4124f48ad614SDennis Dalessandro if (ret) { 4125f48ad614SDennis Dalessandro u32 port_num = be32_to_cpu(smp->attr_mod); 4126f48ad614SDennis Dalessandro 4127f48ad614SDennis Dalessandro /* 4128f48ad614SDennis Dalessandro * If this is a get/set portinfo, we already check the 4129f48ad614SDennis Dalessandro * M_Key if the MAD is for another port and the M_Key 4130f48ad614SDennis Dalessandro * is OK on the receiving port. This check is needed 4131f48ad614SDennis Dalessandro * to increment the error counters when the M_Key 4132f48ad614SDennis Dalessandro * fails to match on *both* ports. 4133f48ad614SDennis Dalessandro */ 4134f48ad614SDennis Dalessandro if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && 4135f48ad614SDennis Dalessandro (smp->method == IB_MGMT_METHOD_GET || 4136f48ad614SDennis Dalessandro smp->method == IB_MGMT_METHOD_SET) && 4137f48ad614SDennis Dalessandro port_num && port_num <= ibdev->phys_port_cnt && 4138f48ad614SDennis Dalessandro port != port_num) 4139f48ad614SDennis Dalessandro (void)check_mkey(to_iport(ibdev, port_num), 4140f48ad614SDennis Dalessandro (struct ib_mad_hdr *)smp, 0, 4141f48ad614SDennis Dalessandro smp->mkey, 4142f48ad614SDennis Dalessandro (__force __be32)smp->dr_slid, 4143f48ad614SDennis Dalessandro smp->return_path, smp->hop_cnt); 4144f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_FAILURE; 4145f48ad614SDennis Dalessandro return ret; 4146f48ad614SDennis Dalessandro } 4147f48ad614SDennis Dalessandro 4148f48ad614SDennis Dalessandro switch (smp->method) { 4149f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 4150f48ad614SDennis Dalessandro switch (smp->attr_id) { 4151f48ad614SDennis Dalessandro case IB_SMP_ATTR_NODE_INFO: 4152f48ad614SDennis Dalessandro ret = subn_get_nodeinfo(smp, ibdev, port); 4153f48ad614SDennis Dalessandro break; 4154f48ad614SDennis Dalessandro default: 4155f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 4156f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4157f48ad614SDennis Dalessandro break; 4158f48ad614SDennis Dalessandro } 4159f48ad614SDennis Dalessandro break; 4160f48ad614SDennis Dalessandro } 4161f48ad614SDennis Dalessandro 4162f48ad614SDennis Dalessandro return ret; 4163f48ad614SDennis Dalessandro } 4164f48ad614SDennis Dalessandro 4165f48ad614SDennis Dalessandro static int process_perf(struct ib_device *ibdev, u8 port, 4166f48ad614SDennis Dalessandro const struct ib_mad *in_mad, 4167f48ad614SDennis Dalessandro struct ib_mad *out_mad) 4168f48ad614SDennis Dalessandro { 4169f48ad614SDennis Dalessandro struct ib_pma_mad *pmp = (struct ib_pma_mad *)out_mad; 4170f48ad614SDennis Dalessandro struct ib_class_port_info *cpi = (struct ib_class_port_info *) 4171f48ad614SDennis Dalessandro &pmp->data; 4172f48ad614SDennis Dalessandro int ret = IB_MAD_RESULT_FAILURE; 4173f48ad614SDennis Dalessandro 4174f48ad614SDennis Dalessandro *out_mad = *in_mad; 4175f48ad614SDennis Dalessandro if (pmp->mad_hdr.class_version != 1) { 4176f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_VERSION; 4177f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4178f48ad614SDennis Dalessandro return ret; 4179f48ad614SDennis Dalessandro } 4180f48ad614SDennis Dalessandro 4181f48ad614SDennis Dalessandro switch (pmp->mad_hdr.method) { 4182f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 4183f48ad614SDennis Dalessandro switch (pmp->mad_hdr.attr_id) { 4184f48ad614SDennis Dalessandro case IB_PMA_PORT_COUNTERS: 4185f48ad614SDennis Dalessandro ret = pma_get_ib_portcounters(pmp, ibdev, port); 4186f48ad614SDennis Dalessandro break; 4187f48ad614SDennis Dalessandro case IB_PMA_PORT_COUNTERS_EXT: 4188f48ad614SDennis Dalessandro ret = pma_get_ib_portcounters_ext(pmp, ibdev, port); 4189f48ad614SDennis Dalessandro break; 4190f48ad614SDennis Dalessandro case IB_PMA_CLASS_PORT_INFO: 4191f48ad614SDennis Dalessandro cpi->capability_mask = IB_PMA_CLASS_CAP_EXT_WIDTH; 4192f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4193f48ad614SDennis Dalessandro break; 4194f48ad614SDennis Dalessandro default: 4195f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; 4196f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4197f48ad614SDennis Dalessandro break; 4198f48ad614SDennis Dalessandro } 4199f48ad614SDennis Dalessandro break; 4200f48ad614SDennis Dalessandro 4201f48ad614SDennis Dalessandro case IB_MGMT_METHOD_SET: 4202f48ad614SDennis Dalessandro if (pmp->mad_hdr.attr_id) { 4203f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; 4204f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4205f48ad614SDennis Dalessandro } 4206f48ad614SDennis Dalessandro break; 4207f48ad614SDennis Dalessandro 4208f48ad614SDennis Dalessandro case IB_MGMT_METHOD_TRAP: 4209f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET_RESP: 4210f48ad614SDennis Dalessandro /* 4211f48ad614SDennis Dalessandro * The ib_mad module will call us to process responses 4212f48ad614SDennis Dalessandro * before checking for other consumers. 4213f48ad614SDennis Dalessandro * Just tell the caller to process it normally. 4214f48ad614SDennis Dalessandro */ 4215f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4216f48ad614SDennis Dalessandro break; 4217f48ad614SDennis Dalessandro 4218f48ad614SDennis Dalessandro default: 4219f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METHOD; 4220f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4221f48ad614SDennis Dalessandro break; 4222f48ad614SDennis Dalessandro } 4223f48ad614SDennis Dalessandro 4224f48ad614SDennis Dalessandro return ret; 4225f48ad614SDennis Dalessandro } 4226f48ad614SDennis Dalessandro 4227f48ad614SDennis Dalessandro static int process_perf_opa(struct ib_device *ibdev, u8 port, 4228f48ad614SDennis Dalessandro const struct opa_mad *in_mad, 4229f48ad614SDennis Dalessandro struct opa_mad *out_mad, u32 *resp_len) 4230f48ad614SDennis Dalessandro { 4231f48ad614SDennis Dalessandro struct opa_pma_mad *pmp = (struct opa_pma_mad *)out_mad; 4232f48ad614SDennis Dalessandro int ret; 4233f48ad614SDennis Dalessandro 4234f48ad614SDennis Dalessandro *out_mad = *in_mad; 4235f48ad614SDennis Dalessandro 42369fa240bbSHal Rosenstock if (pmp->mad_hdr.class_version != OPA_SM_CLASS_VERSION) { 4237f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_VERSION; 4238f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 4239f48ad614SDennis Dalessandro } 4240f48ad614SDennis Dalessandro 4241f48ad614SDennis Dalessandro *resp_len = sizeof(pmp->mad_hdr); 4242f48ad614SDennis Dalessandro 4243f48ad614SDennis Dalessandro switch (pmp->mad_hdr.method) { 4244f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 4245f48ad614SDennis Dalessandro switch (pmp->mad_hdr.attr_id) { 4246f48ad614SDennis Dalessandro case IB_PMA_CLASS_PORT_INFO: 4247f48ad614SDennis Dalessandro ret = pma_get_opa_classportinfo(pmp, ibdev, resp_len); 4248f48ad614SDennis Dalessandro break; 4249f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_PORT_STATUS: 4250f48ad614SDennis Dalessandro ret = pma_get_opa_portstatus(pmp, ibdev, port, 4251f48ad614SDennis Dalessandro resp_len); 4252f48ad614SDennis Dalessandro break; 4253f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_DATA_PORT_COUNTERS: 4254f48ad614SDennis Dalessandro ret = pma_get_opa_datacounters(pmp, ibdev, port, 4255f48ad614SDennis Dalessandro resp_len); 4256f48ad614SDennis Dalessandro break; 4257f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_ERROR_PORT_COUNTERS: 4258f48ad614SDennis Dalessandro ret = pma_get_opa_porterrors(pmp, ibdev, port, 4259f48ad614SDennis Dalessandro resp_len); 4260f48ad614SDennis Dalessandro break; 4261f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_ERROR_INFO: 4262f48ad614SDennis Dalessandro ret = pma_get_opa_errorinfo(pmp, ibdev, port, 4263f48ad614SDennis Dalessandro resp_len); 4264f48ad614SDennis Dalessandro break; 4265f48ad614SDennis Dalessandro default: 4266f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; 4267f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4268f48ad614SDennis Dalessandro break; 4269f48ad614SDennis Dalessandro } 4270f48ad614SDennis Dalessandro break; 4271f48ad614SDennis Dalessandro 4272f48ad614SDennis Dalessandro case IB_MGMT_METHOD_SET: 4273f48ad614SDennis Dalessandro switch (pmp->mad_hdr.attr_id) { 4274f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_CLEAR_PORT_STATUS: 4275f48ad614SDennis Dalessandro ret = pma_set_opa_portstatus(pmp, ibdev, port, 4276f48ad614SDennis Dalessandro resp_len); 4277f48ad614SDennis Dalessandro break; 4278f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_ERROR_INFO: 4279f48ad614SDennis Dalessandro ret = pma_set_opa_errorinfo(pmp, ibdev, port, 4280f48ad614SDennis Dalessandro resp_len); 4281f48ad614SDennis Dalessandro break; 4282f48ad614SDennis Dalessandro default: 4283f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; 4284f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4285f48ad614SDennis Dalessandro break; 4286f48ad614SDennis Dalessandro } 4287f48ad614SDennis Dalessandro break; 4288f48ad614SDennis Dalessandro 4289f48ad614SDennis Dalessandro case IB_MGMT_METHOD_TRAP: 4290f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET_RESP: 4291f48ad614SDennis Dalessandro /* 4292f48ad614SDennis Dalessandro * The ib_mad module will call us to process responses 4293f48ad614SDennis Dalessandro * before checking for other consumers. 4294f48ad614SDennis Dalessandro * Just tell the caller to process it normally. 4295f48ad614SDennis Dalessandro */ 4296f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4297f48ad614SDennis Dalessandro break; 4298f48ad614SDennis Dalessandro 4299f48ad614SDennis Dalessandro default: 4300f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METHOD; 4301f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4302f48ad614SDennis Dalessandro break; 4303f48ad614SDennis Dalessandro } 4304f48ad614SDennis Dalessandro 4305f48ad614SDennis Dalessandro return ret; 4306f48ad614SDennis Dalessandro } 4307f48ad614SDennis Dalessandro 4308f48ad614SDennis Dalessandro static int hfi1_process_opa_mad(struct ib_device *ibdev, int mad_flags, 4309f48ad614SDennis Dalessandro u8 port, const struct ib_wc *in_wc, 4310f48ad614SDennis Dalessandro const struct ib_grh *in_grh, 4311f48ad614SDennis Dalessandro const struct opa_mad *in_mad, 4312f48ad614SDennis Dalessandro struct opa_mad *out_mad, size_t *out_mad_size, 4313f48ad614SDennis Dalessandro u16 *out_mad_pkey_index) 4314f48ad614SDennis Dalessandro { 4315f48ad614SDennis Dalessandro int ret; 4316f48ad614SDennis Dalessandro int pkey_idx; 4317f48ad614SDennis Dalessandro u32 resp_len = 0; 4318f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 4319f48ad614SDennis Dalessandro 4320f48ad614SDennis Dalessandro pkey_idx = hfi1_lookup_pkey_idx(ibp, LIM_MGMT_P_KEY); 4321f48ad614SDennis Dalessandro if (pkey_idx < 0) { 4322f48ad614SDennis Dalessandro pr_warn("failed to find limited mgmt pkey, defaulting 0x%x\n", 4323f48ad614SDennis Dalessandro hfi1_get_pkey(ibp, 1)); 4324f48ad614SDennis Dalessandro pkey_idx = 1; 4325f48ad614SDennis Dalessandro } 4326f48ad614SDennis Dalessandro *out_mad_pkey_index = (u16)pkey_idx; 4327f48ad614SDennis Dalessandro 4328f48ad614SDennis Dalessandro switch (in_mad->mad_hdr.mgmt_class) { 4329f48ad614SDennis Dalessandro case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: 4330f48ad614SDennis Dalessandro case IB_MGMT_CLASS_SUBN_LID_ROUTED: 4331f48ad614SDennis Dalessandro if (is_local_mad(ibp, in_mad, in_wc)) { 4332f48ad614SDennis Dalessandro ret = opa_local_smp_check(ibp, in_wc); 4333f48ad614SDennis Dalessandro if (ret) 4334f48ad614SDennis Dalessandro return IB_MAD_RESULT_FAILURE; 4335f48ad614SDennis Dalessandro } 4336f48ad614SDennis Dalessandro ret = process_subn_opa(ibdev, mad_flags, port, in_mad, 4337f48ad614SDennis Dalessandro out_mad, &resp_len); 4338f48ad614SDennis Dalessandro goto bail; 4339f48ad614SDennis Dalessandro case IB_MGMT_CLASS_PERF_MGMT: 4340f48ad614SDennis Dalessandro ret = process_perf_opa(ibdev, port, in_mad, out_mad, 4341f48ad614SDennis Dalessandro &resp_len); 4342f48ad614SDennis Dalessandro goto bail; 4343f48ad614SDennis Dalessandro 4344f48ad614SDennis Dalessandro default: 4345f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4346f48ad614SDennis Dalessandro } 4347f48ad614SDennis Dalessandro 4348f48ad614SDennis Dalessandro bail: 4349f48ad614SDennis Dalessandro if (ret & IB_MAD_RESULT_REPLY) 4350f48ad614SDennis Dalessandro *out_mad_size = round_up(resp_len, 8); 4351f48ad614SDennis Dalessandro else if (ret & IB_MAD_RESULT_SUCCESS) 4352f48ad614SDennis Dalessandro *out_mad_size = in_wc->byte_len - sizeof(struct ib_grh); 4353f48ad614SDennis Dalessandro 4354f48ad614SDennis Dalessandro return ret; 4355f48ad614SDennis Dalessandro } 4356f48ad614SDennis Dalessandro 4357f48ad614SDennis Dalessandro static int hfi1_process_ib_mad(struct ib_device *ibdev, int mad_flags, u8 port, 4358f48ad614SDennis Dalessandro const struct ib_wc *in_wc, 4359f48ad614SDennis Dalessandro const struct ib_grh *in_grh, 4360f48ad614SDennis Dalessandro const struct ib_mad *in_mad, 4361f48ad614SDennis Dalessandro struct ib_mad *out_mad) 4362f48ad614SDennis Dalessandro { 4363f48ad614SDennis Dalessandro int ret; 4364f48ad614SDennis Dalessandro 4365f48ad614SDennis Dalessandro switch (in_mad->mad_hdr.mgmt_class) { 4366f48ad614SDennis Dalessandro case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: 4367f48ad614SDennis Dalessandro case IB_MGMT_CLASS_SUBN_LID_ROUTED: 4368f48ad614SDennis Dalessandro ret = process_subn(ibdev, mad_flags, port, in_mad, out_mad); 4369f48ad614SDennis Dalessandro break; 4370f48ad614SDennis Dalessandro case IB_MGMT_CLASS_PERF_MGMT: 4371f48ad614SDennis Dalessandro ret = process_perf(ibdev, port, in_mad, out_mad); 4372f48ad614SDennis Dalessandro break; 4373f48ad614SDennis Dalessandro default: 4374f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4375f48ad614SDennis Dalessandro break; 4376f48ad614SDennis Dalessandro } 4377f48ad614SDennis Dalessandro 4378f48ad614SDennis Dalessandro return ret; 4379f48ad614SDennis Dalessandro } 4380f48ad614SDennis Dalessandro 4381f48ad614SDennis Dalessandro /** 4382f48ad614SDennis Dalessandro * hfi1_process_mad - process an incoming MAD packet 4383f48ad614SDennis Dalessandro * @ibdev: the infiniband device this packet came in on 4384f48ad614SDennis Dalessandro * @mad_flags: MAD flags 4385f48ad614SDennis Dalessandro * @port: the port number this packet came in on 4386f48ad614SDennis Dalessandro * @in_wc: the work completion entry for this packet 4387f48ad614SDennis Dalessandro * @in_grh: the global route header for this packet 4388f48ad614SDennis Dalessandro * @in_mad: the incoming MAD 4389f48ad614SDennis Dalessandro * @out_mad: any outgoing MAD reply 4390f48ad614SDennis Dalessandro * 4391f48ad614SDennis Dalessandro * Returns IB_MAD_RESULT_SUCCESS if this is a MAD that we are not 4392f48ad614SDennis Dalessandro * interested in processing. 4393f48ad614SDennis Dalessandro * 4394f48ad614SDennis Dalessandro * Note that the verbs framework has already done the MAD sanity checks, 4395f48ad614SDennis Dalessandro * and hop count/pointer updating for IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 4396f48ad614SDennis Dalessandro * MADs. 4397f48ad614SDennis Dalessandro * 4398f48ad614SDennis Dalessandro * This is called by the ib_mad module. 4399f48ad614SDennis Dalessandro */ 4400f48ad614SDennis Dalessandro int hfi1_process_mad(struct ib_device *ibdev, int mad_flags, u8 port, 4401f48ad614SDennis Dalessandro const struct ib_wc *in_wc, const struct ib_grh *in_grh, 4402f48ad614SDennis Dalessandro const struct ib_mad_hdr *in_mad, size_t in_mad_size, 4403f48ad614SDennis Dalessandro struct ib_mad_hdr *out_mad, size_t *out_mad_size, 4404f48ad614SDennis Dalessandro u16 *out_mad_pkey_index) 4405f48ad614SDennis Dalessandro { 4406f48ad614SDennis Dalessandro switch (in_mad->base_version) { 4407f48ad614SDennis Dalessandro case OPA_MGMT_BASE_VERSION: 4408f48ad614SDennis Dalessandro if (unlikely(in_mad_size != sizeof(struct opa_mad))) { 44093067771cSBart Van Assche dev_err(ibdev->dev.parent, "invalid in_mad_size\n"); 4410f48ad614SDennis Dalessandro return IB_MAD_RESULT_FAILURE; 4411f48ad614SDennis Dalessandro } 4412f48ad614SDennis Dalessandro return hfi1_process_opa_mad(ibdev, mad_flags, port, 4413f48ad614SDennis Dalessandro in_wc, in_grh, 4414f48ad614SDennis Dalessandro (struct opa_mad *)in_mad, 4415f48ad614SDennis Dalessandro (struct opa_mad *)out_mad, 4416f48ad614SDennis Dalessandro out_mad_size, 4417f48ad614SDennis Dalessandro out_mad_pkey_index); 4418f48ad614SDennis Dalessandro case IB_MGMT_BASE_VERSION: 4419f48ad614SDennis Dalessandro return hfi1_process_ib_mad(ibdev, mad_flags, port, 4420f48ad614SDennis Dalessandro in_wc, in_grh, 4421f48ad614SDennis Dalessandro (const struct ib_mad *)in_mad, 4422f48ad614SDennis Dalessandro (struct ib_mad *)out_mad); 4423f48ad614SDennis Dalessandro default: 4424f48ad614SDennis Dalessandro break; 4425f48ad614SDennis Dalessandro } 4426f48ad614SDennis Dalessandro 4427f48ad614SDennis Dalessandro return IB_MAD_RESULT_FAILURE; 4428f48ad614SDennis Dalessandro } 4429