1f48ad614SDennis Dalessandro /* 2935c84acSMichael J. Ruhl * Copyright(c) 2015-2018 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> 4913c19222SDon Hiatt #include <rdma/opa_addr.h> 50f48ad614SDennis Dalessandro #define OPA_NUM_PKEY_BLOCKS_PER_SMP (OPA_SMP_DR_DATA_SIZE \ 51f48ad614SDennis Dalessandro / (OPA_PARTITION_TABLE_BLK_SIZE * sizeof(u16))) 52f48ad614SDennis Dalessandro 53f48ad614SDennis Dalessandro #include "hfi.h" 54f48ad614SDennis Dalessandro #include "mad.h" 55f48ad614SDennis Dalessandro #include "trace.h" 56f48ad614SDennis Dalessandro #include "qp.h" 572280740fSVishwanathapura, Niranjana #include "vnic.h" 58f48ad614SDennis Dalessandro 59f48ad614SDennis Dalessandro /* the reset value from the FM is supposed to be 0xffff, handle both */ 60f48ad614SDennis Dalessandro #define OPA_LINK_WIDTH_RESET_OLD 0x0fff 61f48ad614SDennis Dalessandro #define OPA_LINK_WIDTH_RESET 0xffff 62f48ad614SDennis Dalessandro 63bf90aaddSMichael J. Ruhl struct trap_node { 64bf90aaddSMichael J. Ruhl struct list_head list; 65bf90aaddSMichael J. Ruhl struct opa_mad_notice_attr data; 66bf90aaddSMichael J. Ruhl __be64 tid; 67bf90aaddSMichael J. Ruhl int len; 68bf90aaddSMichael J. Ruhl u32 retry; 69bf90aaddSMichael J. Ruhl u8 in_use; 70bf90aaddSMichael J. Ruhl u8 repress; 71bf90aaddSMichael J. Ruhl }; 72bf90aaddSMichael J. Ruhl 73f1685179SNeel Desai static int smp_length_check(u32 data_size, u32 request_len) 74f1685179SNeel Desai { 75f1685179SNeel Desai if (unlikely(request_len < data_size)) 76f1685179SNeel Desai return -EINVAL; 77f1685179SNeel Desai 78f1685179SNeel Desai return 0; 79f1685179SNeel Desai } 80f1685179SNeel Desai 81f48ad614SDennis Dalessandro static int reply(struct ib_mad_hdr *smp) 82f48ad614SDennis Dalessandro { 83f48ad614SDennis Dalessandro /* 84f48ad614SDennis Dalessandro * The verbs framework will handle the directed/LID route 85f48ad614SDennis Dalessandro * packet changes. 86f48ad614SDennis Dalessandro */ 87f48ad614SDennis Dalessandro smp->method = IB_MGMT_METHOD_GET_RESP; 88f48ad614SDennis Dalessandro if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 89f48ad614SDennis Dalessandro smp->status |= IB_SMP_DIRECTION; 90f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 91f48ad614SDennis Dalessandro } 92f48ad614SDennis Dalessandro 93f48ad614SDennis Dalessandro static inline void clear_opa_smp_data(struct opa_smp *smp) 94f48ad614SDennis Dalessandro { 95f48ad614SDennis Dalessandro void *data = opa_get_smp_data(smp); 96f48ad614SDennis Dalessandro size_t size = opa_get_smp_data_size(smp); 97f48ad614SDennis Dalessandro 98f48ad614SDennis Dalessandro memset(data, 0, size); 99f48ad614SDennis Dalessandro } 100f48ad614SDennis Dalessandro 101406310c6SSebastian Sanchez static u16 hfi1_lookup_pkey_value(struct hfi1_ibport *ibp, int pkey_idx) 102406310c6SSebastian Sanchez { 103406310c6SSebastian Sanchez struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 104406310c6SSebastian Sanchez 105406310c6SSebastian Sanchez if (pkey_idx < ARRAY_SIZE(ppd->pkeys)) 106406310c6SSebastian Sanchez return ppd->pkeys[pkey_idx]; 107406310c6SSebastian Sanchez 108406310c6SSebastian Sanchez return 0; 109406310c6SSebastian Sanchez } 110406310c6SSebastian Sanchez 11134d351f8SSebastian Sanchez void hfi1_event_pkey_change(struct hfi1_devdata *dd, u8 port) 11234d351f8SSebastian Sanchez { 11334d351f8SSebastian Sanchez struct ib_event event; 11434d351f8SSebastian Sanchez 11534d351f8SSebastian Sanchez event.event = IB_EVENT_PKEY_CHANGE; 11634d351f8SSebastian Sanchez event.device = &dd->verbs_dev.rdi.ibdev; 11734d351f8SSebastian Sanchez event.element.port_num = port; 11834d351f8SSebastian Sanchez ib_dispatch_event(&event); 11934d351f8SSebastian Sanchez } 12034d351f8SSebastian Sanchez 121bf90aaddSMichael J. Ruhl /* 122bf90aaddSMichael J. Ruhl * If the port is down, clean up all pending traps. We need to be careful 123bf90aaddSMichael J. Ruhl * with the given trap, because it may be queued. 124bf90aaddSMichael J. Ruhl */ 125bf90aaddSMichael J. Ruhl static void cleanup_traps(struct hfi1_ibport *ibp, struct trap_node *trap) 126bf90aaddSMichael J. Ruhl { 127bf90aaddSMichael J. Ruhl struct trap_node *node, *q; 128bf90aaddSMichael J. Ruhl unsigned long flags; 129bf90aaddSMichael J. Ruhl struct list_head trap_list; 130bf90aaddSMichael J. Ruhl int i; 131bf90aaddSMichael J. Ruhl 132bf90aaddSMichael J. Ruhl for (i = 0; i < RVT_MAX_TRAP_LISTS; i++) { 133bf90aaddSMichael J. Ruhl spin_lock_irqsave(&ibp->rvp.lock, flags); 134bf90aaddSMichael J. Ruhl list_replace_init(&ibp->rvp.trap_lists[i].list, &trap_list); 135bf90aaddSMichael J. Ruhl ibp->rvp.trap_lists[i].list_len = 0; 136bf90aaddSMichael J. Ruhl spin_unlock_irqrestore(&ibp->rvp.lock, flags); 137bf90aaddSMichael J. Ruhl 138bf90aaddSMichael J. Ruhl /* 139bf90aaddSMichael J. Ruhl * Remove all items from the list, freeing all the non-given 140bf90aaddSMichael J. Ruhl * traps. 141bf90aaddSMichael J. Ruhl */ 142bf90aaddSMichael J. Ruhl list_for_each_entry_safe(node, q, &trap_list, list) { 143bf90aaddSMichael J. Ruhl list_del(&node->list); 144bf90aaddSMichael J. Ruhl if (node != trap) 145bf90aaddSMichael J. Ruhl kfree(node); 146bf90aaddSMichael J. Ruhl } 147bf90aaddSMichael J. Ruhl } 148bf90aaddSMichael J. Ruhl 149bf90aaddSMichael J. Ruhl /* 150bf90aaddSMichael J. Ruhl * If this wasn't on one of the lists it would not be freed. If it 151bf90aaddSMichael J. Ruhl * was on the list, it is now safe to free. 152bf90aaddSMichael J. Ruhl */ 153bf90aaddSMichael J. Ruhl kfree(trap); 154bf90aaddSMichael J. Ruhl } 155bf90aaddSMichael J. Ruhl 156bf90aaddSMichael J. Ruhl static struct trap_node *check_and_add_trap(struct hfi1_ibport *ibp, 157bf90aaddSMichael J. Ruhl struct trap_node *trap) 158bf90aaddSMichael J. Ruhl { 159bf90aaddSMichael J. Ruhl struct trap_node *node; 160bf90aaddSMichael J. Ruhl struct trap_list *trap_list; 161bf90aaddSMichael J. Ruhl unsigned long flags; 162bf90aaddSMichael J. Ruhl unsigned long timeout; 163bf90aaddSMichael J. Ruhl int found = 0; 164ec0d8b8aSKamenee Arumugame unsigned int queue_id; 165ec0d8b8aSKamenee Arumugame static int trap_count; 166ec0d8b8aSKamenee Arumugame 167ec0d8b8aSKamenee Arumugame queue_id = trap->data.generic_type & 0x0F; 168ec0d8b8aSKamenee Arumugame if (queue_id >= RVT_MAX_TRAP_LISTS) { 169ec0d8b8aSKamenee Arumugame trap_count++; 170ec0d8b8aSKamenee Arumugame pr_err_ratelimited("hfi1: Invalid trap 0x%0x dropped. Total dropped: %d\n", 171ec0d8b8aSKamenee Arumugame trap->data.generic_type, trap_count); 172ec0d8b8aSKamenee Arumugame kfree(trap); 173ec0d8b8aSKamenee Arumugame return NULL; 174ec0d8b8aSKamenee Arumugame } 175bf90aaddSMichael J. Ruhl 176bf90aaddSMichael J. Ruhl /* 177bf90aaddSMichael J. Ruhl * Since the retry (handle timeout) does not remove a trap request 178bf90aaddSMichael J. Ruhl * from the list, all we have to do is compare the node. 179bf90aaddSMichael J. Ruhl */ 180bf90aaddSMichael J. Ruhl spin_lock_irqsave(&ibp->rvp.lock, flags); 181ec0d8b8aSKamenee Arumugame trap_list = &ibp->rvp.trap_lists[queue_id]; 182bf90aaddSMichael J. Ruhl 183bf90aaddSMichael J. Ruhl list_for_each_entry(node, &trap_list->list, list) { 184bf90aaddSMichael J. Ruhl if (node == trap) { 185bf90aaddSMichael J. Ruhl node->retry++; 186bf90aaddSMichael J. Ruhl found = 1; 187bf90aaddSMichael J. Ruhl break; 188bf90aaddSMichael J. Ruhl } 189bf90aaddSMichael J. Ruhl } 190bf90aaddSMichael J. Ruhl 191bf90aaddSMichael J. Ruhl /* If it is not on the list, add it, limited to RVT-MAX_TRAP_LEN. */ 192bf90aaddSMichael J. Ruhl if (!found) { 193bf90aaddSMichael J. Ruhl if (trap_list->list_len < RVT_MAX_TRAP_LEN) { 194bf90aaddSMichael J. Ruhl trap_list->list_len++; 195bf90aaddSMichael J. Ruhl list_add_tail(&trap->list, &trap_list->list); 196bf90aaddSMichael J. Ruhl } else { 197028e0a67SColin Ian King pr_warn_ratelimited("hfi1: Maximum trap limit reached for 0x%0x traps\n", 198bf90aaddSMichael J. Ruhl trap->data.generic_type); 199bf90aaddSMichael J. Ruhl kfree(trap); 200bf90aaddSMichael J. Ruhl } 201bf90aaddSMichael J. Ruhl } 202bf90aaddSMichael J. Ruhl 203bf90aaddSMichael J. Ruhl /* 204bf90aaddSMichael J. Ruhl * Next check to see if there is a timer pending. If not, set it up 205bf90aaddSMichael J. Ruhl * and get the first trap from the list. 206bf90aaddSMichael J. Ruhl */ 207bf90aaddSMichael J. Ruhl node = NULL; 208bf90aaddSMichael J. Ruhl if (!timer_pending(&ibp->rvp.trap_timer)) { 209bf90aaddSMichael J. Ruhl /* 210bf90aaddSMichael J. Ruhl * o14-2 211bf90aaddSMichael J. Ruhl * If the time out is set we have to wait until it expires 212bf90aaddSMichael J. Ruhl * before the trap can be sent. 213bf90aaddSMichael J. Ruhl * This should be > RVT_TRAP_TIMEOUT 214bf90aaddSMichael J. Ruhl */ 215bf90aaddSMichael J. Ruhl timeout = (RVT_TRAP_TIMEOUT * 216bf90aaddSMichael J. Ruhl (1UL << ibp->rvp.subnet_timeout)) / 1000; 217bf90aaddSMichael J. Ruhl mod_timer(&ibp->rvp.trap_timer, 218bf90aaddSMichael J. Ruhl jiffies + usecs_to_jiffies(timeout)); 219bf90aaddSMichael J. Ruhl node = list_first_entry(&trap_list->list, struct trap_node, 220bf90aaddSMichael J. Ruhl list); 221bf90aaddSMichael J. Ruhl node->in_use = 1; 222bf90aaddSMichael J. Ruhl } 223bf90aaddSMichael J. Ruhl spin_unlock_irqrestore(&ibp->rvp.lock, flags); 224bf90aaddSMichael J. Ruhl 225bf90aaddSMichael J. Ruhl return node; 226bf90aaddSMichael J. Ruhl } 227bf90aaddSMichael J. Ruhl 228bf90aaddSMichael J. Ruhl static void subn_handle_opa_trap_repress(struct hfi1_ibport *ibp, 229bf90aaddSMichael J. Ruhl struct opa_smp *smp) 230bf90aaddSMichael J. Ruhl { 231bf90aaddSMichael J. Ruhl struct trap_list *trap_list; 232bf90aaddSMichael J. Ruhl struct trap_node *trap; 233bf90aaddSMichael J. Ruhl unsigned long flags; 234bf90aaddSMichael J. Ruhl int i; 235bf90aaddSMichael J. Ruhl 236bf90aaddSMichael J. Ruhl if (smp->attr_id != IB_SMP_ATTR_NOTICE) 237bf90aaddSMichael J. Ruhl return; 238bf90aaddSMichael J. Ruhl 239bf90aaddSMichael J. Ruhl spin_lock_irqsave(&ibp->rvp.lock, flags); 240bf90aaddSMichael J. Ruhl for (i = 0; i < RVT_MAX_TRAP_LISTS; i++) { 241bf90aaddSMichael J. Ruhl trap_list = &ibp->rvp.trap_lists[i]; 242bf90aaddSMichael J. Ruhl trap = list_first_entry_or_null(&trap_list->list, 243bf90aaddSMichael J. Ruhl struct trap_node, list); 244bf90aaddSMichael J. Ruhl if (trap && trap->tid == smp->tid) { 245bf90aaddSMichael J. Ruhl if (trap->in_use) { 246bf90aaddSMichael J. Ruhl trap->repress = 1; 247bf90aaddSMichael J. Ruhl } else { 248bf90aaddSMichael J. Ruhl trap_list->list_len--; 249bf90aaddSMichael J. Ruhl list_del(&trap->list); 250bf90aaddSMichael J. Ruhl kfree(trap); 251bf90aaddSMichael J. Ruhl } 252bf90aaddSMichael J. Ruhl break; 253bf90aaddSMichael J. Ruhl } 254bf90aaddSMichael J. Ruhl } 255bf90aaddSMichael J. Ruhl spin_unlock_irqrestore(&ibp->rvp.lock, flags); 256bf90aaddSMichael J. Ruhl } 257bf90aaddSMichael J. Ruhl 25851e658f5SDasaratharaman Chandramouli static void hfi1_update_sm_ah_attr(struct hfi1_ibport *ibp, 25951e658f5SDasaratharaman Chandramouli struct rdma_ah_attr *attr, u32 dlid) 26051e658f5SDasaratharaman Chandramouli { 26151e658f5SDasaratharaman Chandramouli rdma_ah_set_dlid(attr, dlid); 26251e658f5SDasaratharaman Chandramouli rdma_ah_set_port_num(attr, ppd_from_ibp(ibp)->port); 26351e658f5SDasaratharaman Chandramouli if (dlid >= be16_to_cpu(IB_MULTICAST_LID_BASE)) { 26451e658f5SDasaratharaman Chandramouli struct ib_global_route *grh = rdma_ah_retrieve_grh(attr); 26551e658f5SDasaratharaman Chandramouli 26651e658f5SDasaratharaman Chandramouli rdma_ah_set_ah_flags(attr, IB_AH_GRH); 26751e658f5SDasaratharaman Chandramouli grh->sgid_index = 0; 26851e658f5SDasaratharaman Chandramouli grh->hop_limit = 1; 26951e658f5SDasaratharaman Chandramouli grh->dgid.global.subnet_prefix = 27051e658f5SDasaratharaman Chandramouli ibp->rvp.gid_prefix; 27151e658f5SDasaratharaman Chandramouli grh->dgid.global.interface_id = OPA_MAKE_ID(dlid); 27251e658f5SDasaratharaman Chandramouli } 27351e658f5SDasaratharaman Chandramouli } 27451e658f5SDasaratharaman Chandramouli 27551e658f5SDasaratharaman Chandramouli static int hfi1_modify_qp0_ah(struct hfi1_ibport *ibp, 27651e658f5SDasaratharaman Chandramouli struct rvt_ah *ah, u32 dlid) 27751e658f5SDasaratharaman Chandramouli { 27851e658f5SDasaratharaman Chandramouli struct rdma_ah_attr attr; 27951e658f5SDasaratharaman Chandramouli struct rvt_qp *qp0; 28051e658f5SDasaratharaman Chandramouli int ret = -EINVAL; 28151e658f5SDasaratharaman Chandramouli 28251e658f5SDasaratharaman Chandramouli memset(&attr, 0, sizeof(attr)); 28351e658f5SDasaratharaman Chandramouli attr.type = ah->ibah.type; 28451e658f5SDasaratharaman Chandramouli hfi1_update_sm_ah_attr(ibp, &attr, dlid); 28551e658f5SDasaratharaman Chandramouli rcu_read_lock(); 28651e658f5SDasaratharaman Chandramouli qp0 = rcu_dereference(ibp->rvp.qp[0]); 28751e658f5SDasaratharaman Chandramouli if (qp0) 28851e658f5SDasaratharaman Chandramouli ret = rdma_modify_ah(&ah->ibah, &attr); 28951e658f5SDasaratharaman Chandramouli rcu_read_unlock(); 29051e658f5SDasaratharaman Chandramouli return ret; 29151e658f5SDasaratharaman Chandramouli } 29251e658f5SDasaratharaman Chandramouli 29351e658f5SDasaratharaman Chandramouli static struct ib_ah *hfi1_create_qp0_ah(struct hfi1_ibport *ibp, u32 dlid) 29451e658f5SDasaratharaman Chandramouli { 29551e658f5SDasaratharaman Chandramouli struct rdma_ah_attr attr; 29651e658f5SDasaratharaman Chandramouli struct ib_ah *ah = ERR_PTR(-EINVAL); 29751e658f5SDasaratharaman Chandramouli struct rvt_qp *qp0; 29851e658f5SDasaratharaman Chandramouli struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 29951e658f5SDasaratharaman Chandramouli struct hfi1_devdata *dd = dd_from_ppd(ppd); 30051e658f5SDasaratharaman Chandramouli u8 port_num = ppd->port; 30151e658f5SDasaratharaman Chandramouli 30251e658f5SDasaratharaman Chandramouli memset(&attr, 0, sizeof(attr)); 30351e658f5SDasaratharaman Chandramouli attr.type = rdma_ah_find_type(&dd->verbs_dev.rdi.ibdev, port_num); 30451e658f5SDasaratharaman Chandramouli hfi1_update_sm_ah_attr(ibp, &attr, dlid); 30551e658f5SDasaratharaman Chandramouli rcu_read_lock(); 30651e658f5SDasaratharaman Chandramouli qp0 = rcu_dereference(ibp->rvp.qp[0]); 30751e658f5SDasaratharaman Chandramouli if (qp0) 308b090c4e3SGal Pressman ah = rdma_create_ah(qp0->ibqp.pd, &attr, 0); 30951e658f5SDasaratharaman Chandramouli rcu_read_unlock(); 31051e658f5SDasaratharaman Chandramouli return ah; 31151e658f5SDasaratharaman Chandramouli } 31251e658f5SDasaratharaman Chandramouli 313bf90aaddSMichael J. Ruhl static void send_trap(struct hfi1_ibport *ibp, struct trap_node *trap) 314f48ad614SDennis Dalessandro { 315f48ad614SDennis Dalessandro struct ib_mad_send_buf *send_buf; 316f48ad614SDennis Dalessandro struct ib_mad_agent *agent; 317f48ad614SDennis Dalessandro struct opa_smp *smp; 318f48ad614SDennis Dalessandro unsigned long flags; 319f48ad614SDennis Dalessandro int pkey_idx; 320f48ad614SDennis Dalessandro u32 qpn = ppd_from_ibp(ibp)->sm_trap_qp; 321f48ad614SDennis Dalessandro 322f48ad614SDennis Dalessandro agent = ibp->rvp.send_agent; 323bf90aaddSMichael J. Ruhl if (!agent) { 324bf90aaddSMichael J. Ruhl cleanup_traps(ibp, trap); 325f48ad614SDennis Dalessandro return; 326bf90aaddSMichael J. Ruhl } 327f48ad614SDennis Dalessandro 328f48ad614SDennis Dalessandro /* o14-3.2.1 */ 329bf90aaddSMichael J. Ruhl if (driver_lstate(ppd_from_ibp(ibp)) != IB_PORT_ACTIVE) { 330bf90aaddSMichael J. Ruhl cleanup_traps(ibp, trap); 331f48ad614SDennis Dalessandro return; 332bf90aaddSMichael J. Ruhl } 333f48ad614SDennis Dalessandro 334bf90aaddSMichael J. Ruhl /* Add the trap to the list if necessary and see if we can send it */ 335bf90aaddSMichael J. Ruhl trap = check_and_add_trap(ibp, trap); 336bf90aaddSMichael J. Ruhl if (!trap) 337f48ad614SDennis Dalessandro return; 338f48ad614SDennis Dalessandro 339f48ad614SDennis Dalessandro pkey_idx = hfi1_lookup_pkey_idx(ibp, LIM_MGMT_P_KEY); 340f48ad614SDennis Dalessandro if (pkey_idx < 0) { 341f48ad614SDennis Dalessandro pr_warn("%s: failed to find limited mgmt pkey, defaulting 0x%x\n", 342f48ad614SDennis Dalessandro __func__, hfi1_get_pkey(ibp, 1)); 343f48ad614SDennis Dalessandro pkey_idx = 1; 344f48ad614SDennis Dalessandro } 345f48ad614SDennis Dalessandro 346f48ad614SDennis Dalessandro send_buf = ib_create_send_mad(agent, qpn, pkey_idx, 0, 347f48ad614SDennis Dalessandro IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, 348f48ad614SDennis Dalessandro GFP_ATOMIC, IB_MGMT_BASE_VERSION); 349f48ad614SDennis Dalessandro if (IS_ERR(send_buf)) 350f48ad614SDennis Dalessandro return; 351f48ad614SDennis Dalessandro 352f48ad614SDennis Dalessandro smp = send_buf->mad; 353f48ad614SDennis Dalessandro smp->base_version = OPA_MGMT_BASE_VERSION; 354f48ad614SDennis Dalessandro smp->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; 3559fa240bbSHal Rosenstock smp->class_version = OPA_SM_CLASS_VERSION; 356f48ad614SDennis Dalessandro smp->method = IB_MGMT_METHOD_TRAP; 357bf90aaddSMichael J. Ruhl 358bf90aaddSMichael J. Ruhl /* Only update the transaction ID for new traps (o13-5). */ 359bf90aaddSMichael J. Ruhl if (trap->tid == 0) { 360f48ad614SDennis Dalessandro ibp->rvp.tid++; 361bf90aaddSMichael J. Ruhl /* make sure that tid != 0 */ 362bf90aaddSMichael J. Ruhl if (ibp->rvp.tid == 0) 363bf90aaddSMichael J. Ruhl ibp->rvp.tid++; 364bf90aaddSMichael J. Ruhl trap->tid = cpu_to_be64(ibp->rvp.tid); 365bf90aaddSMichael J. Ruhl } 366bf90aaddSMichael J. Ruhl smp->tid = trap->tid; 367bf90aaddSMichael J. Ruhl 368f48ad614SDennis Dalessandro smp->attr_id = IB_SMP_ATTR_NOTICE; 369f48ad614SDennis Dalessandro /* o14-1: smp->mkey = 0; */ 370bf90aaddSMichael J. Ruhl 371bf90aaddSMichael J. Ruhl memcpy(smp->route.lid.data, &trap->data, trap->len); 372f48ad614SDennis Dalessandro 373f48ad614SDennis Dalessandro spin_lock_irqsave(&ibp->rvp.lock, flags); 374f48ad614SDennis Dalessandro if (!ibp->rvp.sm_ah) { 375f48ad614SDennis Dalessandro if (ibp->rvp.sm_lid != be16_to_cpu(IB_LID_PERMISSIVE)) { 376f48ad614SDennis Dalessandro struct ib_ah *ah; 377f48ad614SDennis Dalessandro 378f48ad614SDennis Dalessandro ah = hfi1_create_qp0_ah(ibp, ibp->rvp.sm_lid); 379f48ad614SDennis Dalessandro if (IS_ERR(ah)) { 380bf90aaddSMichael J. Ruhl spin_unlock_irqrestore(&ibp->rvp.lock, flags); 381bf90aaddSMichael J. Ruhl return; 382bf90aaddSMichael J. Ruhl } 383f48ad614SDennis Dalessandro send_buf->ah = ah; 384f48ad614SDennis Dalessandro ibp->rvp.sm_ah = ibah_to_rvtah(ah); 385f48ad614SDennis Dalessandro } else { 386bf90aaddSMichael J. Ruhl spin_unlock_irqrestore(&ibp->rvp.lock, flags); 387bf90aaddSMichael J. Ruhl return; 388f48ad614SDennis Dalessandro } 389f48ad614SDennis Dalessandro } else { 390f48ad614SDennis Dalessandro send_buf->ah = &ibp->rvp.sm_ah->ibah; 391bf90aaddSMichael J. Ruhl } 392bf90aaddSMichael J. Ruhl 393bf90aaddSMichael J. Ruhl /* 394bf90aaddSMichael J. Ruhl * If the trap was repressed while things were getting set up, don't 395bf90aaddSMichael J. Ruhl * bother sending it. This could happen for a retry. 396bf90aaddSMichael J. Ruhl */ 397bf90aaddSMichael J. Ruhl if (trap->repress) { 398bf90aaddSMichael J. Ruhl list_del(&trap->list); 399bf90aaddSMichael J. Ruhl spin_unlock_irqrestore(&ibp->rvp.lock, flags); 400bf90aaddSMichael J. Ruhl kfree(trap); 401bf90aaddSMichael J. Ruhl ib_free_send_mad(send_buf); 402bf90aaddSMichael J. Ruhl return; 403bf90aaddSMichael J. Ruhl } 404bf90aaddSMichael J. Ruhl 405bf90aaddSMichael J. Ruhl trap->in_use = 0; 406bf90aaddSMichael J. Ruhl spin_unlock_irqrestore(&ibp->rvp.lock, flags); 407bf90aaddSMichael J. Ruhl 408bf90aaddSMichael J. Ruhl if (ib_post_send_mad(send_buf, NULL)) 409bf90aaddSMichael J. Ruhl ib_free_send_mad(send_buf); 410bf90aaddSMichael J. Ruhl } 411bf90aaddSMichael J. Ruhl 4128064135eSKees Cook void hfi1_handle_trap_timer(struct timer_list *t) 413bf90aaddSMichael J. Ruhl { 4148064135eSKees Cook struct hfi1_ibport *ibp = from_timer(ibp, t, rvp.trap_timer); 415bf90aaddSMichael J. Ruhl struct trap_node *trap = NULL; 416bf90aaddSMichael J. Ruhl unsigned long flags; 417bf90aaddSMichael J. Ruhl int i; 418bf90aaddSMichael J. Ruhl 419bf90aaddSMichael J. Ruhl /* Find the trap with the highest priority */ 420bf90aaddSMichael J. Ruhl spin_lock_irqsave(&ibp->rvp.lock, flags); 421bf90aaddSMichael J. Ruhl for (i = 0; !trap && i < RVT_MAX_TRAP_LISTS; i++) { 422bf90aaddSMichael J. Ruhl trap = list_first_entry_or_null(&ibp->rvp.trap_lists[i].list, 423bf90aaddSMichael J. Ruhl struct trap_node, list); 424f48ad614SDennis Dalessandro } 425f48ad614SDennis Dalessandro spin_unlock_irqrestore(&ibp->rvp.lock, flags); 426f48ad614SDennis Dalessandro 427bf90aaddSMichael J. Ruhl if (trap) 428bf90aaddSMichael J. Ruhl send_trap(ibp, trap); 429f48ad614SDennis Dalessandro } 430bf90aaddSMichael J. Ruhl 431bf90aaddSMichael J. Ruhl static struct trap_node *create_trap_node(u8 type, __be16 trap_num, u32 lid) 432bf90aaddSMichael J. Ruhl { 433bf90aaddSMichael J. Ruhl struct trap_node *trap; 434bf90aaddSMichael J. Ruhl 435bf90aaddSMichael J. Ruhl trap = kzalloc(sizeof(*trap), GFP_ATOMIC); 436bf90aaddSMichael J. Ruhl if (!trap) 437bf90aaddSMichael J. Ruhl return NULL; 438bf90aaddSMichael J. Ruhl 439bf90aaddSMichael J. Ruhl INIT_LIST_HEAD(&trap->list); 440bf90aaddSMichael J. Ruhl trap->data.generic_type = type; 441bf90aaddSMichael J. Ruhl trap->data.prod_type_lsb = IB_NOTICE_PROD_CA; 442bf90aaddSMichael J. Ruhl trap->data.trap_num = trap_num; 443bf90aaddSMichael J. Ruhl trap->data.issuer_lid = cpu_to_be32(lid); 444bf90aaddSMichael J. Ruhl 445bf90aaddSMichael J. Ruhl return trap; 446f48ad614SDennis Dalessandro } 447f48ad614SDennis Dalessandro 448f48ad614SDennis Dalessandro /* 44913d84914SDennis Dalessandro * Send a bad P_Key trap (ch. 14.3.8). 450f48ad614SDennis Dalessandro */ 45113d84914SDennis Dalessandro void hfi1_bad_pkey(struct hfi1_ibport *ibp, u32 key, u32 sl, 45288733e3bSDon Hiatt u32 qp1, u32 qp2, u32 lid1, u32 lid2) 453f48ad614SDennis Dalessandro { 454bf90aaddSMichael J. Ruhl struct trap_node *trap; 455f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 456f48ad614SDennis Dalessandro 457f48ad614SDennis Dalessandro ibp->rvp.n_pkt_drops++; 45813d84914SDennis Dalessandro ibp->rvp.pkey_violations++; 459f48ad614SDennis Dalessandro 460bf90aaddSMichael J. Ruhl trap = create_trap_node(IB_NOTICE_TYPE_SECURITY, OPA_TRAP_BAD_P_KEY, 461bf90aaddSMichael J. Ruhl lid); 462bf90aaddSMichael J. Ruhl if (!trap) 463bf90aaddSMichael J. Ruhl return; 464f48ad614SDennis Dalessandro 465bf90aaddSMichael J. Ruhl /* Send violation trap */ 46688733e3bSDon Hiatt trap->data.ntc_257_258.lid1 = cpu_to_be32(lid1); 46788733e3bSDon Hiatt trap->data.ntc_257_258.lid2 = cpu_to_be32(lid2); 468bf90aaddSMichael J. Ruhl trap->data.ntc_257_258.key = cpu_to_be32(key); 469bf90aaddSMichael J. Ruhl trap->data.ntc_257_258.sl = sl << 3; 470bf90aaddSMichael J. Ruhl trap->data.ntc_257_258.qp1 = cpu_to_be32(qp1); 471bf90aaddSMichael J. Ruhl trap->data.ntc_257_258.qp2 = cpu_to_be32(qp2); 472bf90aaddSMichael J. Ruhl 473bf90aaddSMichael J. Ruhl trap->len = sizeof(trap->data); 474bf90aaddSMichael J. Ruhl send_trap(ibp, trap); 475f48ad614SDennis Dalessandro } 476f48ad614SDennis Dalessandro 477f48ad614SDennis Dalessandro /* 478f48ad614SDennis Dalessandro * Send a bad M_Key trap (ch. 14.3.9). 479f48ad614SDennis Dalessandro */ 480f48ad614SDennis Dalessandro static void bad_mkey(struct hfi1_ibport *ibp, struct ib_mad_hdr *mad, 481f48ad614SDennis Dalessandro __be64 mkey, __be32 dr_slid, u8 return_path[], u8 hop_cnt) 482f48ad614SDennis Dalessandro { 483bf90aaddSMichael J. Ruhl struct trap_node *trap; 484f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 485f48ad614SDennis Dalessandro 486bf90aaddSMichael J. Ruhl trap = create_trap_node(IB_NOTICE_TYPE_SECURITY, OPA_TRAP_BAD_M_KEY, 487bf90aaddSMichael J. Ruhl lid); 488bf90aaddSMichael J. Ruhl if (!trap) 489bf90aaddSMichael J. Ruhl return; 490bf90aaddSMichael J. Ruhl 491f48ad614SDennis Dalessandro /* Send violation trap */ 492bf90aaddSMichael J. Ruhl trap->data.ntc_256.lid = trap->data.issuer_lid; 493bf90aaddSMichael J. Ruhl trap->data.ntc_256.method = mad->method; 494bf90aaddSMichael J. Ruhl trap->data.ntc_256.attr_id = mad->attr_id; 495bf90aaddSMichael J. Ruhl trap->data.ntc_256.attr_mod = mad->attr_mod; 496bf90aaddSMichael J. Ruhl trap->data.ntc_256.mkey = mkey; 497f48ad614SDennis Dalessandro if (mad->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 498bf90aaddSMichael J. Ruhl trap->data.ntc_256.dr_slid = dr_slid; 499bf90aaddSMichael J. Ruhl trap->data.ntc_256.dr_trunc_hop = IB_NOTICE_TRAP_DR_NOTICE; 500bf90aaddSMichael J. Ruhl if (hop_cnt > ARRAY_SIZE(trap->data.ntc_256.dr_rtn_path)) { 501bf90aaddSMichael J. Ruhl trap->data.ntc_256.dr_trunc_hop |= 502f48ad614SDennis Dalessandro IB_NOTICE_TRAP_DR_TRUNC; 503bf90aaddSMichael J. Ruhl hop_cnt = ARRAY_SIZE(trap->data.ntc_256.dr_rtn_path); 504f48ad614SDennis Dalessandro } 505bf90aaddSMichael J. Ruhl trap->data.ntc_256.dr_trunc_hop |= hop_cnt; 506bf90aaddSMichael J. Ruhl memcpy(trap->data.ntc_256.dr_rtn_path, return_path, 507f48ad614SDennis Dalessandro hop_cnt); 508f48ad614SDennis Dalessandro } 509f48ad614SDennis Dalessandro 510bf90aaddSMichael J. Ruhl trap->len = sizeof(trap->data); 511bf90aaddSMichael J. Ruhl 512bf90aaddSMichael J. Ruhl send_trap(ibp, trap); 513f48ad614SDennis Dalessandro } 514f48ad614SDennis Dalessandro 515f48ad614SDennis Dalessandro /* 516f48ad614SDennis Dalessandro * Send a Port Capability Mask Changed trap (ch. 14.3.11). 517f48ad614SDennis Dalessandro */ 518f48ad614SDennis Dalessandro void hfi1_cap_mask_chg(struct rvt_dev_info *rdi, u8 port_num) 519f48ad614SDennis Dalessandro { 520bf90aaddSMichael J. Ruhl struct trap_node *trap; 521f48ad614SDennis Dalessandro struct hfi1_ibdev *verbs_dev = dev_from_rdi(rdi); 522f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_dev(verbs_dev); 523f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = &dd->pport[port_num - 1].ibport_data; 524f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 525f48ad614SDennis Dalessandro 526bf90aaddSMichael J. Ruhl trap = create_trap_node(IB_NOTICE_TYPE_INFO, 527bf90aaddSMichael J. Ruhl OPA_TRAP_CHANGE_CAPABILITY, 528bf90aaddSMichael J. Ruhl lid); 529bf90aaddSMichael J. Ruhl if (!trap) 530bf90aaddSMichael J. Ruhl return; 531f48ad614SDennis Dalessandro 532bf90aaddSMichael J. Ruhl trap->data.ntc_144.lid = trap->data.issuer_lid; 533bf90aaddSMichael J. Ruhl trap->data.ntc_144.new_cap_mask = cpu_to_be32(ibp->rvp.port_cap_flags); 534bf90aaddSMichael J. Ruhl trap->data.ntc_144.cap_mask3 = cpu_to_be16(ibp->rvp.port_cap3_flags); 535f48ad614SDennis Dalessandro 536bf90aaddSMichael J. Ruhl trap->len = sizeof(trap->data); 537bf90aaddSMichael J. Ruhl send_trap(ibp, trap); 538f48ad614SDennis Dalessandro } 539f48ad614SDennis Dalessandro 540f48ad614SDennis Dalessandro /* 541f48ad614SDennis Dalessandro * Send a System Image GUID Changed trap (ch. 14.3.12). 542f48ad614SDennis Dalessandro */ 543f48ad614SDennis Dalessandro void hfi1_sys_guid_chg(struct hfi1_ibport *ibp) 544f48ad614SDennis Dalessandro { 545bf90aaddSMichael J. Ruhl struct trap_node *trap; 546f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 547f48ad614SDennis Dalessandro 548bf90aaddSMichael J. Ruhl trap = create_trap_node(IB_NOTICE_TYPE_INFO, OPA_TRAP_CHANGE_SYSGUID, 549bf90aaddSMichael J. Ruhl lid); 550bf90aaddSMichael J. Ruhl if (!trap) 551bf90aaddSMichael J. Ruhl return; 552f48ad614SDennis Dalessandro 553bf90aaddSMichael J. Ruhl trap->data.ntc_145.new_sys_guid = ib_hfi1_sys_image_guid; 554bf90aaddSMichael J. Ruhl trap->data.ntc_145.lid = trap->data.issuer_lid; 555f48ad614SDennis Dalessandro 556bf90aaddSMichael J. Ruhl trap->len = sizeof(trap->data); 557bf90aaddSMichael J. Ruhl send_trap(ibp, trap); 558f48ad614SDennis Dalessandro } 559f48ad614SDennis Dalessandro 560f48ad614SDennis Dalessandro /* 561f48ad614SDennis Dalessandro * Send a Node Description Changed trap (ch. 14.3.13). 562f48ad614SDennis Dalessandro */ 563f48ad614SDennis Dalessandro void hfi1_node_desc_chg(struct hfi1_ibport *ibp) 564f48ad614SDennis Dalessandro { 565bf90aaddSMichael J. Ruhl struct trap_node *trap; 566f48ad614SDennis Dalessandro u32 lid = ppd_from_ibp(ibp)->lid; 567f48ad614SDennis Dalessandro 568bf90aaddSMichael J. Ruhl trap = create_trap_node(IB_NOTICE_TYPE_INFO, 569bf90aaddSMichael J. Ruhl OPA_TRAP_CHANGE_CAPABILITY, 570bf90aaddSMichael J. Ruhl lid); 571bf90aaddSMichael J. Ruhl if (!trap) 572bf90aaddSMichael J. Ruhl return; 573f48ad614SDennis Dalessandro 574bf90aaddSMichael J. Ruhl trap->data.ntc_144.lid = trap->data.issuer_lid; 575bf90aaddSMichael J. Ruhl trap->data.ntc_144.change_flags = 576f48ad614SDennis Dalessandro cpu_to_be16(OPA_NOTICE_TRAP_NODE_DESC_CHG); 577f48ad614SDennis Dalessandro 578bf90aaddSMichael J. Ruhl trap->len = sizeof(trap->data); 579bf90aaddSMichael J. Ruhl send_trap(ibp, trap); 580f48ad614SDennis Dalessandro } 581f48ad614SDennis Dalessandro 582f48ad614SDennis Dalessandro static int __subn_get_opa_nodedesc(struct opa_smp *smp, u32 am, 583f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, 584f1685179SNeel Desai u8 port, u32 *resp_len, u32 max_len) 585f48ad614SDennis Dalessandro { 586f48ad614SDennis Dalessandro struct opa_node_description *nd; 587f48ad614SDennis Dalessandro 588f1685179SNeel Desai if (am || smp_length_check(sizeof(*nd), max_len)) { 589f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 590f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 591f48ad614SDennis Dalessandro } 592f48ad614SDennis Dalessandro 593f48ad614SDennis Dalessandro nd = (struct opa_node_description *)data; 594f48ad614SDennis Dalessandro 595f48ad614SDennis Dalessandro memcpy(nd->data, ibdev->node_desc, sizeof(nd->data)); 596f48ad614SDennis Dalessandro 597f48ad614SDennis Dalessandro if (resp_len) 598f48ad614SDennis Dalessandro *resp_len += sizeof(*nd); 599f48ad614SDennis Dalessandro 600f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 601f48ad614SDennis Dalessandro } 602f48ad614SDennis Dalessandro 603f48ad614SDennis Dalessandro static int __subn_get_opa_nodeinfo(struct opa_smp *smp, u32 am, u8 *data, 604f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 605f1685179SNeel Desai u32 *resp_len, u32 max_len) 606f48ad614SDennis Dalessandro { 607f48ad614SDennis Dalessandro struct opa_node_info *ni; 608f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 609f48ad614SDennis Dalessandro unsigned pidx = port - 1; /* IB number port from 1, hw from 0 */ 610f48ad614SDennis Dalessandro 611f48ad614SDennis Dalessandro ni = (struct opa_node_info *)data; 612f48ad614SDennis Dalessandro 613f48ad614SDennis Dalessandro /* GUID 0 is illegal */ 614a6cd5f08SJakub Pawlak if (am || pidx >= dd->num_pports || ibdev->node_guid == 0 || 615f1685179SNeel Desai smp_length_check(sizeof(*ni), max_len) || 616a6cd5f08SJakub Pawlak get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX) == 0) { 617f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 618f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 619f48ad614SDennis Dalessandro } 620f48ad614SDennis Dalessandro 621a6cd5f08SJakub Pawlak ni->port_guid = get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX); 622f48ad614SDennis Dalessandro ni->base_version = OPA_MGMT_BASE_VERSION; 6239fa240bbSHal Rosenstock ni->class_version = OPA_SM_CLASS_VERSION; 624f48ad614SDennis Dalessandro ni->node_type = 1; /* channel adapter */ 625f48ad614SDennis Dalessandro ni->num_ports = ibdev->phys_port_cnt; 626f48ad614SDennis Dalessandro /* This is already in network order */ 627f48ad614SDennis Dalessandro ni->system_image_guid = ib_hfi1_sys_image_guid; 628a6cd5f08SJakub Pawlak ni->node_guid = ibdev->node_guid; 629f48ad614SDennis Dalessandro ni->partition_cap = cpu_to_be16(hfi1_get_npkeys(dd)); 630f48ad614SDennis Dalessandro ni->device_id = cpu_to_be16(dd->pcidev->device); 631f48ad614SDennis Dalessandro ni->revision = cpu_to_be32(dd->minrev); 632f48ad614SDennis Dalessandro ni->local_port_num = port; 633f48ad614SDennis Dalessandro ni->vendor_id[0] = dd->oui1; 634f48ad614SDennis Dalessandro ni->vendor_id[1] = dd->oui2; 635f48ad614SDennis Dalessandro ni->vendor_id[2] = dd->oui3; 636f48ad614SDennis Dalessandro 637f48ad614SDennis Dalessandro if (resp_len) 638f48ad614SDennis Dalessandro *resp_len += sizeof(*ni); 639f48ad614SDennis Dalessandro 640f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 641f48ad614SDennis Dalessandro } 642f48ad614SDennis Dalessandro 643f48ad614SDennis Dalessandro static int subn_get_nodeinfo(struct ib_smp *smp, struct ib_device *ibdev, 644f48ad614SDennis Dalessandro u8 port) 645f48ad614SDennis Dalessandro { 646f48ad614SDennis Dalessandro struct ib_node_info *nip = (struct ib_node_info *)&smp->data; 647f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 648f48ad614SDennis Dalessandro unsigned pidx = port - 1; /* IB number port from 1, hw from 0 */ 649f48ad614SDennis Dalessandro 650f48ad614SDennis Dalessandro /* GUID 0 is illegal */ 651f48ad614SDennis Dalessandro if (smp->attr_mod || pidx >= dd->num_pports || 652a6cd5f08SJakub Pawlak ibdev->node_guid == 0 || 653a6cd5f08SJakub Pawlak get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX) == 0) { 654f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 655a6cd5f08SJakub Pawlak return reply((struct ib_mad_hdr *)smp); 656a6cd5f08SJakub Pawlak } 657f48ad614SDennis Dalessandro 658a6cd5f08SJakub Pawlak nip->port_guid = get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX); 659f48ad614SDennis Dalessandro nip->base_version = OPA_MGMT_BASE_VERSION; 6609fa240bbSHal Rosenstock nip->class_version = OPA_SM_CLASS_VERSION; 661f48ad614SDennis Dalessandro nip->node_type = 1; /* channel adapter */ 662f48ad614SDennis Dalessandro nip->num_ports = ibdev->phys_port_cnt; 663f48ad614SDennis Dalessandro /* This is already in network order */ 664f48ad614SDennis Dalessandro nip->sys_guid = ib_hfi1_sys_image_guid; 665a6cd5f08SJakub Pawlak nip->node_guid = ibdev->node_guid; 666f48ad614SDennis Dalessandro nip->partition_cap = cpu_to_be16(hfi1_get_npkeys(dd)); 667f48ad614SDennis Dalessandro nip->device_id = cpu_to_be16(dd->pcidev->device); 668f48ad614SDennis Dalessandro nip->revision = cpu_to_be32(dd->minrev); 669f48ad614SDennis Dalessandro nip->local_port_num = port; 670f48ad614SDennis Dalessandro nip->vendor_id[0] = dd->oui1; 671f48ad614SDennis Dalessandro nip->vendor_id[1] = dd->oui2; 672f48ad614SDennis Dalessandro nip->vendor_id[2] = dd->oui3; 673f48ad614SDennis Dalessandro 674f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 675f48ad614SDennis Dalessandro } 676f48ad614SDennis Dalessandro 677f48ad614SDennis Dalessandro static void set_link_width_enabled(struct hfi1_pportdata *ppd, u32 w) 678f48ad614SDennis Dalessandro { 679f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_LWID_ENB, w); 680f48ad614SDennis Dalessandro } 681f48ad614SDennis Dalessandro 682f48ad614SDennis Dalessandro static void set_link_width_downgrade_enabled(struct hfi1_pportdata *ppd, u32 w) 683f48ad614SDennis Dalessandro { 684f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_LWID_DG_ENB, w); 685f48ad614SDennis Dalessandro } 686f48ad614SDennis Dalessandro 687f48ad614SDennis Dalessandro static void set_link_speed_enabled(struct hfi1_pportdata *ppd, u32 s) 688f48ad614SDennis Dalessandro { 689f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_SPD_ENB, s); 690f48ad614SDennis Dalessandro } 691f48ad614SDennis Dalessandro 692f48ad614SDennis Dalessandro static int check_mkey(struct hfi1_ibport *ibp, struct ib_mad_hdr *mad, 693f48ad614SDennis Dalessandro int mad_flags, __be64 mkey, __be32 dr_slid, 694f48ad614SDennis Dalessandro u8 return_path[], u8 hop_cnt) 695f48ad614SDennis Dalessandro { 696f48ad614SDennis Dalessandro int valid_mkey = 0; 697f48ad614SDennis Dalessandro int ret = 0; 698f48ad614SDennis Dalessandro 699f48ad614SDennis Dalessandro /* Is the mkey in the process of expiring? */ 700f48ad614SDennis Dalessandro if (ibp->rvp.mkey_lease_timeout && 701f48ad614SDennis Dalessandro time_after_eq(jiffies, ibp->rvp.mkey_lease_timeout)) { 702f48ad614SDennis Dalessandro /* Clear timeout and mkey protection field. */ 703f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_timeout = 0; 704f48ad614SDennis Dalessandro ibp->rvp.mkeyprot = 0; 705f48ad614SDennis Dalessandro } 706f48ad614SDennis Dalessandro 707f48ad614SDennis Dalessandro if ((mad_flags & IB_MAD_IGNORE_MKEY) || ibp->rvp.mkey == 0 || 708f48ad614SDennis Dalessandro ibp->rvp.mkey == mkey) 709f48ad614SDennis Dalessandro valid_mkey = 1; 710f48ad614SDennis Dalessandro 711f48ad614SDennis Dalessandro /* Unset lease timeout on any valid Get/Set/TrapRepress */ 712f48ad614SDennis Dalessandro if (valid_mkey && ibp->rvp.mkey_lease_timeout && 713f48ad614SDennis Dalessandro (mad->method == IB_MGMT_METHOD_GET || 714f48ad614SDennis Dalessandro mad->method == IB_MGMT_METHOD_SET || 715f48ad614SDennis Dalessandro mad->method == IB_MGMT_METHOD_TRAP_REPRESS)) 716f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_timeout = 0; 717f48ad614SDennis Dalessandro 718f48ad614SDennis Dalessandro if (!valid_mkey) { 719f48ad614SDennis Dalessandro switch (mad->method) { 720f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 721f48ad614SDennis Dalessandro /* Bad mkey not a violation below level 2 */ 722f48ad614SDennis Dalessandro if (ibp->rvp.mkeyprot < 2) 723f48ad614SDennis Dalessandro break; 7246f24b159SGustavo A. R. Silva fallthrough; 725f48ad614SDennis Dalessandro case IB_MGMT_METHOD_SET: 726f48ad614SDennis Dalessandro case IB_MGMT_METHOD_TRAP_REPRESS: 727f48ad614SDennis Dalessandro if (ibp->rvp.mkey_violations != 0xFFFF) 728f48ad614SDennis Dalessandro ++ibp->rvp.mkey_violations; 729f48ad614SDennis Dalessandro if (!ibp->rvp.mkey_lease_timeout && 730f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_period) 731f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_timeout = jiffies + 732f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_period * HZ; 733f48ad614SDennis Dalessandro /* Generate a trap notice. */ 734f48ad614SDennis Dalessandro bad_mkey(ibp, mad, mkey, dr_slid, return_path, 735f48ad614SDennis Dalessandro hop_cnt); 736f48ad614SDennis Dalessandro ret = 1; 737f48ad614SDennis Dalessandro } 738f48ad614SDennis Dalessandro } 739f48ad614SDennis Dalessandro 740f48ad614SDennis Dalessandro return ret; 741f48ad614SDennis Dalessandro } 742f48ad614SDennis Dalessandro 743f48ad614SDennis Dalessandro /* 744f48ad614SDennis Dalessandro * The SMA caches reads from LCB registers in case the LCB is unavailable. 745f48ad614SDennis Dalessandro * (The LCB is unavailable in certain link states, for example.) 746f48ad614SDennis Dalessandro */ 747f48ad614SDennis Dalessandro struct lcb_datum { 748f48ad614SDennis Dalessandro u32 off; 749f48ad614SDennis Dalessandro u64 val; 750f48ad614SDennis Dalessandro }; 751f48ad614SDennis Dalessandro 752f48ad614SDennis Dalessandro static struct lcb_datum lcb_cache[] = { 753f48ad614SDennis Dalessandro { DC_LCB_STS_ROUND_TRIP_LTP_CNT, 0 }, 754f48ad614SDennis Dalessandro }; 755f48ad614SDennis Dalessandro 756f48ad614SDennis Dalessandro static int write_lcb_cache(u32 off, u64 val) 757f48ad614SDennis Dalessandro { 758f48ad614SDennis Dalessandro int i; 759f48ad614SDennis Dalessandro 760f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(lcb_cache); i++) { 761f48ad614SDennis Dalessandro if (lcb_cache[i].off == off) { 762f48ad614SDennis Dalessandro lcb_cache[i].val = val; 763f48ad614SDennis Dalessandro return 0; 764f48ad614SDennis Dalessandro } 765f48ad614SDennis Dalessandro } 766f48ad614SDennis Dalessandro 767f48ad614SDennis Dalessandro pr_warn("%s bad offset 0x%x\n", __func__, off); 768f48ad614SDennis Dalessandro return -1; 769f48ad614SDennis Dalessandro } 770f48ad614SDennis Dalessandro 771f48ad614SDennis Dalessandro static int read_lcb_cache(u32 off, u64 *val) 772f48ad614SDennis Dalessandro { 773f48ad614SDennis Dalessandro int i; 774f48ad614SDennis Dalessandro 775f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(lcb_cache); i++) { 776f48ad614SDennis Dalessandro if (lcb_cache[i].off == off) { 777f48ad614SDennis Dalessandro *val = lcb_cache[i].val; 778f48ad614SDennis Dalessandro return 0; 779f48ad614SDennis Dalessandro } 780f48ad614SDennis Dalessandro } 781f48ad614SDennis Dalessandro 782f48ad614SDennis Dalessandro pr_warn("%s bad offset 0x%x\n", __func__, off); 783f48ad614SDennis Dalessandro return -1; 784f48ad614SDennis Dalessandro } 785f48ad614SDennis Dalessandro 786f48ad614SDennis Dalessandro void read_ltp_rtt(struct hfi1_devdata *dd) 787f48ad614SDennis Dalessandro { 788f48ad614SDennis Dalessandro u64 reg; 789f48ad614SDennis Dalessandro 790f48ad614SDennis Dalessandro if (read_lcb_csr(dd, DC_LCB_STS_ROUND_TRIP_LTP_CNT, ®)) 791f48ad614SDennis Dalessandro dd_dev_err(dd, "%s: unable to read LTP RTT\n", __func__); 792f48ad614SDennis Dalessandro else 793f48ad614SDennis Dalessandro write_lcb_cache(DC_LCB_STS_ROUND_TRIP_LTP_CNT, reg); 794f48ad614SDennis Dalessandro } 795f48ad614SDennis Dalessandro 796f48ad614SDennis Dalessandro static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, 797f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 798f1685179SNeel Desai u32 *resp_len, u32 max_len) 799f48ad614SDennis Dalessandro { 800f48ad614SDennis Dalessandro int i; 801f48ad614SDennis Dalessandro struct hfi1_devdata *dd; 802f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 803f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 804f48ad614SDennis Dalessandro struct opa_port_info *pi = (struct opa_port_info *)data; 805f48ad614SDennis Dalessandro u8 mtu; 806f48ad614SDennis Dalessandro u8 credit_rate; 807f48ad614SDennis Dalessandro u8 is_beaconing_active; 808f48ad614SDennis Dalessandro u32 state; 809f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 810f48ad614SDennis Dalessandro u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); 811f48ad614SDennis Dalessandro u32 buffer_units; 812f48ad614SDennis Dalessandro u64 tmp = 0; 813f48ad614SDennis Dalessandro 814f1685179SNeel Desai if (num_ports != 1 || smp_length_check(sizeof(*pi), max_len)) { 815f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 816f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 817f48ad614SDennis Dalessandro } 818f48ad614SDennis Dalessandro 819f48ad614SDennis Dalessandro dd = dd_from_ibdev(ibdev); 820f48ad614SDennis Dalessandro /* IB numbers ports from 1, hw from 0 */ 821f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 822f48ad614SDennis Dalessandro ibp = &ppd->ibport_data; 823f48ad614SDennis Dalessandro 824f48ad614SDennis Dalessandro if (ppd->vls_supported / 2 > ARRAY_SIZE(pi->neigh_mtu.pvlx_to_mtu) || 825f48ad614SDennis Dalessandro ppd->vls_supported > ARRAY_SIZE(dd->vld)) { 826f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 827f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 828f48ad614SDennis Dalessandro } 829f48ad614SDennis Dalessandro 830f48ad614SDennis Dalessandro pi->lid = cpu_to_be32(ppd->lid); 831f48ad614SDennis Dalessandro 832f48ad614SDennis Dalessandro /* Only return the mkey if the protection field allows it. */ 833f48ad614SDennis Dalessandro if (!(smp->method == IB_MGMT_METHOD_GET && 834f48ad614SDennis Dalessandro ibp->rvp.mkey != smp->mkey && 835f48ad614SDennis Dalessandro ibp->rvp.mkeyprot == 1)) 836f48ad614SDennis Dalessandro pi->mkey = ibp->rvp.mkey; 837f48ad614SDennis Dalessandro 838f48ad614SDennis Dalessandro pi->subnet_prefix = ibp->rvp.gid_prefix; 839f48ad614SDennis Dalessandro pi->sm_lid = cpu_to_be32(ibp->rvp.sm_lid); 840f48ad614SDennis Dalessandro pi->ib_cap_mask = cpu_to_be32(ibp->rvp.port_cap_flags); 841f48ad614SDennis Dalessandro pi->mkey_lease_period = cpu_to_be16(ibp->rvp.mkey_lease_period); 842f48ad614SDennis Dalessandro pi->sm_trap_qp = cpu_to_be32(ppd->sm_trap_qp); 843f48ad614SDennis Dalessandro pi->sa_qp = cpu_to_be32(ppd->sa_qp); 844f48ad614SDennis Dalessandro 845f48ad614SDennis Dalessandro pi->link_width.enabled = cpu_to_be16(ppd->link_width_enabled); 846f48ad614SDennis Dalessandro pi->link_width.supported = cpu_to_be16(ppd->link_width_supported); 847f48ad614SDennis Dalessandro pi->link_width.active = cpu_to_be16(ppd->link_width_active); 848f48ad614SDennis Dalessandro 849f48ad614SDennis Dalessandro pi->link_width_downgrade.supported = 850f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_supported); 851f48ad614SDennis Dalessandro pi->link_width_downgrade.enabled = 852f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_enabled); 853f48ad614SDennis Dalessandro pi->link_width_downgrade.tx_active = 854f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_tx_active); 855f48ad614SDennis Dalessandro pi->link_width_downgrade.rx_active = 856f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_rx_active); 857f48ad614SDennis Dalessandro 858f48ad614SDennis Dalessandro pi->link_speed.supported = cpu_to_be16(ppd->link_speed_supported); 859f48ad614SDennis Dalessandro pi->link_speed.active = cpu_to_be16(ppd->link_speed_active); 860f48ad614SDennis Dalessandro pi->link_speed.enabled = cpu_to_be16(ppd->link_speed_enabled); 861f48ad614SDennis Dalessandro 862f48ad614SDennis Dalessandro state = driver_lstate(ppd); 863f48ad614SDennis Dalessandro 864f48ad614SDennis Dalessandro if (start_of_sm_config && (state == IB_PORT_INIT)) 865f48ad614SDennis Dalessandro ppd->is_sm_config_started = 1; 866f48ad614SDennis Dalessandro 867f48ad614SDennis Dalessandro pi->port_phys_conf = (ppd->port_type & 0xf); 868f48ad614SDennis Dalessandro 869f48ad614SDennis Dalessandro pi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4; 870f48ad614SDennis Dalessandro pi->port_states.ledenable_offlinereason |= 871f48ad614SDennis Dalessandro ppd->is_sm_config_started << 5; 872f48ad614SDennis Dalessandro /* 873f48ad614SDennis Dalessandro * This pairs with the memory barrier in hfi1_start_led_override to 874f48ad614SDennis Dalessandro * ensure that we read the correct state of LED beaconing represented 875f48ad614SDennis Dalessandro * by led_override_timer_active 876f48ad614SDennis Dalessandro */ 877f48ad614SDennis Dalessandro smp_rmb(); 878f48ad614SDennis Dalessandro is_beaconing_active = !!atomic_read(&ppd->led_override_timer_active); 879f48ad614SDennis Dalessandro pi->port_states.ledenable_offlinereason |= is_beaconing_active << 6; 880f48ad614SDennis Dalessandro pi->port_states.ledenable_offlinereason |= 881f48ad614SDennis Dalessandro ppd->offline_disabled_reason; 882f48ad614SDennis Dalessandro 883f48ad614SDennis Dalessandro pi->port_states.portphysstate_portstate = 884bec7c79cSByczkowski, Jakub (driver_pstate(ppd) << 4) | state; 885f48ad614SDennis Dalessandro 886f48ad614SDennis Dalessandro pi->mkeyprotect_lmc = (ibp->rvp.mkeyprot << 6) | ppd->lmc; 887f48ad614SDennis Dalessandro 888f48ad614SDennis Dalessandro memset(pi->neigh_mtu.pvlx_to_mtu, 0, sizeof(pi->neigh_mtu.pvlx_to_mtu)); 889f48ad614SDennis Dalessandro for (i = 0; i < ppd->vls_supported; i++) { 890f48ad614SDennis Dalessandro mtu = mtu_to_enum(dd->vld[i].mtu, HFI1_DEFAULT_ACTIVE_MTU); 891f48ad614SDennis Dalessandro if ((i % 2) == 0) 892f48ad614SDennis Dalessandro pi->neigh_mtu.pvlx_to_mtu[i / 2] |= (mtu << 4); 893f48ad614SDennis Dalessandro else 894f48ad614SDennis Dalessandro pi->neigh_mtu.pvlx_to_mtu[i / 2] |= mtu; 895f48ad614SDennis Dalessandro } 896f48ad614SDennis Dalessandro /* don't forget VL 15 */ 897f48ad614SDennis Dalessandro mtu = mtu_to_enum(dd->vld[15].mtu, 2048); 898f48ad614SDennis Dalessandro pi->neigh_mtu.pvlx_to_mtu[15 / 2] |= mtu; 899f48ad614SDennis Dalessandro pi->smsl = ibp->rvp.sm_sl & OPA_PI_MASK_SMSL; 900f48ad614SDennis Dalessandro pi->operational_vls = hfi1_get_ib_cfg(ppd, HFI1_IB_CFG_OP_VLS); 901f48ad614SDennis Dalessandro pi->partenforce_filterraw |= 902f48ad614SDennis Dalessandro (ppd->linkinit_reason & OPA_PI_MASK_LINKINIT_REASON); 903f48ad614SDennis Dalessandro if (ppd->part_enforce & HFI1_PART_ENFORCE_IN) 904f48ad614SDennis Dalessandro pi->partenforce_filterraw |= OPA_PI_MASK_PARTITION_ENFORCE_IN; 905f48ad614SDennis Dalessandro if (ppd->part_enforce & HFI1_PART_ENFORCE_OUT) 906f48ad614SDennis Dalessandro pi->partenforce_filterraw |= OPA_PI_MASK_PARTITION_ENFORCE_OUT; 907f48ad614SDennis Dalessandro pi->mkey_violations = cpu_to_be16(ibp->rvp.mkey_violations); 908f48ad614SDennis Dalessandro /* P_KeyViolations are counted by hardware. */ 909f48ad614SDennis Dalessandro pi->pkey_violations = cpu_to_be16(ibp->rvp.pkey_violations); 910f48ad614SDennis Dalessandro pi->qkey_violations = cpu_to_be16(ibp->rvp.qkey_violations); 911f48ad614SDennis Dalessandro 912f48ad614SDennis Dalessandro pi->vl.cap = ppd->vls_supported; 913f48ad614SDennis Dalessandro pi->vl.high_limit = cpu_to_be16(ibp->rvp.vl_high_limit); 914f48ad614SDennis Dalessandro pi->vl.arb_high_cap = (u8)hfi1_get_ib_cfg(ppd, HFI1_IB_CFG_VL_HIGH_CAP); 915f48ad614SDennis Dalessandro pi->vl.arb_low_cap = (u8)hfi1_get_ib_cfg(ppd, HFI1_IB_CFG_VL_LOW_CAP); 916f48ad614SDennis Dalessandro 917f48ad614SDennis Dalessandro pi->clientrereg_subnettimeout = ibp->rvp.subnet_timeout; 918f48ad614SDennis Dalessandro 919f48ad614SDennis Dalessandro pi->port_link_mode = cpu_to_be16(OPA_PORT_LINK_MODE_OPA << 10 | 920f48ad614SDennis Dalessandro OPA_PORT_LINK_MODE_OPA << 5 | 921f48ad614SDennis Dalessandro OPA_PORT_LINK_MODE_OPA); 922f48ad614SDennis Dalessandro 923f48ad614SDennis Dalessandro pi->port_ltp_crc_mode = cpu_to_be16(ppd->port_ltp_crc_mode); 924f48ad614SDennis Dalessandro 925f48ad614SDennis Dalessandro pi->port_mode = cpu_to_be16( 926f48ad614SDennis Dalessandro ppd->is_active_optimize_enabled ? 927f48ad614SDennis Dalessandro OPA_PI_MASK_PORT_ACTIVE_OPTOMIZE : 0); 928f48ad614SDennis Dalessandro 929f48ad614SDennis Dalessandro pi->port_packet_format.supported = 9302280740fSVishwanathapura, Niranjana cpu_to_be16(OPA_PORT_PACKET_FORMAT_9B | 9312280740fSVishwanathapura, Niranjana OPA_PORT_PACKET_FORMAT_16B); 932f48ad614SDennis Dalessandro pi->port_packet_format.enabled = 9332280740fSVishwanathapura, Niranjana cpu_to_be16(OPA_PORT_PACKET_FORMAT_9B | 9342280740fSVishwanathapura, Niranjana OPA_PORT_PACKET_FORMAT_16B); 935f48ad614SDennis Dalessandro 936f48ad614SDennis Dalessandro /* flit_control.interleave is (OPA V1, version .76): 937f48ad614SDennis Dalessandro * bits use 938f48ad614SDennis Dalessandro * ---- --- 939f48ad614SDennis Dalessandro * 2 res 940f48ad614SDennis Dalessandro * 2 DistanceSupported 941f48ad614SDennis Dalessandro * 2 DistanceEnabled 942f48ad614SDennis Dalessandro * 5 MaxNextLevelTxEnabled 943f48ad614SDennis Dalessandro * 5 MaxNestLevelRxSupported 944f48ad614SDennis Dalessandro * 945f48ad614SDennis Dalessandro * HFI supports only "distance mode 1" (see OPA V1, version .76, 946f48ad614SDennis Dalessandro * section 9.6.2), so set DistanceSupported, DistanceEnabled 947f48ad614SDennis Dalessandro * to 0x1. 948f48ad614SDennis Dalessandro */ 949f48ad614SDennis Dalessandro pi->flit_control.interleave = cpu_to_be16(0x1400); 950f48ad614SDennis Dalessandro 951f48ad614SDennis Dalessandro pi->link_down_reason = ppd->local_link_down_reason.sma; 952f48ad614SDennis Dalessandro pi->neigh_link_down_reason = ppd->neigh_link_down_reason.sma; 953f48ad614SDennis Dalessandro pi->port_error_action = cpu_to_be32(ppd->port_error_action); 954f48ad614SDennis Dalessandro pi->mtucap = mtu_to_enum(hfi1_max_mtu, IB_MTU_4096); 955f48ad614SDennis Dalessandro 956f48ad614SDennis Dalessandro /* 32.768 usec. response time (guessing) */ 957f48ad614SDennis Dalessandro pi->resptimevalue = 3; 958f48ad614SDennis Dalessandro 959f48ad614SDennis Dalessandro pi->local_port_num = port; 960f48ad614SDennis Dalessandro 961f48ad614SDennis Dalessandro /* buffer info for FM */ 962f48ad614SDennis Dalessandro pi->overall_buffer_space = cpu_to_be16(dd->link_credits); 963f48ad614SDennis Dalessandro 964f48ad614SDennis Dalessandro pi->neigh_node_guid = cpu_to_be64(ppd->neighbor_guid); 965f48ad614SDennis Dalessandro pi->neigh_port_num = ppd->neighbor_port_number; 966f48ad614SDennis Dalessandro pi->port_neigh_mode = 967f48ad614SDennis Dalessandro (ppd->neighbor_type & OPA_PI_MASK_NEIGH_NODE_TYPE) | 968f48ad614SDennis Dalessandro (ppd->mgmt_allowed ? OPA_PI_MASK_NEIGH_MGMT_ALLOWED : 0) | 969f48ad614SDennis Dalessandro (ppd->neighbor_fm_security ? 970f48ad614SDennis Dalessandro OPA_PI_MASK_NEIGH_FW_AUTH_BYPASS : 0); 971f48ad614SDennis Dalessandro 972f48ad614SDennis Dalessandro /* HFIs shall always return VL15 credits to their 973f48ad614SDennis Dalessandro * neighbor in a timely manner, without any credit return pacing. 974f48ad614SDennis Dalessandro */ 975f48ad614SDennis Dalessandro credit_rate = 0; 976f48ad614SDennis Dalessandro buffer_units = (dd->vau) & OPA_PI_MASK_BUF_UNIT_BUF_ALLOC; 977f48ad614SDennis Dalessandro buffer_units |= (dd->vcu << 3) & OPA_PI_MASK_BUF_UNIT_CREDIT_ACK; 978f48ad614SDennis Dalessandro buffer_units |= (credit_rate << 6) & 979f48ad614SDennis Dalessandro OPA_PI_MASK_BUF_UNIT_VL15_CREDIT_RATE; 980f48ad614SDennis Dalessandro buffer_units |= (dd->vl15_init << 11) & OPA_PI_MASK_BUF_UNIT_VL15_INIT; 981f48ad614SDennis Dalessandro pi->buffer_units = cpu_to_be32(buffer_units); 982f48ad614SDennis Dalessandro 983cb49366fSVishwanathapura, Niranjana pi->opa_cap_mask = cpu_to_be16(ibp->rvp.port_cap3_flags); 98413c19222SDon Hiatt pi->collectivemask_multicastmask = ((OPA_COLLECTIVE_NR & 0x7) 98513c19222SDon Hiatt << 3 | (OPA_MCAST_NR & 0x7)); 986f48ad614SDennis Dalessandro 987f48ad614SDennis Dalessandro /* HFI supports a replay buffer 128 LTPs in size */ 988f48ad614SDennis Dalessandro pi->replay_depth.buffer = 0x80; 989f48ad614SDennis Dalessandro /* read the cached value of DC_LCB_STS_ROUND_TRIP_LTP_CNT */ 990f48ad614SDennis Dalessandro read_lcb_cache(DC_LCB_STS_ROUND_TRIP_LTP_CNT, &tmp); 991f48ad614SDennis Dalessandro 992f48ad614SDennis Dalessandro /* 993f48ad614SDennis Dalessandro * this counter is 16 bits wide, but the replay_depth.wire 994f48ad614SDennis Dalessandro * variable is only 8 bits 995f48ad614SDennis Dalessandro */ 996f48ad614SDennis Dalessandro if (tmp > 0xff) 997f48ad614SDennis Dalessandro tmp = 0xff; 998f48ad614SDennis Dalessandro pi->replay_depth.wire = tmp; 999f48ad614SDennis Dalessandro 1000f48ad614SDennis Dalessandro if (resp_len) 1001f48ad614SDennis Dalessandro *resp_len += sizeof(struct opa_port_info); 1002f48ad614SDennis Dalessandro 1003f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1004f48ad614SDennis Dalessandro } 1005f48ad614SDennis Dalessandro 1006f48ad614SDennis Dalessandro /** 1007f48ad614SDennis Dalessandro * get_pkeys - return the PKEY table 1008f48ad614SDennis Dalessandro * @dd: the hfi1_ib device 1009f48ad614SDennis Dalessandro * @port: the IB port number 1010f48ad614SDennis Dalessandro * @pkeys: the pkey table is placed here 1011f48ad614SDennis Dalessandro */ 1012f48ad614SDennis Dalessandro static int get_pkeys(struct hfi1_devdata *dd, u8 port, u16 *pkeys) 1013f48ad614SDennis Dalessandro { 1014f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = dd->pport + port - 1; 1015f48ad614SDennis Dalessandro 1016f48ad614SDennis Dalessandro memcpy(pkeys, ppd->pkeys, sizeof(ppd->pkeys)); 1017f48ad614SDennis Dalessandro 1018f48ad614SDennis Dalessandro return 0; 1019f48ad614SDennis Dalessandro } 1020f48ad614SDennis Dalessandro 1021f48ad614SDennis Dalessandro static int __subn_get_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data, 1022f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1023f1685179SNeel Desai u32 *resp_len, u32 max_len) 1024f48ad614SDennis Dalessandro { 1025f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1026f48ad614SDennis Dalessandro u32 n_blocks_req = OPA_AM_NBLK(am); 1027f48ad614SDennis Dalessandro u32 start_block = am & 0x7ff; 1028f48ad614SDennis Dalessandro __be16 *p; 1029f48ad614SDennis Dalessandro u16 *q; 1030f48ad614SDennis Dalessandro int i; 1031f48ad614SDennis Dalessandro u16 n_blocks_avail; 1032f48ad614SDennis Dalessandro unsigned npkeys = hfi1_get_npkeys(dd); 1033f48ad614SDennis Dalessandro size_t size; 1034f48ad614SDennis Dalessandro 1035f48ad614SDennis Dalessandro if (n_blocks_req == 0) { 1036f48ad614SDennis Dalessandro pr_warn("OPA Get PKey AM Invalid : P = %d; B = 0x%x; N = 0x%x\n", 1037f48ad614SDennis Dalessandro port, start_block, n_blocks_req); 1038f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1039f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1040f48ad614SDennis Dalessandro } 1041f48ad614SDennis Dalessandro 1042f48ad614SDennis Dalessandro n_blocks_avail = (u16)(npkeys / OPA_PARTITION_TABLE_BLK_SIZE) + 1; 1043f48ad614SDennis Dalessandro 1044f48ad614SDennis Dalessandro size = (n_blocks_req * OPA_PARTITION_TABLE_BLK_SIZE) * sizeof(u16); 1045f48ad614SDennis Dalessandro 1046f1685179SNeel Desai if (smp_length_check(size, max_len)) { 1047f1685179SNeel Desai smp->status |= IB_SMP_INVALID_FIELD; 1048f1685179SNeel Desai return reply((struct ib_mad_hdr *)smp); 1049f1685179SNeel Desai } 1050f1685179SNeel Desai 1051f48ad614SDennis Dalessandro if (start_block + n_blocks_req > n_blocks_avail || 1052f48ad614SDennis Dalessandro n_blocks_req > OPA_NUM_PKEY_BLOCKS_PER_SMP) { 1053f48ad614SDennis Dalessandro pr_warn("OPA Get PKey AM Invalid : s 0x%x; req 0x%x; " 1054f48ad614SDennis Dalessandro "avail 0x%x; blk/smp 0x%lx\n", 1055f48ad614SDennis Dalessandro start_block, n_blocks_req, n_blocks_avail, 1056f48ad614SDennis Dalessandro OPA_NUM_PKEY_BLOCKS_PER_SMP); 1057f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1058f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1059f48ad614SDennis Dalessandro } 1060f48ad614SDennis Dalessandro 1061f48ad614SDennis Dalessandro p = (__be16 *)data; 1062f48ad614SDennis Dalessandro q = (u16 *)data; 1063f48ad614SDennis Dalessandro /* get the real pkeys if we are requesting the first block */ 1064f48ad614SDennis Dalessandro if (start_block == 0) { 1065f48ad614SDennis Dalessandro get_pkeys(dd, port, q); 1066f48ad614SDennis Dalessandro for (i = 0; i < npkeys; i++) 1067f48ad614SDennis Dalessandro p[i] = cpu_to_be16(q[i]); 1068f48ad614SDennis Dalessandro if (resp_len) 1069f48ad614SDennis Dalessandro *resp_len += size; 1070f48ad614SDennis Dalessandro } else { 1071f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1072f48ad614SDennis Dalessandro } 1073f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1074f48ad614SDennis Dalessandro } 1075f48ad614SDennis Dalessandro 1076f48ad614SDennis Dalessandro enum { 1077f48ad614SDennis Dalessandro HFI_TRANSITION_DISALLOWED, 1078f48ad614SDennis Dalessandro HFI_TRANSITION_IGNORED, 1079f48ad614SDennis Dalessandro HFI_TRANSITION_ALLOWED, 1080f48ad614SDennis Dalessandro HFI_TRANSITION_UNDEFINED, 1081f48ad614SDennis Dalessandro }; 1082f48ad614SDennis Dalessandro 1083f48ad614SDennis Dalessandro /* 1084f48ad614SDennis Dalessandro * Use shortened names to improve readability of 1085f48ad614SDennis Dalessandro * {logical,physical}_state_transitions 1086f48ad614SDennis Dalessandro */ 1087f48ad614SDennis Dalessandro enum { 1088f48ad614SDennis Dalessandro __D = HFI_TRANSITION_DISALLOWED, 1089f48ad614SDennis Dalessandro __I = HFI_TRANSITION_IGNORED, 1090f48ad614SDennis Dalessandro __A = HFI_TRANSITION_ALLOWED, 1091f48ad614SDennis Dalessandro __U = HFI_TRANSITION_UNDEFINED, 1092f48ad614SDennis Dalessandro }; 1093f48ad614SDennis Dalessandro 1094f48ad614SDennis Dalessandro /* 1095f48ad614SDennis Dalessandro * IB_PORTPHYSSTATE_POLLING (2) through OPA_PORTPHYSSTATE_MAX (11) are 1096f48ad614SDennis Dalessandro * represented in physical_state_transitions. 1097f48ad614SDennis Dalessandro */ 1098f48ad614SDennis Dalessandro #define __N_PHYSTATES (OPA_PORTPHYSSTATE_MAX - IB_PORTPHYSSTATE_POLLING + 1) 1099f48ad614SDennis Dalessandro 1100f48ad614SDennis Dalessandro /* 1101f48ad614SDennis Dalessandro * Within physical_state_transitions, rows represent "old" states, 1102f48ad614SDennis Dalessandro * columns "new" states, and physical_state_transitions.allowed[old][new] 1103f48ad614SDennis Dalessandro * indicates if the transition from old state to new state is legal (see 1104f48ad614SDennis Dalessandro * OPAg1v1, Table 6-4). 1105f48ad614SDennis Dalessandro */ 1106f48ad614SDennis Dalessandro static const struct { 1107f48ad614SDennis Dalessandro u8 allowed[__N_PHYSTATES][__N_PHYSTATES]; 1108f48ad614SDennis Dalessandro } physical_state_transitions = { 1109f48ad614SDennis Dalessandro { 1110f48ad614SDennis Dalessandro /* 2 3 4 5 6 7 8 9 10 11 */ 1111f48ad614SDennis Dalessandro /* 2 */ { __A, __A, __D, __D, __D, __D, __D, __D, __D, __D }, 1112f48ad614SDennis Dalessandro /* 3 */ { __A, __I, __D, __D, __D, __D, __D, __D, __D, __A }, 1113f48ad614SDennis Dalessandro /* 4 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, 1114f48ad614SDennis Dalessandro /* 5 */ { __A, __A, __D, __I, __D, __D, __D, __D, __D, __D }, 1115f48ad614SDennis Dalessandro /* 6 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, 1116f48ad614SDennis Dalessandro /* 7 */ { __D, __A, __D, __D, __D, __I, __D, __D, __D, __D }, 1117f48ad614SDennis Dalessandro /* 8 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, 1118f48ad614SDennis Dalessandro /* 9 */ { __I, __A, __D, __D, __D, __D, __D, __I, __D, __D }, 1119f48ad614SDennis Dalessandro /*10 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, 1120f48ad614SDennis Dalessandro /*11 */ { __D, __A, __D, __D, __D, __D, __D, __D, __D, __I }, 1121f48ad614SDennis Dalessandro } 1122f48ad614SDennis Dalessandro }; 1123f48ad614SDennis Dalessandro 1124f48ad614SDennis Dalessandro /* 1125f48ad614SDennis Dalessandro * IB_PORT_DOWN (1) through IB_PORT_ACTIVE_DEFER (5) are represented 1126f48ad614SDennis Dalessandro * logical_state_transitions 1127f48ad614SDennis Dalessandro */ 1128f48ad614SDennis Dalessandro 1129f48ad614SDennis Dalessandro #define __N_LOGICAL_STATES (IB_PORT_ACTIVE_DEFER - IB_PORT_DOWN + 1) 1130f48ad614SDennis Dalessandro 1131f48ad614SDennis Dalessandro /* 1132f48ad614SDennis Dalessandro * Within logical_state_transitions rows represent "old" states, 1133f48ad614SDennis Dalessandro * columns "new" states, and logical_state_transitions.allowed[old][new] 1134f48ad614SDennis Dalessandro * indicates if the transition from old state to new state is legal (see 1135f48ad614SDennis Dalessandro * OPAg1v1, Table 9-12). 1136f48ad614SDennis Dalessandro */ 1137f48ad614SDennis Dalessandro static const struct { 1138f48ad614SDennis Dalessandro u8 allowed[__N_LOGICAL_STATES][__N_LOGICAL_STATES]; 1139f48ad614SDennis Dalessandro } logical_state_transitions = { 1140f48ad614SDennis Dalessandro { 1141f48ad614SDennis Dalessandro /* 1 2 3 4 5 */ 1142f48ad614SDennis Dalessandro /* 1 */ { __I, __D, __D, __D, __U}, 1143f48ad614SDennis Dalessandro /* 2 */ { __D, __I, __A, __D, __U}, 1144f48ad614SDennis Dalessandro /* 3 */ { __D, __D, __I, __A, __U}, 1145f48ad614SDennis Dalessandro /* 4 */ { __D, __D, __I, __I, __U}, 1146f48ad614SDennis Dalessandro /* 5 */ { __U, __U, __U, __U, __U}, 1147f48ad614SDennis Dalessandro } 1148f48ad614SDennis Dalessandro }; 1149f48ad614SDennis Dalessandro 1150f48ad614SDennis Dalessandro static int logical_transition_allowed(int old, int new) 1151f48ad614SDennis Dalessandro { 1152f48ad614SDennis Dalessandro if (old < IB_PORT_NOP || old > IB_PORT_ACTIVE_DEFER || 1153f48ad614SDennis Dalessandro new < IB_PORT_NOP || new > IB_PORT_ACTIVE_DEFER) { 1154f48ad614SDennis Dalessandro pr_warn("invalid logical state(s) (old %d new %d)\n", 1155f48ad614SDennis Dalessandro old, new); 1156f48ad614SDennis Dalessandro return HFI_TRANSITION_UNDEFINED; 1157f48ad614SDennis Dalessandro } 1158f48ad614SDennis Dalessandro 1159f48ad614SDennis Dalessandro if (new == IB_PORT_NOP) 1160f48ad614SDennis Dalessandro return HFI_TRANSITION_ALLOWED; /* always allowed */ 1161f48ad614SDennis Dalessandro 1162f48ad614SDennis Dalessandro /* adjust states for indexing into logical_state_transitions */ 1163f48ad614SDennis Dalessandro old -= IB_PORT_DOWN; 1164f48ad614SDennis Dalessandro new -= IB_PORT_DOWN; 1165f48ad614SDennis Dalessandro 1166f48ad614SDennis Dalessandro if (old < 0 || new < 0) 1167f48ad614SDennis Dalessandro return HFI_TRANSITION_UNDEFINED; 1168f48ad614SDennis Dalessandro return logical_state_transitions.allowed[old][new]; 1169f48ad614SDennis Dalessandro } 1170f48ad614SDennis Dalessandro 1171f48ad614SDennis Dalessandro static int physical_transition_allowed(int old, int new) 1172f48ad614SDennis Dalessandro { 1173f48ad614SDennis Dalessandro if (old < IB_PORTPHYSSTATE_NOP || old > OPA_PORTPHYSSTATE_MAX || 1174f48ad614SDennis Dalessandro new < IB_PORTPHYSSTATE_NOP || new > OPA_PORTPHYSSTATE_MAX) { 1175f48ad614SDennis Dalessandro pr_warn("invalid physical state(s) (old %d new %d)\n", 1176f48ad614SDennis Dalessandro old, new); 1177f48ad614SDennis Dalessandro return HFI_TRANSITION_UNDEFINED; 1178f48ad614SDennis Dalessandro } 1179f48ad614SDennis Dalessandro 1180f48ad614SDennis Dalessandro if (new == IB_PORTPHYSSTATE_NOP) 1181f48ad614SDennis Dalessandro return HFI_TRANSITION_ALLOWED; /* always allowed */ 1182f48ad614SDennis Dalessandro 1183f48ad614SDennis Dalessandro /* adjust states for indexing into physical_state_transitions */ 1184f48ad614SDennis Dalessandro old -= IB_PORTPHYSSTATE_POLLING; 1185f48ad614SDennis Dalessandro new -= IB_PORTPHYSSTATE_POLLING; 1186f48ad614SDennis Dalessandro 1187f48ad614SDennis Dalessandro if (old < 0 || new < 0) 1188f48ad614SDennis Dalessandro return HFI_TRANSITION_UNDEFINED; 1189f48ad614SDennis Dalessandro return physical_state_transitions.allowed[old][new]; 1190f48ad614SDennis Dalessandro } 1191f48ad614SDennis Dalessandro 1192f48ad614SDennis Dalessandro static int port_states_transition_allowed(struct hfi1_pportdata *ppd, 1193f48ad614SDennis Dalessandro u32 logical_new, u32 physical_new) 1194f48ad614SDennis Dalessandro { 1195d392a673SJakub Byczkowski u32 physical_old = driver_pstate(ppd); 119602a222c7SByczkowski, Jakub u32 logical_old = driver_lstate(ppd); 1197f48ad614SDennis Dalessandro int ret, logical_allowed, physical_allowed; 1198f48ad614SDennis Dalessandro 1199f48ad614SDennis Dalessandro ret = logical_transition_allowed(logical_old, logical_new); 1200f48ad614SDennis Dalessandro logical_allowed = ret; 1201f48ad614SDennis Dalessandro 1202f48ad614SDennis Dalessandro if (ret == HFI_TRANSITION_DISALLOWED || 1203f48ad614SDennis Dalessandro ret == HFI_TRANSITION_UNDEFINED) { 1204f48ad614SDennis Dalessandro pr_warn("invalid logical state transition %s -> %s\n", 1205f48ad614SDennis Dalessandro opa_lstate_name(logical_old), 1206f48ad614SDennis Dalessandro opa_lstate_name(logical_new)); 1207f48ad614SDennis Dalessandro return ret; 1208f48ad614SDennis Dalessandro } 1209f48ad614SDennis Dalessandro 1210f48ad614SDennis Dalessandro ret = physical_transition_allowed(physical_old, physical_new); 1211f48ad614SDennis Dalessandro physical_allowed = ret; 1212f48ad614SDennis Dalessandro 1213f48ad614SDennis Dalessandro if (ret == HFI_TRANSITION_DISALLOWED || 1214f48ad614SDennis Dalessandro ret == HFI_TRANSITION_UNDEFINED) { 1215f48ad614SDennis Dalessandro pr_warn("invalid physical state transition %s -> %s\n", 1216f48ad614SDennis Dalessandro opa_pstate_name(physical_old), 1217f48ad614SDennis Dalessandro opa_pstate_name(physical_new)); 1218f48ad614SDennis Dalessandro return ret; 1219f48ad614SDennis Dalessandro } 1220f48ad614SDennis Dalessandro 1221f48ad614SDennis Dalessandro if (logical_allowed == HFI_TRANSITION_IGNORED && 1222f48ad614SDennis Dalessandro physical_allowed == HFI_TRANSITION_IGNORED) 1223f48ad614SDennis Dalessandro return HFI_TRANSITION_IGNORED; 1224f48ad614SDennis Dalessandro 1225f48ad614SDennis Dalessandro /* 1226f48ad614SDennis Dalessandro * A change request of Physical Port State from 1227f48ad614SDennis Dalessandro * 'Offline' to 'Polling' should be ignored. 1228f48ad614SDennis Dalessandro */ 1229f48ad614SDennis Dalessandro if ((physical_old == OPA_PORTPHYSSTATE_OFFLINE) && 1230f48ad614SDennis Dalessandro (physical_new == IB_PORTPHYSSTATE_POLLING)) 1231f48ad614SDennis Dalessandro return HFI_TRANSITION_IGNORED; 1232f48ad614SDennis Dalessandro 1233f48ad614SDennis Dalessandro /* 1234f48ad614SDennis Dalessandro * Either physical_allowed or logical_allowed is 1235f48ad614SDennis Dalessandro * HFI_TRANSITION_ALLOWED. 1236f48ad614SDennis Dalessandro */ 1237f48ad614SDennis Dalessandro return HFI_TRANSITION_ALLOWED; 1238f48ad614SDennis Dalessandro } 1239f48ad614SDennis Dalessandro 1240f48ad614SDennis Dalessandro static int set_port_states(struct hfi1_pportdata *ppd, struct opa_smp *smp, 1241959f2d17SAlex Estrin u32 logical_state, u32 phys_state, int local_mad) 1242f48ad614SDennis Dalessandro { 1243f48ad614SDennis Dalessandro struct hfi1_devdata *dd = ppd->dd; 1244f48ad614SDennis Dalessandro u32 link_state; 1245f48ad614SDennis Dalessandro int ret; 1246f48ad614SDennis Dalessandro 1247f48ad614SDennis Dalessandro ret = port_states_transition_allowed(ppd, logical_state, phys_state); 1248f48ad614SDennis Dalessandro if (ret == HFI_TRANSITION_DISALLOWED || 1249f48ad614SDennis Dalessandro ret == HFI_TRANSITION_UNDEFINED) { 1250f48ad614SDennis Dalessandro /* error message emitted above */ 1251f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1252f48ad614SDennis Dalessandro return 0; 1253f48ad614SDennis Dalessandro } 1254f48ad614SDennis Dalessandro 1255f48ad614SDennis Dalessandro if (ret == HFI_TRANSITION_IGNORED) 1256f48ad614SDennis Dalessandro return 0; 1257f48ad614SDennis Dalessandro 1258f48ad614SDennis Dalessandro if ((phys_state != IB_PORTPHYSSTATE_NOP) && 1259f48ad614SDennis Dalessandro !(logical_state == IB_PORT_DOWN || 1260f48ad614SDennis Dalessandro logical_state == IB_PORT_NOP)){ 1261f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) port state invalid: logical_state 0x%x physical_state 0x%x\n", 1262f48ad614SDennis Dalessandro logical_state, phys_state); 1263f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1264f48ad614SDennis Dalessandro } 1265f48ad614SDennis Dalessandro 1266f48ad614SDennis Dalessandro /* 1267f48ad614SDennis Dalessandro * Logical state changes are summarized in OPAv1g1 spec., 1268f48ad614SDennis Dalessandro * Table 9-12; physical state changes are summarized in 1269f48ad614SDennis Dalessandro * OPAv1g1 spec., Table 6.4. 1270f48ad614SDennis Dalessandro */ 1271f48ad614SDennis Dalessandro switch (logical_state) { 1272f48ad614SDennis Dalessandro case IB_PORT_NOP: 1273f48ad614SDennis Dalessandro if (phys_state == IB_PORTPHYSSTATE_NOP) 1274f48ad614SDennis Dalessandro break; 12756f24b159SGustavo A. R. Silva fallthrough; 1276f48ad614SDennis Dalessandro case IB_PORT_DOWN: 1277f48ad614SDennis Dalessandro if (phys_state == IB_PORTPHYSSTATE_NOP) { 1278f48ad614SDennis Dalessandro link_state = HLS_DN_DOWNDEF; 1279f48ad614SDennis Dalessandro } else if (phys_state == IB_PORTPHYSSTATE_POLLING) { 1280f48ad614SDennis Dalessandro link_state = HLS_DN_POLL; 1281f48ad614SDennis Dalessandro set_link_down_reason(ppd, OPA_LINKDOWN_REASON_FM_BOUNCE, 1282f48ad614SDennis Dalessandro 0, OPA_LINKDOWN_REASON_FM_BOUNCE); 1283f48ad614SDennis Dalessandro } else if (phys_state == IB_PORTPHYSSTATE_DISABLED) { 1284f48ad614SDennis Dalessandro link_state = HLS_DN_DISABLE; 1285f48ad614SDennis Dalessandro } else { 1286f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) invalid physical state 0x%x\n", 1287f48ad614SDennis Dalessandro phys_state); 1288f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1289f48ad614SDennis Dalessandro break; 1290f48ad614SDennis Dalessandro } 1291f48ad614SDennis Dalessandro 1292f48ad614SDennis Dalessandro if ((link_state == HLS_DN_POLL || 1293f48ad614SDennis Dalessandro link_state == HLS_DN_DOWNDEF)) { 1294f48ad614SDennis Dalessandro /* 1295f48ad614SDennis Dalessandro * Going to poll. No matter what the current state, 1296f48ad614SDennis Dalessandro * always move offline first, then tune and start the 1297f48ad614SDennis Dalessandro * link. This correctly handles a FM link bounce and 1298f48ad614SDennis Dalessandro * a link enable. Going offline is a no-op if already 1299f48ad614SDennis Dalessandro * offline. 1300f48ad614SDennis Dalessandro */ 1301f48ad614SDennis Dalessandro set_link_state(ppd, HLS_DN_OFFLINE); 1302f48ad614SDennis Dalessandro start_link(ppd); 1303f48ad614SDennis Dalessandro } else { 1304f48ad614SDennis Dalessandro set_link_state(ppd, link_state); 1305f48ad614SDennis Dalessandro } 1306f48ad614SDennis Dalessandro if (link_state == HLS_DN_DISABLE && 1307f48ad614SDennis Dalessandro (ppd->offline_disabled_reason > 1308f48ad614SDennis Dalessandro HFI1_ODR_MASK(OPA_LINKDOWN_REASON_SMA_DISABLED) || 1309f48ad614SDennis Dalessandro ppd->offline_disabled_reason == 1310f48ad614SDennis Dalessandro HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE))) 1311f48ad614SDennis Dalessandro ppd->offline_disabled_reason = 1312f48ad614SDennis Dalessandro HFI1_ODR_MASK(OPA_LINKDOWN_REASON_SMA_DISABLED); 1313f48ad614SDennis Dalessandro /* 1314f48ad614SDennis Dalessandro * Don't send a reply if the response would be sent 1315f48ad614SDennis Dalessandro * through the disabled port. 1316f48ad614SDennis Dalessandro */ 1317959f2d17SAlex Estrin if (link_state == HLS_DN_DISABLE && !local_mad) 1318f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 1319f48ad614SDennis Dalessandro break; 1320f48ad614SDennis Dalessandro case IB_PORT_ARMED: 1321f48ad614SDennis Dalessandro ret = set_link_state(ppd, HLS_UP_ARMED); 1322a276672eSGrzegorz Morys if (!ret) 1323f48ad614SDennis Dalessandro send_idle_sma(dd, SMA_IDLE_ARM); 1324f48ad614SDennis Dalessandro break; 1325f48ad614SDennis Dalessandro case IB_PORT_ACTIVE: 1326f48ad614SDennis Dalessandro if (ppd->neighbor_normal) { 1327f48ad614SDennis Dalessandro ret = set_link_state(ppd, HLS_UP_ACTIVE); 1328f48ad614SDennis Dalessandro if (ret == 0) 1329f48ad614SDennis Dalessandro send_idle_sma(dd, SMA_IDLE_ACTIVE); 1330f48ad614SDennis Dalessandro } else { 1331f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) Cannot move to Active with NeighborNormal 0\n"); 1332f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1333f48ad614SDennis Dalessandro } 1334f48ad614SDennis Dalessandro break; 1335f48ad614SDennis Dalessandro default: 1336f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) invalid logical state 0x%x\n", 1337f48ad614SDennis Dalessandro logical_state); 1338f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1339f48ad614SDennis Dalessandro } 1340f48ad614SDennis Dalessandro 1341f48ad614SDennis Dalessandro return 0; 1342f48ad614SDennis Dalessandro } 1343f48ad614SDennis Dalessandro 1344*29f7e5a3SLee Jones /* 1345f48ad614SDennis Dalessandro * subn_set_opa_portinfo - set port information 1346f48ad614SDennis Dalessandro * @smp: the incoming SM packet 1347f48ad614SDennis Dalessandro * @ibdev: the infiniband device 1348f48ad614SDennis Dalessandro * @port: the port on the device 1349f48ad614SDennis Dalessandro * 1350f48ad614SDennis Dalessandro */ 1351f48ad614SDennis Dalessandro static int __subn_set_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, 1352f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1353959f2d17SAlex Estrin u32 *resp_len, u32 max_len, int local_mad) 1354f48ad614SDennis Dalessandro { 1355f48ad614SDennis Dalessandro struct opa_port_info *pi = (struct opa_port_info *)data; 1356f48ad614SDennis Dalessandro struct ib_event event; 1357f48ad614SDennis Dalessandro struct hfi1_devdata *dd; 1358f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1359f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 1360f48ad614SDennis Dalessandro u8 clientrereg; 1361f48ad614SDennis Dalessandro unsigned long flags; 136251e658f5SDasaratharaman Chandramouli u32 smlid; 136351e658f5SDasaratharaman Chandramouli u32 lid; 1364f48ad614SDennis Dalessandro u8 ls_old, ls_new, ps_new; 1365f48ad614SDennis Dalessandro u8 vls; 1366f48ad614SDennis Dalessandro u8 msl; 1367f48ad614SDennis Dalessandro u8 crc_enabled; 1368f48ad614SDennis Dalessandro u16 lse, lwe, mtu; 1369f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 1370f48ad614SDennis Dalessandro u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); 1371f48ad614SDennis Dalessandro int ret, i, invalid = 0, call_set_mtu = 0; 1372f48ad614SDennis Dalessandro int call_link_downgrade_policy = 0; 1373f48ad614SDennis Dalessandro 1374f1685179SNeel Desai if (num_ports != 1 || 1375f1685179SNeel Desai smp_length_check(sizeof(*pi), max_len)) { 1376f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1377f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1378f48ad614SDennis Dalessandro } 1379f48ad614SDennis Dalessandro 138051e658f5SDasaratharaman Chandramouli lid = be32_to_cpu(pi->lid); 138151e658f5SDasaratharaman Chandramouli if (lid & 0xFF000000) { 138251e658f5SDasaratharaman Chandramouli pr_warn("OPA_PortInfo lid out of range: %X\n", lid); 1383f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1384f48ad614SDennis Dalessandro goto get_only; 1385f48ad614SDennis Dalessandro } 1386f48ad614SDennis Dalessandro 1387f48ad614SDennis Dalessandro 1388f48ad614SDennis Dalessandro smlid = be32_to_cpu(pi->sm_lid); 138951e658f5SDasaratharaman Chandramouli if (smlid & 0xFF000000) { 1390f48ad614SDennis Dalessandro pr_warn("OPA_PortInfo SM lid out of range: %X\n", smlid); 1391f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1392f48ad614SDennis Dalessandro goto get_only; 1393f48ad614SDennis Dalessandro } 1394f48ad614SDennis Dalessandro 1395f48ad614SDennis Dalessandro clientrereg = (pi->clientrereg_subnettimeout & 1396f48ad614SDennis Dalessandro OPA_PI_MASK_CLIENT_REREGISTER); 1397f48ad614SDennis Dalessandro 1398f48ad614SDennis Dalessandro dd = dd_from_ibdev(ibdev); 1399f48ad614SDennis Dalessandro /* IB numbers ports from 1, hw from 0 */ 1400f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1401f48ad614SDennis Dalessandro ibp = &ppd->ibport_data; 1402f48ad614SDennis Dalessandro event.device = ibdev; 1403f48ad614SDennis Dalessandro event.element.port_num = port; 1404f48ad614SDennis Dalessandro 1405f48ad614SDennis Dalessandro ls_old = driver_lstate(ppd); 1406f48ad614SDennis Dalessandro 1407f48ad614SDennis Dalessandro ibp->rvp.mkey = pi->mkey; 140851e658f5SDasaratharaman Chandramouli if (ibp->rvp.gid_prefix != pi->subnet_prefix) { 1409f48ad614SDennis Dalessandro ibp->rvp.gid_prefix = pi->subnet_prefix; 141051e658f5SDasaratharaman Chandramouli event.event = IB_EVENT_GID_CHANGE; 141151e658f5SDasaratharaman Chandramouli ib_dispatch_event(&event); 141251e658f5SDasaratharaman Chandramouli } 1413f48ad614SDennis Dalessandro ibp->rvp.mkey_lease_period = be16_to_cpu(pi->mkey_lease_period); 1414f48ad614SDennis Dalessandro 1415f48ad614SDennis Dalessandro /* Must be a valid unicast LID address. */ 1416f48ad614SDennis Dalessandro if ((lid == 0 && ls_old > IB_PORT_INIT) || 141751e658f5SDasaratharaman Chandramouli (hfi1_is_16B_mcast(lid))) { 1418f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1419f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) lid invalid 0x%x\n", 1420f48ad614SDennis Dalessandro lid); 1421f48ad614SDennis Dalessandro } else if (ppd->lid != lid || 1422f48ad614SDennis Dalessandro ppd->lmc != (pi->mkeyprotect_lmc & OPA_PI_MASK_LMC)) { 1423f48ad614SDennis Dalessandro if (ppd->lid != lid) 1424f48ad614SDennis Dalessandro hfi1_set_uevent_bits(ppd, _HFI1_EVENT_LID_CHANGE_BIT); 1425f48ad614SDennis Dalessandro if (ppd->lmc != (pi->mkeyprotect_lmc & OPA_PI_MASK_LMC)) 1426f48ad614SDennis Dalessandro hfi1_set_uevent_bits(ppd, _HFI1_EVENT_LMC_CHANGE_BIT); 1427f48ad614SDennis Dalessandro hfi1_set_lid(ppd, lid, pi->mkeyprotect_lmc & OPA_PI_MASK_LMC); 1428f48ad614SDennis Dalessandro event.event = IB_EVENT_LID_CHANGE; 1429f48ad614SDennis Dalessandro ib_dispatch_event(&event); 143051e658f5SDasaratharaman Chandramouli 143151e658f5SDasaratharaman Chandramouli if (HFI1_PORT_GUID_INDEX + 1 < HFI1_GUIDS_PER_PORT) { 143251e658f5SDasaratharaman Chandramouli /* Manufacture GID from LID to support extended 143351e658f5SDasaratharaman Chandramouli * addresses 143451e658f5SDasaratharaman Chandramouli */ 143551e658f5SDasaratharaman Chandramouli ppd->guids[HFI1_PORT_GUID_INDEX + 1] = 143651e658f5SDasaratharaman Chandramouli be64_to_cpu(OPA_MAKE_ID(lid)); 143751e658f5SDasaratharaman Chandramouli event.event = IB_EVENT_GID_CHANGE; 143851e658f5SDasaratharaman Chandramouli ib_dispatch_event(&event); 143951e658f5SDasaratharaman Chandramouli } 1440f48ad614SDennis Dalessandro } 1441f48ad614SDennis Dalessandro 1442f48ad614SDennis Dalessandro msl = pi->smsl & OPA_PI_MASK_SMSL; 1443f48ad614SDennis Dalessandro if (pi->partenforce_filterraw & OPA_PI_MASK_LINKINIT_REASON) 1444f48ad614SDennis Dalessandro ppd->linkinit_reason = 1445f48ad614SDennis Dalessandro (pi->partenforce_filterraw & 1446f48ad614SDennis Dalessandro OPA_PI_MASK_LINKINIT_REASON); 1447f48ad614SDennis Dalessandro 1448f48ad614SDennis Dalessandro /* Must be a valid unicast LID address. */ 1449f48ad614SDennis Dalessandro if ((smlid == 0 && ls_old > IB_PORT_INIT) || 145051e658f5SDasaratharaman Chandramouli (hfi1_is_16B_mcast(smlid))) { 1451f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1452f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) smlid invalid 0x%x\n", smlid); 1453f48ad614SDennis Dalessandro } else if (smlid != ibp->rvp.sm_lid || msl != ibp->rvp.sm_sl) { 1454f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) smlid 0x%x\n", smlid); 1455f48ad614SDennis Dalessandro spin_lock_irqsave(&ibp->rvp.lock, flags); 1456f48ad614SDennis Dalessandro if (ibp->rvp.sm_ah) { 1457f48ad614SDennis Dalessandro if (smlid != ibp->rvp.sm_lid) 145851e658f5SDasaratharaman Chandramouli hfi1_modify_qp0_ah(ibp, ibp->rvp.sm_ah, smlid); 1459f48ad614SDennis Dalessandro if (msl != ibp->rvp.sm_sl) 1460d8966fcdSDasaratharaman Chandramouli rdma_ah_set_sl(&ibp->rvp.sm_ah->attr, msl); 1461f48ad614SDennis Dalessandro } 1462f48ad614SDennis Dalessandro spin_unlock_irqrestore(&ibp->rvp.lock, flags); 1463f48ad614SDennis Dalessandro if (smlid != ibp->rvp.sm_lid) 1464f48ad614SDennis Dalessandro ibp->rvp.sm_lid = smlid; 1465f48ad614SDennis Dalessandro if (msl != ibp->rvp.sm_sl) 1466f48ad614SDennis Dalessandro ibp->rvp.sm_sl = msl; 1467f48ad614SDennis Dalessandro event.event = IB_EVENT_SM_CHANGE; 1468f48ad614SDennis Dalessandro ib_dispatch_event(&event); 1469f48ad614SDennis Dalessandro } 1470f48ad614SDennis Dalessandro 1471f48ad614SDennis Dalessandro if (pi->link_down_reason == 0) { 1472f48ad614SDennis Dalessandro ppd->local_link_down_reason.sma = 0; 1473f48ad614SDennis Dalessandro ppd->local_link_down_reason.latest = 0; 1474f48ad614SDennis Dalessandro } 1475f48ad614SDennis Dalessandro 1476f48ad614SDennis Dalessandro if (pi->neigh_link_down_reason == 0) { 1477f48ad614SDennis Dalessandro ppd->neigh_link_down_reason.sma = 0; 1478f48ad614SDennis Dalessandro ppd->neigh_link_down_reason.latest = 0; 1479f48ad614SDennis Dalessandro } 1480f48ad614SDennis Dalessandro 1481f48ad614SDennis Dalessandro ppd->sm_trap_qp = be32_to_cpu(pi->sm_trap_qp); 1482f48ad614SDennis Dalessandro ppd->sa_qp = be32_to_cpu(pi->sa_qp); 1483f48ad614SDennis Dalessandro 1484f48ad614SDennis Dalessandro ppd->port_error_action = be32_to_cpu(pi->port_error_action); 1485f48ad614SDennis Dalessandro lwe = be16_to_cpu(pi->link_width.enabled); 1486f48ad614SDennis Dalessandro if (lwe) { 1487f48ad614SDennis Dalessandro if (lwe == OPA_LINK_WIDTH_RESET || 1488f48ad614SDennis Dalessandro lwe == OPA_LINK_WIDTH_RESET_OLD) 1489f48ad614SDennis Dalessandro set_link_width_enabled(ppd, ppd->link_width_supported); 1490f48ad614SDennis Dalessandro else if ((lwe & ~ppd->link_width_supported) == 0) 1491f48ad614SDennis Dalessandro set_link_width_enabled(ppd, lwe); 1492f48ad614SDennis Dalessandro else 1493f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1494f48ad614SDennis Dalessandro } 1495f48ad614SDennis Dalessandro lwe = be16_to_cpu(pi->link_width_downgrade.enabled); 1496f48ad614SDennis Dalessandro /* LWD.E is always applied - 0 means "disabled" */ 1497f48ad614SDennis Dalessandro if (lwe == OPA_LINK_WIDTH_RESET || 1498f48ad614SDennis Dalessandro lwe == OPA_LINK_WIDTH_RESET_OLD) { 1499f48ad614SDennis Dalessandro set_link_width_downgrade_enabled(ppd, 1500f48ad614SDennis Dalessandro ppd-> 1501f48ad614SDennis Dalessandro link_width_downgrade_supported 1502f48ad614SDennis Dalessandro ); 1503f48ad614SDennis Dalessandro } else if ((lwe & ~ppd->link_width_downgrade_supported) == 0) { 1504f48ad614SDennis Dalessandro /* only set and apply if something changed */ 1505f48ad614SDennis Dalessandro if (lwe != ppd->link_width_downgrade_enabled) { 1506f48ad614SDennis Dalessandro set_link_width_downgrade_enabled(ppd, lwe); 1507f48ad614SDennis Dalessandro call_link_downgrade_policy = 1; 1508f48ad614SDennis Dalessandro } 1509f48ad614SDennis Dalessandro } else { 1510f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1511f48ad614SDennis Dalessandro } 1512f48ad614SDennis Dalessandro lse = be16_to_cpu(pi->link_speed.enabled); 1513f48ad614SDennis Dalessandro if (lse) { 1514f48ad614SDennis Dalessandro if (lse & be16_to_cpu(pi->link_speed.supported)) 1515f48ad614SDennis Dalessandro set_link_speed_enabled(ppd, lse); 1516f48ad614SDennis Dalessandro else 1517f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1518f48ad614SDennis Dalessandro } 1519f48ad614SDennis Dalessandro 1520f48ad614SDennis Dalessandro ibp->rvp.mkeyprot = 1521f48ad614SDennis Dalessandro (pi->mkeyprotect_lmc & OPA_PI_MASK_MKEY_PROT_BIT) >> 6; 1522f48ad614SDennis Dalessandro ibp->rvp.vl_high_limit = be16_to_cpu(pi->vl.high_limit) & 0xFF; 1523f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_VL_HIGH_LIMIT, 1524f48ad614SDennis Dalessandro ibp->rvp.vl_high_limit); 1525f48ad614SDennis Dalessandro 1526f48ad614SDennis Dalessandro if (ppd->vls_supported / 2 > ARRAY_SIZE(pi->neigh_mtu.pvlx_to_mtu) || 1527f48ad614SDennis Dalessandro ppd->vls_supported > ARRAY_SIZE(dd->vld)) { 1528f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1529f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1530f48ad614SDennis Dalessandro } 1531f48ad614SDennis Dalessandro for (i = 0; i < ppd->vls_supported; i++) { 1532f48ad614SDennis Dalessandro if ((i % 2) == 0) 1533f48ad614SDennis Dalessandro mtu = enum_to_mtu((pi->neigh_mtu.pvlx_to_mtu[i / 2] >> 1534f48ad614SDennis Dalessandro 4) & 0xF); 1535f48ad614SDennis Dalessandro else 1536f48ad614SDennis Dalessandro mtu = enum_to_mtu(pi->neigh_mtu.pvlx_to_mtu[i / 2] & 1537f48ad614SDennis Dalessandro 0xF); 1538f48ad614SDennis Dalessandro if (mtu == 0xffff) { 1539f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) mtu invalid %d (0x%x)\n", 1540f48ad614SDennis Dalessandro mtu, 1541f48ad614SDennis Dalessandro (pi->neigh_mtu.pvlx_to_mtu[0] >> 4) & 0xF); 1542f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1543f48ad614SDennis Dalessandro mtu = hfi1_max_mtu; /* use a valid MTU */ 1544f48ad614SDennis Dalessandro } 1545f48ad614SDennis Dalessandro if (dd->vld[i].mtu != mtu) { 1546f48ad614SDennis Dalessandro dd_dev_info(dd, 1547f48ad614SDennis Dalessandro "MTU change on vl %d from %d to %d\n", 1548f48ad614SDennis Dalessandro i, dd->vld[i].mtu, mtu); 1549f48ad614SDennis Dalessandro dd->vld[i].mtu = mtu; 1550f48ad614SDennis Dalessandro call_set_mtu++; 1551f48ad614SDennis Dalessandro } 1552f48ad614SDennis Dalessandro } 1553f48ad614SDennis Dalessandro /* As per OPAV1 spec: VL15 must support and be configured 1554f48ad614SDennis Dalessandro * for operation with a 2048 or larger MTU. 1555f48ad614SDennis Dalessandro */ 1556f48ad614SDennis Dalessandro mtu = enum_to_mtu(pi->neigh_mtu.pvlx_to_mtu[15 / 2] & 0xF); 1557f48ad614SDennis Dalessandro if (mtu < 2048 || mtu == 0xffff) 1558f48ad614SDennis Dalessandro mtu = 2048; 1559f48ad614SDennis Dalessandro if (dd->vld[15].mtu != mtu) { 1560f48ad614SDennis Dalessandro dd_dev_info(dd, 1561f48ad614SDennis Dalessandro "MTU change on vl 15 from %d to %d\n", 1562f48ad614SDennis Dalessandro dd->vld[15].mtu, mtu); 1563f48ad614SDennis Dalessandro dd->vld[15].mtu = mtu; 1564f48ad614SDennis Dalessandro call_set_mtu++; 1565f48ad614SDennis Dalessandro } 1566f48ad614SDennis Dalessandro if (call_set_mtu) 1567f48ad614SDennis Dalessandro set_mtu(ppd); 1568f48ad614SDennis Dalessandro 1569f48ad614SDennis Dalessandro /* Set operational VLs */ 1570f48ad614SDennis Dalessandro vls = pi->operational_vls & OPA_PI_MASK_OPERATIONAL_VL; 1571f48ad614SDennis Dalessandro if (vls) { 1572f48ad614SDennis Dalessandro if (vls > ppd->vls_supported) { 1573f48ad614SDennis Dalessandro pr_warn("SubnSet(OPA_PortInfo) VL's supported invalid %d\n", 1574f48ad614SDennis Dalessandro pi->operational_vls); 1575f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1576f48ad614SDennis Dalessandro } else { 1577f48ad614SDennis Dalessandro if (hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_OP_VLS, 1578f48ad614SDennis Dalessandro vls) == -EINVAL) 1579f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1580f48ad614SDennis Dalessandro } 1581f48ad614SDennis Dalessandro } 1582f48ad614SDennis Dalessandro 1583f48ad614SDennis Dalessandro if (pi->mkey_violations == 0) 1584f48ad614SDennis Dalessandro ibp->rvp.mkey_violations = 0; 1585f48ad614SDennis Dalessandro 1586f48ad614SDennis Dalessandro if (pi->pkey_violations == 0) 1587f48ad614SDennis Dalessandro ibp->rvp.pkey_violations = 0; 1588f48ad614SDennis Dalessandro 1589f48ad614SDennis Dalessandro if (pi->qkey_violations == 0) 1590f48ad614SDennis Dalessandro ibp->rvp.qkey_violations = 0; 1591f48ad614SDennis Dalessandro 1592f48ad614SDennis Dalessandro ibp->rvp.subnet_timeout = 1593f48ad614SDennis Dalessandro pi->clientrereg_subnettimeout & OPA_PI_MASK_SUBNET_TIMEOUT; 1594f48ad614SDennis Dalessandro 1595f48ad614SDennis Dalessandro crc_enabled = be16_to_cpu(pi->port_ltp_crc_mode); 1596f48ad614SDennis Dalessandro crc_enabled >>= 4; 1597f48ad614SDennis Dalessandro crc_enabled &= 0xf; 1598f48ad614SDennis Dalessandro 1599f48ad614SDennis Dalessandro if (crc_enabled != 0) 1600f48ad614SDennis Dalessandro ppd->port_crc_mode_enabled = port_ltp_to_cap(crc_enabled); 1601f48ad614SDennis Dalessandro 1602f48ad614SDennis Dalessandro ppd->is_active_optimize_enabled = 1603f48ad614SDennis Dalessandro !!(be16_to_cpu(pi->port_mode) 1604f48ad614SDennis Dalessandro & OPA_PI_MASK_PORT_ACTIVE_OPTOMIZE); 1605f48ad614SDennis Dalessandro 1606f48ad614SDennis Dalessandro ls_new = pi->port_states.portphysstate_portstate & 1607f48ad614SDennis Dalessandro OPA_PI_MASK_PORT_STATE; 1608f48ad614SDennis Dalessandro ps_new = (pi->port_states.portphysstate_portstate & 1609f48ad614SDennis Dalessandro OPA_PI_MASK_PORT_PHYSICAL_STATE) >> 4; 1610f48ad614SDennis Dalessandro 1611f48ad614SDennis Dalessandro if (ls_old == IB_PORT_INIT) { 1612f48ad614SDennis Dalessandro if (start_of_sm_config) { 1613f48ad614SDennis Dalessandro if (ls_new == ls_old || (ls_new == IB_PORT_ARMED)) 1614f48ad614SDennis Dalessandro ppd->is_sm_config_started = 1; 1615f48ad614SDennis Dalessandro } else if (ls_new == IB_PORT_ARMED) { 1616a276672eSGrzegorz Morys if (ppd->is_sm_config_started == 0) { 1617f48ad614SDennis Dalessandro invalid = 1; 1618a276672eSGrzegorz Morys smp->status |= IB_SMP_INVALID_FIELD; 1619a276672eSGrzegorz Morys } 1620f48ad614SDennis Dalessandro } 1621f48ad614SDennis Dalessandro } 1622f48ad614SDennis Dalessandro 1623f48ad614SDennis Dalessandro /* Handle CLIENT_REREGISTER event b/c SM asked us for it */ 1624f48ad614SDennis Dalessandro if (clientrereg) { 1625f48ad614SDennis Dalessandro event.event = IB_EVENT_CLIENT_REREGISTER; 1626f48ad614SDennis Dalessandro ib_dispatch_event(&event); 1627f48ad614SDennis Dalessandro } 1628f48ad614SDennis Dalessandro 1629f48ad614SDennis Dalessandro /* 1630f48ad614SDennis Dalessandro * Do the port state change now that the other link parameters 1631f48ad614SDennis Dalessandro * have been set. 1632f48ad614SDennis Dalessandro * Changing the port physical state only makes sense if the link 1633f48ad614SDennis Dalessandro * is down or is being set to down. 1634f48ad614SDennis Dalessandro */ 1635f48ad614SDennis Dalessandro 1636a276672eSGrzegorz Morys if (!invalid) { 1637959f2d17SAlex Estrin ret = set_port_states(ppd, smp, ls_new, ps_new, local_mad); 1638f48ad614SDennis Dalessandro if (ret) 1639f48ad614SDennis Dalessandro return ret; 1640a276672eSGrzegorz Morys } 1641f48ad614SDennis Dalessandro 1642f1685179SNeel Desai ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len, 1643f1685179SNeel Desai max_len); 1644f48ad614SDennis Dalessandro 1645f48ad614SDennis Dalessandro /* restore re-reg bit per o14-12.2.1 */ 1646f48ad614SDennis Dalessandro pi->clientrereg_subnettimeout |= clientrereg; 1647f48ad614SDennis Dalessandro 1648f48ad614SDennis Dalessandro /* 1649f48ad614SDennis Dalessandro * Apply the new link downgrade policy. This may result in a link 1650f48ad614SDennis Dalessandro * bounce. Do this after everything else so things are settled. 1651f48ad614SDennis Dalessandro * Possible problem: if setting the port state above fails, then 1652f48ad614SDennis Dalessandro * the policy change is not applied. 1653f48ad614SDennis Dalessandro */ 1654f48ad614SDennis Dalessandro if (call_link_downgrade_policy) 1655f48ad614SDennis Dalessandro apply_link_downgrade_policy(ppd, 0); 1656f48ad614SDennis Dalessandro 1657f48ad614SDennis Dalessandro return ret; 1658f48ad614SDennis Dalessandro 1659f48ad614SDennis Dalessandro get_only: 1660f1685179SNeel Desai return __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len, 1661f1685179SNeel Desai max_len); 1662f48ad614SDennis Dalessandro } 1663f48ad614SDennis Dalessandro 1664f48ad614SDennis Dalessandro /** 1665f48ad614SDennis Dalessandro * set_pkeys - set the PKEY table for ctxt 0 1666f48ad614SDennis Dalessandro * @dd: the hfi1_ib device 1667f48ad614SDennis Dalessandro * @port: the IB port number 1668f48ad614SDennis Dalessandro * @pkeys: the PKEY table 1669f48ad614SDennis Dalessandro */ 1670f48ad614SDennis Dalessandro static int set_pkeys(struct hfi1_devdata *dd, u8 port, u16 *pkeys) 1671f48ad614SDennis Dalessandro { 1672f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1673f48ad614SDennis Dalessandro int i; 1674f48ad614SDennis Dalessandro int changed = 0; 1675f48ad614SDennis Dalessandro int update_includes_mgmt_partition = 0; 1676f48ad614SDennis Dalessandro 1677f48ad614SDennis Dalessandro /* 1678f48ad614SDennis Dalessandro * IB port one/two always maps to context zero/one, 1679f48ad614SDennis Dalessandro * always a kernel context, no locking needed 1680f48ad614SDennis Dalessandro * If we get here with ppd setup, no need to check 1681f48ad614SDennis Dalessandro * that rcd is valid. 1682f48ad614SDennis Dalessandro */ 1683f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1684f48ad614SDennis Dalessandro /* 1685f48ad614SDennis Dalessandro * If the update does not include the management pkey, don't do it. 1686f48ad614SDennis Dalessandro */ 1687f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) { 1688f48ad614SDennis Dalessandro if (pkeys[i] == LIM_MGMT_P_KEY) { 1689f48ad614SDennis Dalessandro update_includes_mgmt_partition = 1; 1690f48ad614SDennis Dalessandro break; 1691f48ad614SDennis Dalessandro } 1692f48ad614SDennis Dalessandro } 1693f48ad614SDennis Dalessandro 1694f48ad614SDennis Dalessandro if (!update_includes_mgmt_partition) 1695f48ad614SDennis Dalessandro return 1; 1696f48ad614SDennis Dalessandro 1697f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) { 1698f48ad614SDennis Dalessandro u16 key = pkeys[i]; 1699f48ad614SDennis Dalessandro u16 okey = ppd->pkeys[i]; 1700f48ad614SDennis Dalessandro 1701f48ad614SDennis Dalessandro if (key == okey) 1702f48ad614SDennis Dalessandro continue; 1703f48ad614SDennis Dalessandro /* 1704f48ad614SDennis Dalessandro * The SM gives us the complete PKey table. We have 1705f48ad614SDennis Dalessandro * to ensure that we put the PKeys in the matching 1706f48ad614SDennis Dalessandro * slots. 1707f48ad614SDennis Dalessandro */ 1708f48ad614SDennis Dalessandro ppd->pkeys[i] = key; 1709f48ad614SDennis Dalessandro changed = 1; 1710f48ad614SDennis Dalessandro } 1711f48ad614SDennis Dalessandro 1712f48ad614SDennis Dalessandro if (changed) { 1713f48ad614SDennis Dalessandro (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_PKEYS, 0); 171434d351f8SSebastian Sanchez hfi1_event_pkey_change(dd, port); 1715f48ad614SDennis Dalessandro } 171634d351f8SSebastian Sanchez 1717f48ad614SDennis Dalessandro return 0; 1718f48ad614SDennis Dalessandro } 1719f48ad614SDennis Dalessandro 1720f48ad614SDennis Dalessandro static int __subn_set_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data, 1721f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1722f1685179SNeel Desai u32 *resp_len, u32 max_len) 1723f48ad614SDennis Dalessandro { 1724f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1725f48ad614SDennis Dalessandro u32 n_blocks_sent = OPA_AM_NBLK(am); 1726f48ad614SDennis Dalessandro u32 start_block = am & 0x7ff; 1727f48ad614SDennis Dalessandro u16 *p = (u16 *)data; 1728f48ad614SDennis Dalessandro __be16 *q = (__be16 *)data; 1729f48ad614SDennis Dalessandro int i; 1730f48ad614SDennis Dalessandro u16 n_blocks_avail; 1731f48ad614SDennis Dalessandro unsigned npkeys = hfi1_get_npkeys(dd); 1732f1685179SNeel Desai u32 size = 0; 1733f48ad614SDennis Dalessandro 1734f48ad614SDennis Dalessandro if (n_blocks_sent == 0) { 1735f48ad614SDennis Dalessandro pr_warn("OPA Get PKey AM Invalid : P = %d; B = 0x%x; N = 0x%x\n", 1736f48ad614SDennis Dalessandro port, start_block, n_blocks_sent); 1737f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1738f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1739f48ad614SDennis Dalessandro } 1740f48ad614SDennis Dalessandro 1741f48ad614SDennis Dalessandro n_blocks_avail = (u16)(npkeys / OPA_PARTITION_TABLE_BLK_SIZE) + 1; 1742f48ad614SDennis Dalessandro 1743f1685179SNeel Desai size = sizeof(u16) * (n_blocks_sent * OPA_PARTITION_TABLE_BLK_SIZE); 1744f1685179SNeel Desai 1745f1685179SNeel Desai if (smp_length_check(size, max_len)) { 1746f1685179SNeel Desai smp->status |= IB_SMP_INVALID_FIELD; 1747f1685179SNeel Desai return reply((struct ib_mad_hdr *)smp); 1748f1685179SNeel Desai } 1749f1685179SNeel Desai 1750f48ad614SDennis Dalessandro if (start_block + n_blocks_sent > n_blocks_avail || 1751f48ad614SDennis Dalessandro n_blocks_sent > OPA_NUM_PKEY_BLOCKS_PER_SMP) { 1752f48ad614SDennis Dalessandro pr_warn("OPA Set PKey AM Invalid : s 0x%x; req 0x%x; avail 0x%x; blk/smp 0x%lx\n", 1753f48ad614SDennis Dalessandro start_block, n_blocks_sent, n_blocks_avail, 1754f48ad614SDennis Dalessandro OPA_NUM_PKEY_BLOCKS_PER_SMP); 1755f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1756f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1757f48ad614SDennis Dalessandro } 1758f48ad614SDennis Dalessandro 1759f48ad614SDennis Dalessandro for (i = 0; i < n_blocks_sent * OPA_PARTITION_TABLE_BLK_SIZE; i++) 1760f48ad614SDennis Dalessandro p[i] = be16_to_cpu(q[i]); 1761f48ad614SDennis Dalessandro 1762f48ad614SDennis Dalessandro if (start_block == 0 && set_pkeys(dd, port, p) != 0) { 1763f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1764f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1765f48ad614SDennis Dalessandro } 1766f48ad614SDennis Dalessandro 1767f1685179SNeel Desai return __subn_get_opa_pkeytable(smp, am, data, ibdev, port, resp_len, 1768f1685179SNeel Desai max_len); 1769f48ad614SDennis Dalessandro } 1770f48ad614SDennis Dalessandro 1771f48ad614SDennis Dalessandro #define ILLEGAL_VL 12 1772f48ad614SDennis Dalessandro /* 1773f48ad614SDennis Dalessandro * filter_sc2vlt changes mappings to VL15 to ILLEGAL_VL (except 1774f48ad614SDennis Dalessandro * for SC15, which must map to VL15). If we don't remap things this 1775f48ad614SDennis Dalessandro * way it is possible for VL15 counters to increment when we try to 1776f48ad614SDennis Dalessandro * send on a SC which is mapped to an invalid VL. 17773ca4fbc8SSebastian Sanchez * When getting the table convert ILLEGAL_VL back to VL15. 1778f48ad614SDennis Dalessandro */ 17793ca4fbc8SSebastian Sanchez static void filter_sc2vlt(void *data, bool set) 1780f48ad614SDennis Dalessandro { 1781f48ad614SDennis Dalessandro int i; 1782f48ad614SDennis Dalessandro u8 *pd = data; 1783f48ad614SDennis Dalessandro 1784f48ad614SDennis Dalessandro for (i = 0; i < OPA_MAX_SCS; i++) { 1785f48ad614SDennis Dalessandro if (i == 15) 1786f48ad614SDennis Dalessandro continue; 17873ca4fbc8SSebastian Sanchez 17883ca4fbc8SSebastian Sanchez if (set) { 1789f48ad614SDennis Dalessandro if ((pd[i] & 0x1f) == 0xf) 1790f48ad614SDennis Dalessandro pd[i] = ILLEGAL_VL; 17913ca4fbc8SSebastian Sanchez } else { 17923ca4fbc8SSebastian Sanchez if ((pd[i] & 0x1f) == ILLEGAL_VL) 17933ca4fbc8SSebastian Sanchez pd[i] = 0xf; 17943ca4fbc8SSebastian Sanchez } 1795f48ad614SDennis Dalessandro } 1796f48ad614SDennis Dalessandro } 1797f48ad614SDennis Dalessandro 1798f48ad614SDennis Dalessandro static int set_sc2vlt_tables(struct hfi1_devdata *dd, void *data) 1799f48ad614SDennis Dalessandro { 1800f48ad614SDennis Dalessandro u64 *val = data; 1801f48ad614SDennis Dalessandro 18023ca4fbc8SSebastian Sanchez filter_sc2vlt(data, true); 1803f48ad614SDennis Dalessandro 1804f48ad614SDennis Dalessandro write_csr(dd, SEND_SC2VLT0, *val++); 1805f48ad614SDennis Dalessandro write_csr(dd, SEND_SC2VLT1, *val++); 1806f48ad614SDennis Dalessandro write_csr(dd, SEND_SC2VLT2, *val++); 1807f48ad614SDennis Dalessandro write_csr(dd, SEND_SC2VLT3, *val++); 1808f48ad614SDennis Dalessandro write_seqlock_irq(&dd->sc2vl_lock); 1809f48ad614SDennis Dalessandro memcpy(dd->sc2vl, data, sizeof(dd->sc2vl)); 1810f48ad614SDennis Dalessandro write_sequnlock_irq(&dd->sc2vl_lock); 1811f48ad614SDennis Dalessandro return 0; 1812f48ad614SDennis Dalessandro } 1813f48ad614SDennis Dalessandro 18143ca4fbc8SSebastian Sanchez static int get_sc2vlt_tables(struct hfi1_devdata *dd, void *data) 18153ca4fbc8SSebastian Sanchez { 18163ca4fbc8SSebastian Sanchez u64 *val = (u64 *)data; 18173ca4fbc8SSebastian Sanchez 18183ca4fbc8SSebastian Sanchez *val++ = read_csr(dd, SEND_SC2VLT0); 18193ca4fbc8SSebastian Sanchez *val++ = read_csr(dd, SEND_SC2VLT1); 18203ca4fbc8SSebastian Sanchez *val++ = read_csr(dd, SEND_SC2VLT2); 18213ca4fbc8SSebastian Sanchez *val++ = read_csr(dd, SEND_SC2VLT3); 18223ca4fbc8SSebastian Sanchez 18233ca4fbc8SSebastian Sanchez filter_sc2vlt((u64 *)data, false); 18243ca4fbc8SSebastian Sanchez return 0; 18253ca4fbc8SSebastian Sanchez } 18263ca4fbc8SSebastian Sanchez 1827f48ad614SDennis Dalessandro static int __subn_get_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data, 1828f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1829f1685179SNeel Desai u32 *resp_len, u32 max_len) 1830f48ad614SDennis Dalessandro { 1831f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 1832f48ad614SDennis Dalessandro u8 *p = data; 1833f48ad614SDennis Dalessandro size_t size = ARRAY_SIZE(ibp->sl_to_sc); /* == 32 */ 1834f48ad614SDennis Dalessandro unsigned i; 1835f48ad614SDennis Dalessandro 1836f1685179SNeel Desai if (am || smp_length_check(size, max_len)) { 1837f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1838f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1839f48ad614SDennis Dalessandro } 1840f48ad614SDennis Dalessandro 1841f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ibp->sl_to_sc); i++) 1842f48ad614SDennis Dalessandro *p++ = ibp->sl_to_sc[i]; 1843f48ad614SDennis Dalessandro 1844f48ad614SDennis Dalessandro if (resp_len) 1845f48ad614SDennis Dalessandro *resp_len += size; 1846f48ad614SDennis Dalessandro 1847f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1848f48ad614SDennis Dalessandro } 1849f48ad614SDennis Dalessandro 1850f48ad614SDennis Dalessandro static int __subn_set_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data, 1851f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1852f1685179SNeel Desai u32 *resp_len, u32 max_len) 1853f48ad614SDennis Dalessandro { 1854f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 1855f48ad614SDennis Dalessandro u8 *p = data; 1856f1685179SNeel Desai size_t size = ARRAY_SIZE(ibp->sl_to_sc); 1857f48ad614SDennis Dalessandro int i; 1858f48ad614SDennis Dalessandro u8 sc; 1859f48ad614SDennis Dalessandro 1860f1685179SNeel Desai if (am || smp_length_check(size, max_len)) { 1861f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1862f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1863f48ad614SDennis Dalessandro } 1864f48ad614SDennis Dalessandro 1865f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ibp->sl_to_sc); i++) { 1866f48ad614SDennis Dalessandro sc = *p++; 1867f48ad614SDennis Dalessandro if (ibp->sl_to_sc[i] != sc) { 1868f48ad614SDennis Dalessandro ibp->sl_to_sc[i] = sc; 1869f48ad614SDennis Dalessandro 1870f48ad614SDennis Dalessandro /* Put all stale qps into error state */ 1871f48ad614SDennis Dalessandro hfi1_error_port_qps(ibp, i); 1872f48ad614SDennis Dalessandro } 1873f48ad614SDennis Dalessandro } 1874f48ad614SDennis Dalessandro 1875f1685179SNeel Desai return __subn_get_opa_sl_to_sc(smp, am, data, ibdev, port, resp_len, 1876f1685179SNeel Desai max_len); 1877f48ad614SDennis Dalessandro } 1878f48ad614SDennis Dalessandro 1879f48ad614SDennis Dalessandro static int __subn_get_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data, 1880f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1881f1685179SNeel Desai u32 *resp_len, u32 max_len) 1882f48ad614SDennis Dalessandro { 1883f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 1884f48ad614SDennis Dalessandro u8 *p = data; 1885f48ad614SDennis Dalessandro size_t size = ARRAY_SIZE(ibp->sc_to_sl); /* == 32 */ 1886f48ad614SDennis Dalessandro unsigned i; 1887f48ad614SDennis Dalessandro 1888f1685179SNeel Desai if (am || smp_length_check(size, max_len)) { 1889f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1890f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1891f48ad614SDennis Dalessandro } 1892f48ad614SDennis Dalessandro 1893f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ibp->sc_to_sl); i++) 1894f48ad614SDennis Dalessandro *p++ = ibp->sc_to_sl[i]; 1895f48ad614SDennis Dalessandro 1896f48ad614SDennis Dalessandro if (resp_len) 1897f48ad614SDennis Dalessandro *resp_len += size; 1898f48ad614SDennis Dalessandro 1899f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1900f48ad614SDennis Dalessandro } 1901f48ad614SDennis Dalessandro 1902f48ad614SDennis Dalessandro static int __subn_set_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data, 1903f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1904f1685179SNeel Desai u32 *resp_len, u32 max_len) 1905f48ad614SDennis Dalessandro { 1906f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 1907f1685179SNeel Desai size_t size = ARRAY_SIZE(ibp->sc_to_sl); 1908f48ad614SDennis Dalessandro u8 *p = data; 1909f48ad614SDennis Dalessandro int i; 1910f48ad614SDennis Dalessandro 1911f1685179SNeel Desai if (am || smp_length_check(size, max_len)) { 1912f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1913f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1914f48ad614SDennis Dalessandro } 1915f48ad614SDennis Dalessandro 1916f48ad614SDennis Dalessandro for (i = 0; i < ARRAY_SIZE(ibp->sc_to_sl); i++) 1917f48ad614SDennis Dalessandro ibp->sc_to_sl[i] = *p++; 1918f48ad614SDennis Dalessandro 1919f1685179SNeel Desai return __subn_get_opa_sc_to_sl(smp, am, data, ibdev, port, resp_len, 1920f1685179SNeel Desai max_len); 1921f48ad614SDennis Dalessandro } 1922f48ad614SDennis Dalessandro 1923f48ad614SDennis Dalessandro static int __subn_get_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data, 1924f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1925f1685179SNeel Desai u32 *resp_len, u32 max_len) 1926f48ad614SDennis Dalessandro { 1927f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NBLK(am); 1928f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1929f48ad614SDennis Dalessandro void *vp = (void *)data; 1930f48ad614SDennis Dalessandro size_t size = 4 * sizeof(u64); 1931f48ad614SDennis Dalessandro 1932f1685179SNeel Desai if (n_blocks != 1 || smp_length_check(size, max_len)) { 1933f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1934f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1935f48ad614SDennis Dalessandro } 1936f48ad614SDennis Dalessandro 1937f48ad614SDennis Dalessandro get_sc2vlt_tables(dd, vp); 1938f48ad614SDennis Dalessandro 1939f48ad614SDennis Dalessandro if (resp_len) 1940f48ad614SDennis Dalessandro *resp_len += size; 1941f48ad614SDennis Dalessandro 1942f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1943f48ad614SDennis Dalessandro } 1944f48ad614SDennis Dalessandro 1945f48ad614SDennis Dalessandro static int __subn_set_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data, 1946f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1947f1685179SNeel Desai u32 *resp_len, u32 max_len) 1948f48ad614SDennis Dalessandro { 1949f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NBLK(am); 1950f48ad614SDennis Dalessandro int async_update = OPA_AM_ASYNC(am); 1951f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1952f48ad614SDennis Dalessandro void *vp = (void *)data; 1953f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1954f48ad614SDennis Dalessandro int lstate; 1955f1685179SNeel Desai /* 1956f1685179SNeel Desai * set_sc2vlt_tables writes the information contained in *data 1957f1685179SNeel Desai * to four 64-bit registers SendSC2VLt[0-3]. We need to make 1958f1685179SNeel Desai * sure *max_len is not greater than the total size of the four 1959f1685179SNeel Desai * SendSC2VLt[0-3] registers. 1960f1685179SNeel Desai */ 1961f1685179SNeel Desai size_t size = 4 * sizeof(u64); 1962f48ad614SDennis Dalessandro 1963f1685179SNeel Desai if (n_blocks != 1 || async_update || smp_length_check(size, max_len)) { 1964f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1965f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1966f48ad614SDennis Dalessandro } 1967f48ad614SDennis Dalessandro 1968f48ad614SDennis Dalessandro /* IB numbers ports from 1, hw from 0 */ 1969f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 1970f48ad614SDennis Dalessandro lstate = driver_lstate(ppd); 1971f48ad614SDennis Dalessandro /* 1972f48ad614SDennis Dalessandro * it's known that async_update is 0 by this point, but include 1973f48ad614SDennis Dalessandro * the explicit check for clarity 1974f48ad614SDennis Dalessandro */ 1975f48ad614SDennis Dalessandro if (!async_update && 1976f48ad614SDennis Dalessandro (lstate == IB_PORT_ARMED || lstate == IB_PORT_ACTIVE)) { 1977f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1978f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 1979f48ad614SDennis Dalessandro } 1980f48ad614SDennis Dalessandro 1981f48ad614SDennis Dalessandro set_sc2vlt_tables(dd, vp); 1982f48ad614SDennis Dalessandro 1983f1685179SNeel Desai return __subn_get_opa_sc_to_vlt(smp, am, data, ibdev, port, resp_len, 1984f1685179SNeel Desai max_len); 1985f48ad614SDennis Dalessandro } 1986f48ad614SDennis Dalessandro 1987f48ad614SDennis Dalessandro static int __subn_get_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data, 1988f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 1989f1685179SNeel Desai u32 *resp_len, u32 max_len) 1990f48ad614SDennis Dalessandro { 1991f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NPORT(am); 1992f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 1993f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 1994f48ad614SDennis Dalessandro void *vp = (void *)data; 1995f1685179SNeel Desai int size = sizeof(struct sc2vlnt); 1996f48ad614SDennis Dalessandro 1997f1685179SNeel Desai if (n_blocks != 1 || smp_length_check(size, max_len)) { 1998f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 1999f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2000f48ad614SDennis Dalessandro } 2001f48ad614SDennis Dalessandro 2002f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 2003f48ad614SDennis Dalessandro 2004f1685179SNeel Desai fm_get_table(ppd, FM_TBL_SC2VLNT, vp); 2005f48ad614SDennis Dalessandro 2006f48ad614SDennis Dalessandro if (resp_len) 2007f48ad614SDennis Dalessandro *resp_len += size; 2008f48ad614SDennis Dalessandro 2009f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2010f48ad614SDennis Dalessandro } 2011f48ad614SDennis Dalessandro 2012f48ad614SDennis Dalessandro static int __subn_set_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data, 2013f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 2014f1685179SNeel Desai u32 *resp_len, u32 max_len) 2015f48ad614SDennis Dalessandro { 2016f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NPORT(am); 2017f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2018f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 2019f48ad614SDennis Dalessandro void *vp = (void *)data; 2020f48ad614SDennis Dalessandro int lstate; 2021f1685179SNeel Desai int size = sizeof(struct sc2vlnt); 2022f48ad614SDennis Dalessandro 2023f1685179SNeel Desai if (n_blocks != 1 || smp_length_check(size, max_len)) { 2024f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2025f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2026f48ad614SDennis Dalessandro } 2027f48ad614SDennis Dalessandro 2028f48ad614SDennis Dalessandro /* IB numbers ports from 1, hw from 0 */ 2029f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 2030f48ad614SDennis Dalessandro lstate = driver_lstate(ppd); 2031f48ad614SDennis Dalessandro if (lstate == IB_PORT_ARMED || lstate == IB_PORT_ACTIVE) { 2032f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2033f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2034f48ad614SDennis Dalessandro } 2035f48ad614SDennis Dalessandro 2036f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 2037f48ad614SDennis Dalessandro 2038f48ad614SDennis Dalessandro fm_set_table(ppd, FM_TBL_SC2VLNT, vp); 2039f48ad614SDennis Dalessandro 2040f48ad614SDennis Dalessandro return __subn_get_opa_sc_to_vlnt(smp, am, data, ibdev, port, 2041f1685179SNeel Desai resp_len, max_len); 2042f48ad614SDennis Dalessandro } 2043f48ad614SDennis Dalessandro 2044f48ad614SDennis Dalessandro static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data, 2045f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 2046f1685179SNeel Desai u32 *resp_len, u32 max_len) 2047f48ad614SDennis Dalessandro { 2048f48ad614SDennis Dalessandro u32 nports = OPA_AM_NPORT(am); 2049f48ad614SDennis Dalessandro u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); 2050f48ad614SDennis Dalessandro u32 lstate; 2051f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 2052f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 2053f48ad614SDennis Dalessandro struct opa_port_state_info *psi = (struct opa_port_state_info *)data; 2054f48ad614SDennis Dalessandro 2055f1685179SNeel Desai if (nports != 1 || smp_length_check(sizeof(*psi), max_len)) { 2056f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2057f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2058f48ad614SDennis Dalessandro } 2059f48ad614SDennis Dalessandro 2060f48ad614SDennis Dalessandro ibp = to_iport(ibdev, port); 2061f48ad614SDennis Dalessandro ppd = ppd_from_ibp(ibp); 2062f48ad614SDennis Dalessandro 2063f48ad614SDennis Dalessandro lstate = driver_lstate(ppd); 2064f48ad614SDennis Dalessandro 2065f48ad614SDennis Dalessandro if (start_of_sm_config && (lstate == IB_PORT_INIT)) 2066f48ad614SDennis Dalessandro ppd->is_sm_config_started = 1; 2067f48ad614SDennis Dalessandro 2068f48ad614SDennis Dalessandro psi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4; 2069f48ad614SDennis Dalessandro psi->port_states.ledenable_offlinereason |= 2070f48ad614SDennis Dalessandro ppd->is_sm_config_started << 5; 2071f48ad614SDennis Dalessandro psi->port_states.ledenable_offlinereason |= 2072f48ad614SDennis Dalessandro ppd->offline_disabled_reason; 2073f48ad614SDennis Dalessandro 2074f48ad614SDennis Dalessandro psi->port_states.portphysstate_portstate = 2075bec7c79cSByczkowski, Jakub (driver_pstate(ppd) << 4) | (lstate & 0xf); 2076f48ad614SDennis Dalessandro psi->link_width_downgrade_tx_active = 2077f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_tx_active); 2078f48ad614SDennis Dalessandro psi->link_width_downgrade_rx_active = 2079f48ad614SDennis Dalessandro cpu_to_be16(ppd->link_width_downgrade_rx_active); 2080f48ad614SDennis Dalessandro if (resp_len) 2081f48ad614SDennis Dalessandro *resp_len += sizeof(struct opa_port_state_info); 2082f48ad614SDennis Dalessandro 2083f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2084f48ad614SDennis Dalessandro } 2085f48ad614SDennis Dalessandro 2086f48ad614SDennis Dalessandro static int __subn_set_opa_psi(struct opa_smp *smp, u32 am, u8 *data, 2087f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 2088959f2d17SAlex Estrin u32 *resp_len, u32 max_len, int local_mad) 2089f48ad614SDennis Dalessandro { 2090f48ad614SDennis Dalessandro u32 nports = OPA_AM_NPORT(am); 2091f48ad614SDennis Dalessandro u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); 2092f48ad614SDennis Dalessandro u32 ls_old; 2093f48ad614SDennis Dalessandro u8 ls_new, ps_new; 2094f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 2095f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 2096f48ad614SDennis Dalessandro struct opa_port_state_info *psi = (struct opa_port_state_info *)data; 2097f48ad614SDennis Dalessandro int ret, invalid = 0; 2098f48ad614SDennis Dalessandro 2099f1685179SNeel Desai if (nports != 1 || smp_length_check(sizeof(*psi), max_len)) { 2100f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2101f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2102f48ad614SDennis Dalessandro } 2103f48ad614SDennis Dalessandro 2104f48ad614SDennis Dalessandro ibp = to_iport(ibdev, port); 2105f48ad614SDennis Dalessandro ppd = ppd_from_ibp(ibp); 2106f48ad614SDennis Dalessandro 2107f48ad614SDennis Dalessandro ls_old = driver_lstate(ppd); 2108f48ad614SDennis Dalessandro 2109f48ad614SDennis Dalessandro ls_new = port_states_to_logical_state(&psi->port_states); 2110f48ad614SDennis Dalessandro ps_new = port_states_to_phys_state(&psi->port_states); 2111f48ad614SDennis Dalessandro 2112f48ad614SDennis Dalessandro if (ls_old == IB_PORT_INIT) { 2113f48ad614SDennis Dalessandro if (start_of_sm_config) { 2114f48ad614SDennis Dalessandro if (ls_new == ls_old || (ls_new == IB_PORT_ARMED)) 2115f48ad614SDennis Dalessandro ppd->is_sm_config_started = 1; 2116f48ad614SDennis Dalessandro } else if (ls_new == IB_PORT_ARMED) { 2117a276672eSGrzegorz Morys if (ppd->is_sm_config_started == 0) { 2118f48ad614SDennis Dalessandro invalid = 1; 2119a276672eSGrzegorz Morys smp->status |= IB_SMP_INVALID_FIELD; 2120a276672eSGrzegorz Morys } 2121f48ad614SDennis Dalessandro } 2122f48ad614SDennis Dalessandro } 2123f48ad614SDennis Dalessandro 2124a276672eSGrzegorz Morys if (!invalid) { 2125959f2d17SAlex Estrin ret = set_port_states(ppd, smp, ls_new, ps_new, local_mad); 2126f48ad614SDennis Dalessandro if (ret) 2127f48ad614SDennis Dalessandro return ret; 2128a276672eSGrzegorz Morys } 2129f48ad614SDennis Dalessandro 2130f1685179SNeel Desai return __subn_get_opa_psi(smp, am, data, ibdev, port, resp_len, 2131f1685179SNeel Desai max_len); 2132f48ad614SDennis Dalessandro } 2133f48ad614SDennis Dalessandro 2134f48ad614SDennis Dalessandro static int __subn_get_opa_cable_info(struct opa_smp *smp, u32 am, u8 *data, 2135f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 2136f1685179SNeel Desai u32 *resp_len, u32 max_len) 2137f48ad614SDennis Dalessandro { 2138f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2139f48ad614SDennis Dalessandro u32 addr = OPA_AM_CI_ADDR(am); 2140f48ad614SDennis Dalessandro u32 len = OPA_AM_CI_LEN(am) + 1; 2141f48ad614SDennis Dalessandro int ret; 2142f48ad614SDennis Dalessandro 2143f1685179SNeel Desai if (dd->pport->port_type != PORT_TYPE_QSFP || 2144f1685179SNeel Desai smp_length_check(len, max_len)) { 2145f29a08dcSEaswar Hariharan smp->status |= IB_SMP_INVALID_FIELD; 2146f29a08dcSEaswar Hariharan return reply((struct ib_mad_hdr *)smp); 2147f29a08dcSEaswar Hariharan } 2148f29a08dcSEaswar Hariharan 2149f48ad614SDennis Dalessandro #define __CI_PAGE_SIZE BIT(7) /* 128 bytes */ 2150f48ad614SDennis Dalessandro #define __CI_PAGE_MASK ~(__CI_PAGE_SIZE - 1) 2151f48ad614SDennis Dalessandro #define __CI_PAGE_NUM(a) ((a) & __CI_PAGE_MASK) 2152f48ad614SDennis Dalessandro 2153f48ad614SDennis Dalessandro /* 2154f48ad614SDennis Dalessandro * check that addr is within spec, and 2155f48ad614SDennis Dalessandro * addr and (addr + len - 1) are on the same "page" 2156f48ad614SDennis Dalessandro */ 2157f48ad614SDennis Dalessandro if (addr >= 4096 || 2158f48ad614SDennis Dalessandro (__CI_PAGE_NUM(addr) != __CI_PAGE_NUM(addr + len - 1))) { 2159f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2160f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2161f48ad614SDennis Dalessandro } 2162f48ad614SDennis Dalessandro 2163f48ad614SDennis Dalessandro ret = get_cable_info(dd, port, addr, len, data); 2164f48ad614SDennis Dalessandro 2165f48ad614SDennis Dalessandro if (ret == -ENODEV) { 2166f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 2167f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2168f48ad614SDennis Dalessandro } 2169f48ad614SDennis Dalessandro 2170f48ad614SDennis Dalessandro /* The address range for the CableInfo SMA query is wider than the 2171f48ad614SDennis Dalessandro * memory available on the QSFP cable. We want to return a valid 2172f48ad614SDennis Dalessandro * response, albeit zeroed out, for address ranges beyond available 2173f48ad614SDennis Dalessandro * memory but that are within the CableInfo query spec 2174f48ad614SDennis Dalessandro */ 2175f48ad614SDennis Dalessandro if (ret < 0 && ret != -ERANGE) { 2176f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2177f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2178f48ad614SDennis Dalessandro } 2179f48ad614SDennis Dalessandro 2180f48ad614SDennis Dalessandro if (resp_len) 2181f48ad614SDennis Dalessandro *resp_len += len; 2182f48ad614SDennis Dalessandro 2183f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2184f48ad614SDennis Dalessandro } 2185f48ad614SDennis Dalessandro 2186f48ad614SDennis Dalessandro static int __subn_get_opa_bct(struct opa_smp *smp, u32 am, u8 *data, 2187f1685179SNeel Desai struct ib_device *ibdev, u8 port, u32 *resp_len, 2188f1685179SNeel Desai u32 max_len) 2189f48ad614SDennis Dalessandro { 2190f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 2191f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2192f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 2193f48ad614SDennis Dalessandro struct buffer_control *p = (struct buffer_control *)data; 2194f1685179SNeel Desai int size = sizeof(struct buffer_control); 2195f48ad614SDennis Dalessandro 2196f1685179SNeel Desai if (num_ports != 1 || smp_length_check(size, max_len)) { 2197f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2198f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2199f48ad614SDennis Dalessandro } 2200f48ad614SDennis Dalessandro 2201f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 2202f1685179SNeel Desai fm_get_table(ppd, FM_TBL_BUFFER_CONTROL, p); 2203f48ad614SDennis Dalessandro trace_bct_get(dd, p); 2204f48ad614SDennis Dalessandro if (resp_len) 2205f48ad614SDennis Dalessandro *resp_len += size; 2206f48ad614SDennis Dalessandro 2207f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2208f48ad614SDennis Dalessandro } 2209f48ad614SDennis Dalessandro 2210f48ad614SDennis Dalessandro static int __subn_set_opa_bct(struct opa_smp *smp, u32 am, u8 *data, 2211f1685179SNeel Desai struct ib_device *ibdev, u8 port, u32 *resp_len, 2212f1685179SNeel Desai u32 max_len) 2213f48ad614SDennis Dalessandro { 2214f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 2215f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2216f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 2217f48ad614SDennis Dalessandro struct buffer_control *p = (struct buffer_control *)data; 2218f48ad614SDennis Dalessandro 2219f1685179SNeel Desai if (num_ports != 1 || smp_length_check(sizeof(*p), max_len)) { 2220f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2221f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2222f48ad614SDennis Dalessandro } 2223f48ad614SDennis Dalessandro ppd = dd->pport + (port - 1); 2224f48ad614SDennis Dalessandro trace_bct_set(dd, p); 2225f48ad614SDennis Dalessandro if (fm_set_table(ppd, FM_TBL_BUFFER_CONTROL, p) < 0) { 2226f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2227f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2228f48ad614SDennis Dalessandro } 2229f48ad614SDennis Dalessandro 2230f1685179SNeel Desai return __subn_get_opa_bct(smp, am, data, ibdev, port, resp_len, 2231f1685179SNeel Desai max_len); 2232f48ad614SDennis Dalessandro } 2233f48ad614SDennis Dalessandro 2234f48ad614SDennis Dalessandro static int __subn_get_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data, 2235f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 2236f1685179SNeel Desai u32 *resp_len, u32 max_len) 2237f48ad614SDennis Dalessandro { 2238f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port)); 2239f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 2240f48ad614SDennis Dalessandro u8 section = (am & 0x00ff0000) >> 16; 2241f48ad614SDennis Dalessandro u8 *p = data; 2242f1685179SNeel Desai int size = 256; 2243f48ad614SDennis Dalessandro 2244f1685179SNeel Desai if (num_ports != 1 || smp_length_check(size, max_len)) { 2245f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2246f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2247f48ad614SDennis Dalessandro } 2248f48ad614SDennis Dalessandro 2249f48ad614SDennis Dalessandro switch (section) { 2250f48ad614SDennis Dalessandro case OPA_VLARB_LOW_ELEMENTS: 2251f1685179SNeel Desai fm_get_table(ppd, FM_TBL_VL_LOW_ARB, p); 2252f48ad614SDennis Dalessandro break; 2253f48ad614SDennis Dalessandro case OPA_VLARB_HIGH_ELEMENTS: 2254f1685179SNeel Desai fm_get_table(ppd, FM_TBL_VL_HIGH_ARB, p); 2255f48ad614SDennis Dalessandro break; 2256f48ad614SDennis Dalessandro case OPA_VLARB_PREEMPT_ELEMENTS: 2257f1685179SNeel Desai fm_get_table(ppd, FM_TBL_VL_PREEMPT_ELEMS, p); 2258f48ad614SDennis Dalessandro break; 2259f48ad614SDennis Dalessandro case OPA_VLARB_PREEMPT_MATRIX: 2260f1685179SNeel Desai fm_get_table(ppd, FM_TBL_VL_PREEMPT_MATRIX, p); 2261f48ad614SDennis Dalessandro break; 2262f48ad614SDennis Dalessandro default: 2263f48ad614SDennis Dalessandro pr_warn("OPA SubnGet(VL Arb) AM Invalid : 0x%x\n", 2264f48ad614SDennis Dalessandro be32_to_cpu(smp->attr_mod)); 2265f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2266f1685179SNeel Desai size = 0; 2267f48ad614SDennis Dalessandro break; 2268f48ad614SDennis Dalessandro } 2269f48ad614SDennis Dalessandro 2270f48ad614SDennis Dalessandro if (size > 0 && resp_len) 2271f48ad614SDennis Dalessandro *resp_len += size; 2272f48ad614SDennis Dalessandro 2273f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2274f48ad614SDennis Dalessandro } 2275f48ad614SDennis Dalessandro 2276f48ad614SDennis Dalessandro static int __subn_set_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data, 2277f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 2278f1685179SNeel Desai u32 *resp_len, u32 max_len) 2279f48ad614SDennis Dalessandro { 2280f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port)); 2281f48ad614SDennis Dalessandro u32 num_ports = OPA_AM_NPORT(am); 2282f48ad614SDennis Dalessandro u8 section = (am & 0x00ff0000) >> 16; 2283f48ad614SDennis Dalessandro u8 *p = data; 2284f1685179SNeel Desai int size = 256; 2285f48ad614SDennis Dalessandro 2286f1685179SNeel Desai if (num_ports != 1 || smp_length_check(size, max_len)) { 2287f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2288f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 2289f48ad614SDennis Dalessandro } 2290f48ad614SDennis Dalessandro 2291f48ad614SDennis Dalessandro switch (section) { 2292f48ad614SDennis Dalessandro case OPA_VLARB_LOW_ELEMENTS: 2293f48ad614SDennis Dalessandro (void)fm_set_table(ppd, FM_TBL_VL_LOW_ARB, p); 2294f48ad614SDennis Dalessandro break; 2295f48ad614SDennis Dalessandro case OPA_VLARB_HIGH_ELEMENTS: 2296f48ad614SDennis Dalessandro (void)fm_set_table(ppd, FM_TBL_VL_HIGH_ARB, p); 2297f48ad614SDennis Dalessandro break; 2298f48ad614SDennis Dalessandro /* 2299f48ad614SDennis Dalessandro * neither OPA_VLARB_PREEMPT_ELEMENTS, or OPA_VLARB_PREEMPT_MATRIX 2300f48ad614SDennis Dalessandro * can be changed from the default values 2301f48ad614SDennis Dalessandro */ 2302f48ad614SDennis Dalessandro case OPA_VLARB_PREEMPT_ELEMENTS: 2303f48ad614SDennis Dalessandro case OPA_VLARB_PREEMPT_MATRIX: 2304f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 2305f48ad614SDennis Dalessandro break; 2306f48ad614SDennis Dalessandro default: 2307f48ad614SDennis Dalessandro pr_warn("OPA SubnSet(VL Arb) AM Invalid : 0x%x\n", 2308f48ad614SDennis Dalessandro be32_to_cpu(smp->attr_mod)); 2309f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 2310f48ad614SDennis Dalessandro break; 2311f48ad614SDennis Dalessandro } 2312f48ad614SDennis Dalessandro 2313f1685179SNeel Desai return __subn_get_opa_vl_arb(smp, am, data, ibdev, port, resp_len, 2314f1685179SNeel Desai max_len); 2315f48ad614SDennis Dalessandro } 2316f48ad614SDennis Dalessandro 2317f48ad614SDennis Dalessandro struct opa_pma_mad { 2318f48ad614SDennis Dalessandro struct ib_mad_hdr mad_hdr; 2319f48ad614SDennis Dalessandro u8 data[2024]; 2320f48ad614SDennis Dalessandro } __packed; 2321f48ad614SDennis Dalessandro 2322f48ad614SDennis Dalessandro struct opa_port_status_req { 2323f48ad614SDennis Dalessandro __u8 port_num; 2324f48ad614SDennis Dalessandro __u8 reserved[3]; 2325f48ad614SDennis Dalessandro __be32 vl_select_mask; 2326f48ad614SDennis Dalessandro }; 2327f48ad614SDennis Dalessandro 2328f8659d68SIra Weiny #define VL_MASK_ALL 0x00000000000080ffUL 2329f48ad614SDennis Dalessandro 2330f48ad614SDennis Dalessandro struct opa_port_status_rsp { 2331f48ad614SDennis Dalessandro __u8 port_num; 2332f48ad614SDennis Dalessandro __u8 reserved[3]; 2333f48ad614SDennis Dalessandro __be32 vl_select_mask; 2334f48ad614SDennis Dalessandro 2335f48ad614SDennis Dalessandro /* Data counters */ 2336f48ad614SDennis Dalessandro __be64 port_xmit_data; 2337f48ad614SDennis Dalessandro __be64 port_rcv_data; 2338f48ad614SDennis Dalessandro __be64 port_xmit_pkts; 2339f48ad614SDennis Dalessandro __be64 port_rcv_pkts; 2340f48ad614SDennis Dalessandro __be64 port_multicast_xmit_pkts; 2341f48ad614SDennis Dalessandro __be64 port_multicast_rcv_pkts; 2342f48ad614SDennis Dalessandro __be64 port_xmit_wait; 2343f48ad614SDennis Dalessandro __be64 sw_port_congestion; 2344f48ad614SDennis Dalessandro __be64 port_rcv_fecn; 2345f48ad614SDennis Dalessandro __be64 port_rcv_becn; 2346f48ad614SDennis Dalessandro __be64 port_xmit_time_cong; 2347f48ad614SDennis Dalessandro __be64 port_xmit_wasted_bw; 2348f48ad614SDennis Dalessandro __be64 port_xmit_wait_data; 2349f48ad614SDennis Dalessandro __be64 port_rcv_bubble; 2350f48ad614SDennis Dalessandro __be64 port_mark_fecn; 2351f48ad614SDennis Dalessandro /* Error counters */ 2352f48ad614SDennis Dalessandro __be64 port_rcv_constraint_errors; 2353f48ad614SDennis Dalessandro __be64 port_rcv_switch_relay_errors; 2354f48ad614SDennis Dalessandro __be64 port_xmit_discards; 2355f48ad614SDennis Dalessandro __be64 port_xmit_constraint_errors; 2356f48ad614SDennis Dalessandro __be64 port_rcv_remote_physical_errors; 2357f48ad614SDennis Dalessandro __be64 local_link_integrity_errors; 2358f48ad614SDennis Dalessandro __be64 port_rcv_errors; 2359f48ad614SDennis Dalessandro __be64 excessive_buffer_overruns; 2360f48ad614SDennis Dalessandro __be64 fm_config_errors; 2361f48ad614SDennis Dalessandro __be32 link_error_recovery; 2362f48ad614SDennis Dalessandro __be32 link_downed; 2363f48ad614SDennis Dalessandro u8 uncorrectable_errors; 2364f48ad614SDennis Dalessandro 2365f48ad614SDennis Dalessandro u8 link_quality_indicator; /* 5res, 3bit */ 2366f48ad614SDennis Dalessandro u8 res2[6]; 2367f48ad614SDennis Dalessandro struct _vls_pctrs { 2368f48ad614SDennis Dalessandro /* per-VL Data counters */ 2369f48ad614SDennis Dalessandro __be64 port_vl_xmit_data; 2370f48ad614SDennis Dalessandro __be64 port_vl_rcv_data; 2371f48ad614SDennis Dalessandro __be64 port_vl_xmit_pkts; 2372f48ad614SDennis Dalessandro __be64 port_vl_rcv_pkts; 2373f48ad614SDennis Dalessandro __be64 port_vl_xmit_wait; 2374f48ad614SDennis Dalessandro __be64 sw_port_vl_congestion; 2375f48ad614SDennis Dalessandro __be64 port_vl_rcv_fecn; 2376f48ad614SDennis Dalessandro __be64 port_vl_rcv_becn; 2377f48ad614SDennis Dalessandro __be64 port_xmit_time_cong; 2378f48ad614SDennis Dalessandro __be64 port_vl_xmit_wasted_bw; 2379f48ad614SDennis Dalessandro __be64 port_vl_xmit_wait_data; 2380f48ad614SDennis Dalessandro __be64 port_vl_rcv_bubble; 2381f48ad614SDennis Dalessandro __be64 port_vl_mark_fecn; 2382f48ad614SDennis Dalessandro __be64 port_vl_xmit_discards; 23835b361328SGustavo A. R. Silva } vls[]; /* real array size defined by # bits set in vl_select_mask */ 2384f48ad614SDennis Dalessandro }; 2385f48ad614SDennis Dalessandro 2386f48ad614SDennis Dalessandro enum counter_selects { 2387f48ad614SDennis Dalessandro CS_PORT_XMIT_DATA = (1 << 31), 2388f48ad614SDennis Dalessandro CS_PORT_RCV_DATA = (1 << 30), 2389f48ad614SDennis Dalessandro CS_PORT_XMIT_PKTS = (1 << 29), 2390f48ad614SDennis Dalessandro CS_PORT_RCV_PKTS = (1 << 28), 2391f48ad614SDennis Dalessandro CS_PORT_MCAST_XMIT_PKTS = (1 << 27), 2392f48ad614SDennis Dalessandro CS_PORT_MCAST_RCV_PKTS = (1 << 26), 2393f48ad614SDennis Dalessandro CS_PORT_XMIT_WAIT = (1 << 25), 2394f48ad614SDennis Dalessandro CS_SW_PORT_CONGESTION = (1 << 24), 2395f48ad614SDennis Dalessandro CS_PORT_RCV_FECN = (1 << 23), 2396f48ad614SDennis Dalessandro CS_PORT_RCV_BECN = (1 << 22), 2397f48ad614SDennis Dalessandro CS_PORT_XMIT_TIME_CONG = (1 << 21), 2398f48ad614SDennis Dalessandro CS_PORT_XMIT_WASTED_BW = (1 << 20), 2399f48ad614SDennis Dalessandro CS_PORT_XMIT_WAIT_DATA = (1 << 19), 2400f48ad614SDennis Dalessandro CS_PORT_RCV_BUBBLE = (1 << 18), 2401f48ad614SDennis Dalessandro CS_PORT_MARK_FECN = (1 << 17), 2402f48ad614SDennis Dalessandro CS_PORT_RCV_CONSTRAINT_ERRORS = (1 << 16), 2403f48ad614SDennis Dalessandro CS_PORT_RCV_SWITCH_RELAY_ERRORS = (1 << 15), 2404f48ad614SDennis Dalessandro CS_PORT_XMIT_DISCARDS = (1 << 14), 2405f48ad614SDennis Dalessandro CS_PORT_XMIT_CONSTRAINT_ERRORS = (1 << 13), 2406f48ad614SDennis Dalessandro CS_PORT_RCV_REMOTE_PHYSICAL_ERRORS = (1 << 12), 2407f48ad614SDennis Dalessandro CS_LOCAL_LINK_INTEGRITY_ERRORS = (1 << 11), 2408f48ad614SDennis Dalessandro CS_PORT_RCV_ERRORS = (1 << 10), 2409f48ad614SDennis Dalessandro CS_EXCESSIVE_BUFFER_OVERRUNS = (1 << 9), 2410f48ad614SDennis Dalessandro CS_FM_CONFIG_ERRORS = (1 << 8), 2411f48ad614SDennis Dalessandro CS_LINK_ERROR_RECOVERY = (1 << 7), 2412f48ad614SDennis Dalessandro CS_LINK_DOWNED = (1 << 6), 2413f48ad614SDennis Dalessandro CS_UNCORRECTABLE_ERRORS = (1 << 5), 2414f48ad614SDennis Dalessandro }; 2415f48ad614SDennis Dalessandro 2416f48ad614SDennis Dalessandro struct opa_clear_port_status { 2417f48ad614SDennis Dalessandro __be64 port_select_mask[4]; 2418f48ad614SDennis Dalessandro __be32 counter_select_mask; 2419f48ad614SDennis Dalessandro }; 2420f48ad614SDennis Dalessandro 2421f48ad614SDennis Dalessandro struct opa_aggregate { 2422f48ad614SDennis Dalessandro __be16 attr_id; 2423f48ad614SDennis Dalessandro __be16 err_reqlength; /* 1 bit, 8 res, 7 bit */ 2424f48ad614SDennis Dalessandro __be32 attr_mod; 24255b361328SGustavo A. R. Silva u8 data[]; 2426f48ad614SDennis Dalessandro }; 2427f48ad614SDennis Dalessandro 2428f48ad614SDennis Dalessandro #define MSK_LLI 0x000000f0 2429f48ad614SDennis Dalessandro #define MSK_LLI_SFT 4 2430f48ad614SDennis Dalessandro #define MSK_LER 0x0000000f 2431f48ad614SDennis Dalessandro #define MSK_LER_SFT 0 2432f48ad614SDennis Dalessandro #define ADD_LLI 8 2433f48ad614SDennis Dalessandro #define ADD_LER 2 2434f48ad614SDennis Dalessandro 2435f48ad614SDennis Dalessandro /* Request contains first three fields, response contains those plus the rest */ 2436f48ad614SDennis Dalessandro struct opa_port_data_counters_msg { 2437f48ad614SDennis Dalessandro __be64 port_select_mask[4]; 2438f48ad614SDennis Dalessandro __be32 vl_select_mask; 2439f48ad614SDennis Dalessandro __be32 resolution; 2440f48ad614SDennis Dalessandro 2441f48ad614SDennis Dalessandro /* Response fields follow */ 2442f48ad614SDennis Dalessandro struct _port_dctrs { 2443f48ad614SDennis Dalessandro u8 port_number; 2444f48ad614SDennis Dalessandro u8 reserved2[3]; 2445f48ad614SDennis Dalessandro __be32 link_quality_indicator; /* 29res, 3bit */ 2446f48ad614SDennis Dalessandro 2447f48ad614SDennis Dalessandro /* Data counters */ 2448f48ad614SDennis Dalessandro __be64 port_xmit_data; 2449f48ad614SDennis Dalessandro __be64 port_rcv_data; 2450f48ad614SDennis Dalessandro __be64 port_xmit_pkts; 2451f48ad614SDennis Dalessandro __be64 port_rcv_pkts; 2452f48ad614SDennis Dalessandro __be64 port_multicast_xmit_pkts; 2453f48ad614SDennis Dalessandro __be64 port_multicast_rcv_pkts; 2454f48ad614SDennis Dalessandro __be64 port_xmit_wait; 2455f48ad614SDennis Dalessandro __be64 sw_port_congestion; 2456f48ad614SDennis Dalessandro __be64 port_rcv_fecn; 2457f48ad614SDennis Dalessandro __be64 port_rcv_becn; 2458f48ad614SDennis Dalessandro __be64 port_xmit_time_cong; 2459f48ad614SDennis Dalessandro __be64 port_xmit_wasted_bw; 2460f48ad614SDennis Dalessandro __be64 port_xmit_wait_data; 2461f48ad614SDennis Dalessandro __be64 port_rcv_bubble; 2462f48ad614SDennis Dalessandro __be64 port_mark_fecn; 2463f48ad614SDennis Dalessandro 2464f48ad614SDennis Dalessandro __be64 port_error_counter_summary; 2465f48ad614SDennis Dalessandro /* Sum of error counts/port */ 2466f48ad614SDennis Dalessandro 2467f48ad614SDennis Dalessandro struct _vls_dctrs { 2468f48ad614SDennis Dalessandro /* per-VL Data counters */ 2469f48ad614SDennis Dalessandro __be64 port_vl_xmit_data; 2470f48ad614SDennis Dalessandro __be64 port_vl_rcv_data; 2471f48ad614SDennis Dalessandro __be64 port_vl_xmit_pkts; 2472f48ad614SDennis Dalessandro __be64 port_vl_rcv_pkts; 2473f48ad614SDennis Dalessandro __be64 port_vl_xmit_wait; 2474f48ad614SDennis Dalessandro __be64 sw_port_vl_congestion; 2475f48ad614SDennis Dalessandro __be64 port_vl_rcv_fecn; 2476f48ad614SDennis Dalessandro __be64 port_vl_rcv_becn; 2477f48ad614SDennis Dalessandro __be64 port_xmit_time_cong; 2478f48ad614SDennis Dalessandro __be64 port_vl_xmit_wasted_bw; 2479f48ad614SDennis Dalessandro __be64 port_vl_xmit_wait_data; 2480f48ad614SDennis Dalessandro __be64 port_vl_rcv_bubble; 2481f48ad614SDennis Dalessandro __be64 port_vl_mark_fecn; 2482f48ad614SDennis Dalessandro } vls[0]; 2483f48ad614SDennis Dalessandro /* array size defined by #bits set in vl_select_mask*/ 2484f48ad614SDennis Dalessandro } port[1]; /* array size defined by #ports in attribute modifier */ 2485f48ad614SDennis Dalessandro }; 2486f48ad614SDennis Dalessandro 2487f48ad614SDennis Dalessandro struct opa_port_error_counters64_msg { 2488f48ad614SDennis Dalessandro /* 2489f48ad614SDennis Dalessandro * Request contains first two fields, response contains the 2490f48ad614SDennis Dalessandro * whole magilla 2491f48ad614SDennis Dalessandro */ 2492f48ad614SDennis Dalessandro __be64 port_select_mask[4]; 2493f48ad614SDennis Dalessandro __be32 vl_select_mask; 2494f48ad614SDennis Dalessandro 2495f48ad614SDennis Dalessandro /* Response-only fields follow */ 2496f48ad614SDennis Dalessandro __be32 reserved1; 2497f48ad614SDennis Dalessandro struct _port_ectrs { 2498f48ad614SDennis Dalessandro u8 port_number; 2499f48ad614SDennis Dalessandro u8 reserved2[7]; 2500f48ad614SDennis Dalessandro __be64 port_rcv_constraint_errors; 2501f48ad614SDennis Dalessandro __be64 port_rcv_switch_relay_errors; 2502f48ad614SDennis Dalessandro __be64 port_xmit_discards; 2503f48ad614SDennis Dalessandro __be64 port_xmit_constraint_errors; 2504f48ad614SDennis Dalessandro __be64 port_rcv_remote_physical_errors; 2505f48ad614SDennis Dalessandro __be64 local_link_integrity_errors; 2506f48ad614SDennis Dalessandro __be64 port_rcv_errors; 2507f48ad614SDennis Dalessandro __be64 excessive_buffer_overruns; 2508f48ad614SDennis Dalessandro __be64 fm_config_errors; 2509f48ad614SDennis Dalessandro __be32 link_error_recovery; 2510f48ad614SDennis Dalessandro __be32 link_downed; 2511f48ad614SDennis Dalessandro u8 uncorrectable_errors; 2512f48ad614SDennis Dalessandro u8 reserved3[7]; 2513f48ad614SDennis Dalessandro struct _vls_ectrs { 2514f48ad614SDennis Dalessandro __be64 port_vl_xmit_discards; 2515f48ad614SDennis Dalessandro } vls[0]; 2516f48ad614SDennis Dalessandro /* array size defined by #bits set in vl_select_mask */ 2517f48ad614SDennis Dalessandro } port[1]; /* array size defined by #ports in attribute modifier */ 2518f48ad614SDennis Dalessandro }; 2519f48ad614SDennis Dalessandro 2520f48ad614SDennis Dalessandro struct opa_port_error_info_msg { 2521f48ad614SDennis Dalessandro __be64 port_select_mask[4]; 2522f48ad614SDennis Dalessandro __be32 error_info_select_mask; 2523f48ad614SDennis Dalessandro __be32 reserved1; 2524f48ad614SDennis Dalessandro struct _port_ei { 2525f48ad614SDennis Dalessandro u8 port_number; 2526f48ad614SDennis Dalessandro u8 reserved2[7]; 2527f48ad614SDennis Dalessandro 2528f48ad614SDennis Dalessandro /* PortRcvErrorInfo */ 2529f48ad614SDennis Dalessandro struct { 2530f48ad614SDennis Dalessandro u8 status_and_code; 2531f48ad614SDennis Dalessandro union { 2532f48ad614SDennis Dalessandro u8 raw[17]; 2533f48ad614SDennis Dalessandro struct { 2534f48ad614SDennis Dalessandro /* EI1to12 format */ 2535f48ad614SDennis Dalessandro u8 packet_flit1[8]; 2536f48ad614SDennis Dalessandro u8 packet_flit2[8]; 2537f48ad614SDennis Dalessandro u8 remaining_flit_bits12; 2538f48ad614SDennis Dalessandro } ei1to12; 2539f48ad614SDennis Dalessandro struct { 2540f48ad614SDennis Dalessandro u8 packet_bytes[8]; 2541f48ad614SDennis Dalessandro u8 remaining_flit_bits; 2542f48ad614SDennis Dalessandro } ei13; 2543f48ad614SDennis Dalessandro } ei; 2544f48ad614SDennis Dalessandro u8 reserved3[6]; 2545f48ad614SDennis Dalessandro } __packed port_rcv_ei; 2546f48ad614SDennis Dalessandro 2547f48ad614SDennis Dalessandro /* ExcessiveBufferOverrunInfo */ 2548f48ad614SDennis Dalessandro struct { 2549f48ad614SDennis Dalessandro u8 status_and_sc; 2550f48ad614SDennis Dalessandro u8 reserved4[7]; 2551f48ad614SDennis Dalessandro } __packed excessive_buffer_overrun_ei; 2552f48ad614SDennis Dalessandro 2553f48ad614SDennis Dalessandro /* PortXmitConstraintErrorInfo */ 2554f48ad614SDennis Dalessandro struct { 2555f48ad614SDennis Dalessandro u8 status; 2556f48ad614SDennis Dalessandro u8 reserved5; 2557f48ad614SDennis Dalessandro __be16 pkey; 2558f48ad614SDennis Dalessandro __be32 slid; 2559f48ad614SDennis Dalessandro } __packed port_xmit_constraint_ei; 2560f48ad614SDennis Dalessandro 2561f48ad614SDennis Dalessandro /* PortRcvConstraintErrorInfo */ 2562f48ad614SDennis Dalessandro struct { 2563f48ad614SDennis Dalessandro u8 status; 2564f48ad614SDennis Dalessandro u8 reserved6; 2565f48ad614SDennis Dalessandro __be16 pkey; 2566f48ad614SDennis Dalessandro __be32 slid; 2567f48ad614SDennis Dalessandro } __packed port_rcv_constraint_ei; 2568f48ad614SDennis Dalessandro 2569f48ad614SDennis Dalessandro /* PortRcvSwitchRelayErrorInfo */ 2570f48ad614SDennis Dalessandro struct { 2571f48ad614SDennis Dalessandro u8 status_and_code; 2572f48ad614SDennis Dalessandro u8 reserved7[3]; 2573f48ad614SDennis Dalessandro __u32 error_info; 2574f48ad614SDennis Dalessandro } __packed port_rcv_switch_relay_ei; 2575f48ad614SDennis Dalessandro 2576f48ad614SDennis Dalessandro /* UncorrectableErrorInfo */ 2577f48ad614SDennis Dalessandro struct { 2578f48ad614SDennis Dalessandro u8 status_and_code; 2579f48ad614SDennis Dalessandro u8 reserved8; 2580f48ad614SDennis Dalessandro } __packed uncorrectable_ei; 2581f48ad614SDennis Dalessandro 2582f48ad614SDennis Dalessandro /* FMConfigErrorInfo */ 2583f48ad614SDennis Dalessandro struct { 2584f48ad614SDennis Dalessandro u8 status_and_code; 2585f48ad614SDennis Dalessandro u8 error_info; 2586f48ad614SDennis Dalessandro } __packed fm_config_ei; 2587f48ad614SDennis Dalessandro __u32 reserved9; 2588f48ad614SDennis Dalessandro } port[1]; /* actual array size defined by #ports in attr modifier */ 2589f48ad614SDennis Dalessandro }; 2590f48ad614SDennis Dalessandro 2591f48ad614SDennis Dalessandro /* opa_port_error_info_msg error_info_select_mask bit definitions */ 2592f48ad614SDennis Dalessandro enum error_info_selects { 2593f48ad614SDennis Dalessandro ES_PORT_RCV_ERROR_INFO = (1 << 31), 2594f48ad614SDennis Dalessandro ES_EXCESSIVE_BUFFER_OVERRUN_INFO = (1 << 30), 2595f48ad614SDennis Dalessandro ES_PORT_XMIT_CONSTRAINT_ERROR_INFO = (1 << 29), 2596f48ad614SDennis Dalessandro ES_PORT_RCV_CONSTRAINT_ERROR_INFO = (1 << 28), 2597f48ad614SDennis Dalessandro ES_PORT_RCV_SWITCH_RELAY_ERROR_INFO = (1 << 27), 2598f48ad614SDennis Dalessandro ES_UNCORRECTABLE_ERROR_INFO = (1 << 26), 2599f48ad614SDennis Dalessandro ES_FM_CONFIG_ERROR_INFO = (1 << 25) 2600f48ad614SDennis Dalessandro }; 2601f48ad614SDennis Dalessandro 2602f48ad614SDennis Dalessandro static int pma_get_opa_classportinfo(struct opa_pma_mad *pmp, 2603f48ad614SDennis Dalessandro struct ib_device *ibdev, u32 *resp_len) 2604f48ad614SDennis Dalessandro { 2605f48ad614SDennis Dalessandro struct opa_class_port_info *p = 2606f48ad614SDennis Dalessandro (struct opa_class_port_info *)pmp->data; 2607f48ad614SDennis Dalessandro 2608f48ad614SDennis Dalessandro memset(pmp->data, 0, sizeof(pmp->data)); 2609f48ad614SDennis Dalessandro 2610f48ad614SDennis Dalessandro if (pmp->mad_hdr.attr_mod != 0) 2611f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2612f48ad614SDennis Dalessandro 2613f48ad614SDennis Dalessandro p->base_version = OPA_MGMT_BASE_VERSION; 26149fa240bbSHal Rosenstock p->class_version = OPA_SM_CLASS_VERSION; 2615f48ad614SDennis Dalessandro /* 2616f48ad614SDennis Dalessandro * Expected response time is 4.096 usec. * 2^18 == 1.073741824 sec. 2617f48ad614SDennis Dalessandro */ 2618f48ad614SDennis Dalessandro p->cap_mask2_resp_time = cpu_to_be32(18); 2619f48ad614SDennis Dalessandro 2620f48ad614SDennis Dalessandro if (resp_len) 2621f48ad614SDennis Dalessandro *resp_len += sizeof(*p); 2622f48ad614SDennis Dalessandro 2623f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2624f48ad614SDennis Dalessandro } 2625f48ad614SDennis Dalessandro 2626f48ad614SDennis Dalessandro static void a0_portstatus(struct hfi1_pportdata *ppd, 2627f8659d68SIra Weiny struct opa_port_status_rsp *rsp) 2628f48ad614SDennis Dalessandro { 2629f48ad614SDennis Dalessandro if (!is_bx(ppd->dd)) { 2630f48ad614SDennis Dalessandro unsigned long vl; 2631f48ad614SDennis Dalessandro u64 sum_vl_xmit_wait = 0; 2632f8659d68SIra Weiny unsigned long vl_all_mask = VL_MASK_ALL; 2633f48ad614SDennis Dalessandro 2634f8659d68SIra Weiny for_each_set_bit(vl, &vl_all_mask, BITS_PER_LONG) { 2635f48ad614SDennis Dalessandro u64 tmp = sum_vl_xmit_wait + 2636f48ad614SDennis Dalessandro read_port_cntr(ppd, C_TX_WAIT_VL, 2637f48ad614SDennis Dalessandro idx_from_vl(vl)); 2638f48ad614SDennis Dalessandro if (tmp < sum_vl_xmit_wait) { 2639f48ad614SDennis Dalessandro /* we wrapped */ 2640f48ad614SDennis Dalessandro sum_vl_xmit_wait = (u64)~0; 2641f48ad614SDennis Dalessandro break; 2642f48ad614SDennis Dalessandro } 2643f48ad614SDennis Dalessandro sum_vl_xmit_wait = tmp; 2644f48ad614SDennis Dalessandro } 2645f48ad614SDennis Dalessandro if (be64_to_cpu(rsp->port_xmit_wait) > sum_vl_xmit_wait) 2646f48ad614SDennis Dalessandro rsp->port_xmit_wait = cpu_to_be64(sum_vl_xmit_wait); 2647f48ad614SDennis Dalessandro } 2648f48ad614SDennis Dalessandro } 2649f48ad614SDennis Dalessandro 265007190076SKamenee Arumugam /** 265107190076SKamenee Arumugam * tx_link_width - convert link width bitmask to integer 265207190076SKamenee Arumugam * value representing actual link width. 265307190076SKamenee Arumugam * @link_width: width of active link 265407190076SKamenee Arumugam * @return: return index of the bit set in link_width var 265507190076SKamenee Arumugam * 265607190076SKamenee Arumugam * The function convert and return the index of bit set 265707190076SKamenee Arumugam * that indicate the current link width. 265807190076SKamenee Arumugam */ 265907190076SKamenee Arumugam u16 tx_link_width(u16 link_width) 266007190076SKamenee Arumugam { 266107190076SKamenee Arumugam int n = LINK_WIDTH_DEFAULT; 266207190076SKamenee Arumugam u16 tx_width = n; 266307190076SKamenee Arumugam 266407190076SKamenee Arumugam while (link_width && n) { 266507190076SKamenee Arumugam if (link_width & (1 << (n - 1))) { 266607190076SKamenee Arumugam tx_width = n; 266707190076SKamenee Arumugam break; 266807190076SKamenee Arumugam } 266907190076SKamenee Arumugam n--; 267007190076SKamenee Arumugam } 267107190076SKamenee Arumugam 267207190076SKamenee Arumugam return tx_width; 267307190076SKamenee Arumugam } 267407190076SKamenee Arumugam 267507190076SKamenee Arumugam /** 267607190076SKamenee Arumugam * get_xmit_wait_counters - Convert HFI 's SendWaitCnt/SendWaitVlCnt 267707190076SKamenee Arumugam * counter in unit of TXE cycle times to flit times. 267807190076SKamenee Arumugam * @ppd: info of physical Hfi port 267907190076SKamenee Arumugam * @link_width: width of active link 268007190076SKamenee Arumugam * @link_speed: speed of active link 268107190076SKamenee Arumugam * @vl: represent VL0-VL7, VL15 for PortVLXmitWait counters request 268207190076SKamenee Arumugam * and if vl value is C_VL_COUNT, it represent SendWaitCnt 268307190076SKamenee Arumugam * counter request 268407190076SKamenee Arumugam * @return: return SendWaitCnt/SendWaitVlCnt counter value per vl. 268507190076SKamenee Arumugam * 268607190076SKamenee Arumugam * Convert SendWaitCnt/SendWaitVlCnt counter from TXE cycle times to 268707190076SKamenee Arumugam * flit times. Call this function to samples these counters. This 268807190076SKamenee Arumugam * function will calculate for previous state transition and update 268907190076SKamenee Arumugam * current state at end of function using ppd->prev_link_width and 269007190076SKamenee Arumugam * ppd->port_vl_xmit_wait_last to port_vl_xmit_wait_curr and link_width. 269107190076SKamenee Arumugam */ 269207190076SKamenee Arumugam u64 get_xmit_wait_counters(struct hfi1_pportdata *ppd, 269307190076SKamenee Arumugam u16 link_width, u16 link_speed, int vl) 269407190076SKamenee Arumugam { 269507190076SKamenee Arumugam u64 port_vl_xmit_wait_curr; 269607190076SKamenee Arumugam u64 delta_vl_xmit_wait; 269707190076SKamenee Arumugam u64 xmit_wait_val; 269807190076SKamenee Arumugam 269907190076SKamenee Arumugam if (vl > C_VL_COUNT) 270007190076SKamenee Arumugam return 0; 270107190076SKamenee Arumugam if (vl < C_VL_COUNT) 270207190076SKamenee Arumugam port_vl_xmit_wait_curr = 270307190076SKamenee Arumugam read_port_cntr(ppd, C_TX_WAIT_VL, vl); 270407190076SKamenee Arumugam else 270507190076SKamenee Arumugam port_vl_xmit_wait_curr = 270607190076SKamenee Arumugam read_port_cntr(ppd, C_TX_WAIT, CNTR_INVALID_VL); 270707190076SKamenee Arumugam 270807190076SKamenee Arumugam xmit_wait_val = 270907190076SKamenee Arumugam port_vl_xmit_wait_curr - 271007190076SKamenee Arumugam ppd->port_vl_xmit_wait_last[vl]; 271107190076SKamenee Arumugam delta_vl_xmit_wait = 271207190076SKamenee Arumugam convert_xmit_counter(xmit_wait_val, 271307190076SKamenee Arumugam ppd->prev_link_width, 271407190076SKamenee Arumugam link_speed); 271507190076SKamenee Arumugam 271607190076SKamenee Arumugam ppd->vl_xmit_flit_cnt[vl] += delta_vl_xmit_wait; 271707190076SKamenee Arumugam ppd->port_vl_xmit_wait_last[vl] = port_vl_xmit_wait_curr; 271807190076SKamenee Arumugam ppd->prev_link_width = link_width; 271907190076SKamenee Arumugam 272007190076SKamenee Arumugam return ppd->vl_xmit_flit_cnt[vl]; 272107190076SKamenee Arumugam } 272207190076SKamenee Arumugam 2723f48ad614SDennis Dalessandro static int pma_get_opa_portstatus(struct opa_pma_mad *pmp, 2724f48ad614SDennis Dalessandro struct ib_device *ibdev, 2725f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 2726f48ad614SDennis Dalessandro { 2727f48ad614SDennis Dalessandro struct opa_port_status_req *req = 2728f48ad614SDennis Dalessandro (struct opa_port_status_req *)pmp->data; 2729f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2730f48ad614SDennis Dalessandro struct opa_port_status_rsp *rsp; 2731f8659d68SIra Weiny unsigned long vl_select_mask = be32_to_cpu(req->vl_select_mask); 2732f48ad614SDennis Dalessandro unsigned long vl; 2733f48ad614SDennis Dalessandro size_t response_data_size; 2734f48ad614SDennis Dalessandro u32 nports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; 2735f48ad614SDennis Dalessandro u8 port_num = req->port_num; 2736f8659d68SIra Weiny u8 num_vls = hweight64(vl_select_mask); 2737f48ad614SDennis Dalessandro struct _vls_pctrs *vlinfo; 2738f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 2739f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 2740f48ad614SDennis Dalessandro int vfi; 2741f48ad614SDennis Dalessandro u64 tmp, tmp2; 274207190076SKamenee Arumugam u16 link_width; 274307190076SKamenee Arumugam u16 link_speed; 2744f48ad614SDennis Dalessandro 27456fe1a9b9SGustavo A. R. Silva response_data_size = struct_size(rsp, vls, num_vls); 2746f48ad614SDennis Dalessandro if (response_data_size > sizeof(pmp->data)) { 2747f48ad614SDennis Dalessandro pmp->mad_hdr.status |= OPA_PM_STATUS_REQUEST_TOO_LARGE; 2748f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2749f48ad614SDennis Dalessandro } 2750f48ad614SDennis Dalessandro 2751f48ad614SDennis Dalessandro if (nports != 1 || (port_num && port_num != port) || 2752f48ad614SDennis Dalessandro num_vls > OPA_MAX_VLS || (vl_select_mask & ~VL_MASK_ALL)) { 2753f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 2754f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2755f48ad614SDennis Dalessandro } 2756f48ad614SDennis Dalessandro 2757f48ad614SDennis Dalessandro memset(pmp->data, 0, sizeof(pmp->data)); 2758f48ad614SDennis Dalessandro 2759f48ad614SDennis Dalessandro rsp = (struct opa_port_status_rsp *)pmp->data; 2760f48ad614SDennis Dalessandro if (port_num) 2761f48ad614SDennis Dalessandro rsp->port_num = port_num; 2762f48ad614SDennis Dalessandro else 2763f48ad614SDennis Dalessandro rsp->port_num = port; 2764f48ad614SDennis Dalessandro 2765f48ad614SDennis Dalessandro rsp->port_rcv_constraint_errors = 2766f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, 2767f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2768f48ad614SDennis Dalessandro 2769f48ad614SDennis Dalessandro hfi1_read_link_quality(dd, &rsp->link_quality_indicator); 2770f48ad614SDennis Dalessandro 2771f8659d68SIra Weiny rsp->vl_select_mask = cpu_to_be32((u32)vl_select_mask); 2772f48ad614SDennis Dalessandro rsp->port_xmit_data = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_FLITS, 2773f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2774f48ad614SDennis Dalessandro rsp->port_rcv_data = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FLITS, 2775f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2776f48ad614SDennis Dalessandro rsp->port_xmit_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_PKTS, 2777f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2778f48ad614SDennis Dalessandro rsp->port_rcv_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_PKTS, 2779f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2780f48ad614SDennis Dalessandro rsp->port_multicast_xmit_pkts = 2781f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_MC_XMIT_PKTS, 2782f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2783f48ad614SDennis Dalessandro rsp->port_multicast_rcv_pkts = 2784f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_MC_RCV_PKTS, 2785f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 278607190076SKamenee Arumugam /* 278707190076SKamenee Arumugam * Convert PortXmitWait counter from TXE cycle times 278807190076SKamenee Arumugam * to flit times. 278907190076SKamenee Arumugam */ 279007190076SKamenee Arumugam link_width = 279107190076SKamenee Arumugam tx_link_width(ppd->link_width_downgrade_tx_active); 279207190076SKamenee Arumugam link_speed = get_link_speed(ppd->link_speed_active); 2793f48ad614SDennis Dalessandro rsp->port_xmit_wait = 279407190076SKamenee Arumugam cpu_to_be64(get_xmit_wait_counters(ppd, link_width, 279507190076SKamenee Arumugam link_speed, C_VL_COUNT)); 2796f48ad614SDennis Dalessandro rsp->port_rcv_fecn = 2797f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN, CNTR_INVALID_VL)); 2798f48ad614SDennis Dalessandro rsp->port_rcv_becn = 2799f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL)); 2800f48ad614SDennis Dalessandro rsp->port_xmit_discards = 2801f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD, 2802f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2803f48ad614SDennis Dalessandro rsp->port_xmit_constraint_errors = 2804f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, 2805f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2806f48ad614SDennis Dalessandro rsp->port_rcv_remote_physical_errors = 2807f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR, 2808f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 28093210314aSJakub Pawlak rsp->local_link_integrity_errors = 28103210314aSJakub Pawlak cpu_to_be64(read_dev_cntr(dd, C_DC_RX_REPLAY, 28113210314aSJakub Pawlak CNTR_INVALID_VL)); 2812f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); 2813f48ad614SDennis Dalessandro tmp2 = tmp + read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, 2814f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2815f48ad614SDennis Dalessandro if (tmp2 > (u32)UINT_MAX || tmp2 < tmp) { 2816f48ad614SDennis Dalessandro /* overflow/wrapped */ 2817f48ad614SDennis Dalessandro rsp->link_error_recovery = cpu_to_be32(~0); 2818f48ad614SDennis Dalessandro } else { 2819f48ad614SDennis Dalessandro rsp->link_error_recovery = cpu_to_be32(tmp2); 2820f48ad614SDennis Dalessandro } 2821f48ad614SDennis Dalessandro rsp->port_rcv_errors = 2822f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL)); 2823f48ad614SDennis Dalessandro rsp->excessive_buffer_overruns = 2824f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL)); 2825f48ad614SDennis Dalessandro rsp->fm_config_errors = 2826f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_FM_CFG_ERR, 2827f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2828f48ad614SDennis Dalessandro rsp->link_downed = cpu_to_be32(read_port_cntr(ppd, C_SW_LINK_DOWN, 2829f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2830f48ad614SDennis Dalessandro 2831f48ad614SDennis Dalessandro /* rsp->uncorrectable_errors is 8 bits wide, and it pegs at 0xff */ 2832f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); 2833f48ad614SDennis Dalessandro rsp->uncorrectable_errors = tmp < 0x100 ? (tmp & 0xff) : 0xff; 2834f48ad614SDennis Dalessandro 2835f48ad614SDennis Dalessandro vlinfo = &rsp->vls[0]; 2836f48ad614SDennis Dalessandro vfi = 0; 2837f48ad614SDennis Dalessandro /* The vl_select_mask has been checked above, and we know 2838f48ad614SDennis Dalessandro * that it contains only entries which represent valid VLs. 2839f48ad614SDennis Dalessandro * So in the for_each_set_bit() loop below, we don't need 2840f48ad614SDennis Dalessandro * any additional checks for vl. 2841f48ad614SDennis Dalessandro */ 2842f8659d68SIra Weiny for_each_set_bit(vl, &vl_select_mask, BITS_PER_LONG) { 2843f48ad614SDennis Dalessandro memset(vlinfo, 0, sizeof(*vlinfo)); 2844f48ad614SDennis Dalessandro 2845f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_RX_FLIT_VL, idx_from_vl(vl)); 2846f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_data = cpu_to_be64(tmp); 2847f48ad614SDennis Dalessandro 2848f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_pkts = 2849f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RX_PKT_VL, 2850f48ad614SDennis Dalessandro idx_from_vl(vl))); 2851f48ad614SDennis Dalessandro 2852f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_data = 2853f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_FLIT_VL, 2854f48ad614SDennis Dalessandro idx_from_vl(vl))); 2855f48ad614SDennis Dalessandro 2856f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_pkts = 2857f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_PKT_VL, 2858f48ad614SDennis Dalessandro idx_from_vl(vl))); 285907190076SKamenee Arumugam /* 286007190076SKamenee Arumugam * Convert PortVlXmitWait counter from TXE cycle 286107190076SKamenee Arumugam * times to flit times. 286207190076SKamenee Arumugam */ 2863f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_wait = 286407190076SKamenee Arumugam cpu_to_be64(get_xmit_wait_counters(ppd, link_width, 286507190076SKamenee Arumugam link_speed, 2866f48ad614SDennis Dalessandro idx_from_vl(vl))); 2867f48ad614SDennis Dalessandro 2868f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_fecn = 2869f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN_VL, 2870f48ad614SDennis Dalessandro idx_from_vl(vl))); 2871f48ad614SDennis Dalessandro 2872f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_becn = 2873f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN_VL, 2874f48ad614SDennis Dalessandro idx_from_vl(vl))); 2875f48ad614SDennis Dalessandro 2876583eb8b8SJakub Pawlak rsp->vls[vfi].port_vl_xmit_discards = 2877583eb8b8SJakub Pawlak cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD_VL, 2878583eb8b8SJakub Pawlak idx_from_vl(vl))); 2879f48ad614SDennis Dalessandro vlinfo++; 2880f48ad614SDennis Dalessandro vfi++; 2881f48ad614SDennis Dalessandro } 2882f48ad614SDennis Dalessandro 2883f8659d68SIra Weiny a0_portstatus(ppd, rsp); 2884f48ad614SDennis Dalessandro 2885f48ad614SDennis Dalessandro if (resp_len) 2886f48ad614SDennis Dalessandro *resp_len += response_data_size; 2887f48ad614SDennis Dalessandro 2888f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 2889f48ad614SDennis Dalessandro } 2890f48ad614SDennis Dalessandro 2891f48ad614SDennis Dalessandro static u64 get_error_counter_summary(struct ib_device *ibdev, u8 port, 2892f48ad614SDennis Dalessandro u8 res_lli, u8 res_ler) 2893f48ad614SDennis Dalessandro { 2894f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2895f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 2896f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 2897f48ad614SDennis Dalessandro u64 error_counter_summary = 0, tmp; 2898f48ad614SDennis Dalessandro 2899f48ad614SDennis Dalessandro error_counter_summary += read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, 2900f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2901f48ad614SDennis Dalessandro /* port_rcv_switch_relay_errors is 0 for HFIs */ 2902f48ad614SDennis Dalessandro error_counter_summary += read_port_cntr(ppd, C_SW_XMIT_DSCD, 2903f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2904f48ad614SDennis Dalessandro error_counter_summary += read_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, 2905f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2906f48ad614SDennis Dalessandro error_counter_summary += read_dev_cntr(dd, C_DC_RMT_PHY_ERR, 2907f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2908f48ad614SDennis Dalessandro /* local link integrity must be right-shifted by the lli resolution */ 29093210314aSJakub Pawlak error_counter_summary += (read_dev_cntr(dd, C_DC_RX_REPLAY, 29103210314aSJakub Pawlak CNTR_INVALID_VL) >> res_lli); 2911f48ad614SDennis Dalessandro /* link error recovery must b right-shifted by the ler resolution */ 2912f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); 2913f48ad614SDennis Dalessandro tmp += read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL); 2914f48ad614SDennis Dalessandro error_counter_summary += (tmp >> res_ler); 2915f48ad614SDennis Dalessandro error_counter_summary += read_dev_cntr(dd, C_DC_RCV_ERR, 2916f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2917f48ad614SDennis Dalessandro error_counter_summary += read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL); 2918f48ad614SDennis Dalessandro error_counter_summary += read_dev_cntr(dd, C_DC_FM_CFG_ERR, 2919f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2920f48ad614SDennis Dalessandro /* ppd->link_downed is a 32-bit value */ 2921f48ad614SDennis Dalessandro error_counter_summary += read_port_cntr(ppd, C_SW_LINK_DOWN, 2922f48ad614SDennis Dalessandro CNTR_INVALID_VL); 2923f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); 2924f48ad614SDennis Dalessandro /* this is an 8-bit quantity */ 2925f48ad614SDennis Dalessandro error_counter_summary += tmp < 0x100 ? (tmp & 0xff) : 0xff; 2926f48ad614SDennis Dalessandro 2927f48ad614SDennis Dalessandro return error_counter_summary; 2928f48ad614SDennis Dalessandro } 2929f48ad614SDennis Dalessandro 2930f8659d68SIra Weiny static void a0_datacounters(struct hfi1_pportdata *ppd, struct _port_dctrs *rsp) 2931f48ad614SDennis Dalessandro { 2932f48ad614SDennis Dalessandro if (!is_bx(ppd->dd)) { 2933f48ad614SDennis Dalessandro unsigned long vl; 2934f48ad614SDennis Dalessandro u64 sum_vl_xmit_wait = 0; 2935f8659d68SIra Weiny unsigned long vl_all_mask = VL_MASK_ALL; 2936f48ad614SDennis Dalessandro 2937f8659d68SIra Weiny for_each_set_bit(vl, &vl_all_mask, BITS_PER_LONG) { 2938f48ad614SDennis Dalessandro u64 tmp = sum_vl_xmit_wait + 2939f48ad614SDennis Dalessandro read_port_cntr(ppd, C_TX_WAIT_VL, 2940f48ad614SDennis Dalessandro idx_from_vl(vl)); 2941f48ad614SDennis Dalessandro if (tmp < sum_vl_xmit_wait) { 2942f48ad614SDennis Dalessandro /* we wrapped */ 2943f48ad614SDennis Dalessandro sum_vl_xmit_wait = (u64)~0; 2944f48ad614SDennis Dalessandro break; 2945f48ad614SDennis Dalessandro } 2946f48ad614SDennis Dalessandro sum_vl_xmit_wait = tmp; 2947f48ad614SDennis Dalessandro } 2948f48ad614SDennis Dalessandro if (be64_to_cpu(rsp->port_xmit_wait) > sum_vl_xmit_wait) 2949f48ad614SDennis Dalessandro rsp->port_xmit_wait = cpu_to_be64(sum_vl_xmit_wait); 2950f48ad614SDennis Dalessandro } 2951f48ad614SDennis Dalessandro } 2952f48ad614SDennis Dalessandro 2953f48ad614SDennis Dalessandro static void pma_get_opa_port_dctrs(struct ib_device *ibdev, 2954f48ad614SDennis Dalessandro struct _port_dctrs *rsp) 2955f48ad614SDennis Dalessandro { 2956f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2957f48ad614SDennis Dalessandro 2958f48ad614SDennis Dalessandro rsp->port_xmit_data = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_FLITS, 2959f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2960f48ad614SDennis Dalessandro rsp->port_rcv_data = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FLITS, 2961f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2962f48ad614SDennis Dalessandro rsp->port_xmit_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_PKTS, 2963f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2964f48ad614SDennis Dalessandro rsp->port_rcv_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_PKTS, 2965f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2966f48ad614SDennis Dalessandro rsp->port_multicast_xmit_pkts = 2967f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_MC_XMIT_PKTS, 2968f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2969f48ad614SDennis Dalessandro rsp->port_multicast_rcv_pkts = 2970f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_MC_RCV_PKTS, 2971f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 2972f48ad614SDennis Dalessandro } 2973f48ad614SDennis Dalessandro 2974f48ad614SDennis Dalessandro static int pma_get_opa_datacounters(struct opa_pma_mad *pmp, 2975f48ad614SDennis Dalessandro struct ib_device *ibdev, 2976f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 2977f48ad614SDennis Dalessandro { 2978f48ad614SDennis Dalessandro struct opa_port_data_counters_msg *req = 2979f48ad614SDennis Dalessandro (struct opa_port_data_counters_msg *)pmp->data; 2980f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 2981f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 2982f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 2983f48ad614SDennis Dalessandro struct _port_dctrs *rsp; 2984f48ad614SDennis Dalessandro struct _vls_dctrs *vlinfo; 2985f48ad614SDennis Dalessandro size_t response_data_size; 2986f48ad614SDennis Dalessandro u32 num_ports; 2987f48ad614SDennis Dalessandro u8 lq, num_vls; 2988f48ad614SDennis Dalessandro u8 res_lli, res_ler; 2989f48ad614SDennis Dalessandro u64 port_mask; 299061a28d2bSChristophe Jaillet u8 port_num; 2991f48ad614SDennis Dalessandro unsigned long vl; 2992f8659d68SIra Weiny unsigned long vl_select_mask; 2993f48ad614SDennis Dalessandro int vfi; 299407190076SKamenee Arumugam u16 link_width; 299507190076SKamenee Arumugam u16 link_speed; 2996f48ad614SDennis Dalessandro 2997f48ad614SDennis Dalessandro num_ports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; 2998f48ad614SDennis Dalessandro num_vls = hweight32(be32_to_cpu(req->vl_select_mask)); 2999f48ad614SDennis Dalessandro vl_select_mask = be32_to_cpu(req->vl_select_mask); 3000f48ad614SDennis Dalessandro res_lli = (u8)(be32_to_cpu(req->resolution) & MSK_LLI) >> MSK_LLI_SFT; 3001f48ad614SDennis Dalessandro res_lli = res_lli ? res_lli + ADD_LLI : 0; 3002f48ad614SDennis Dalessandro res_ler = (u8)(be32_to_cpu(req->resolution) & MSK_LER) >> MSK_LER_SFT; 3003f48ad614SDennis Dalessandro res_ler = res_ler ? res_ler + ADD_LER : 0; 3004f48ad614SDennis Dalessandro 3005f48ad614SDennis Dalessandro if (num_ports != 1 || (vl_select_mask & ~VL_MASK_ALL)) { 3006f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3007f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3008f48ad614SDennis Dalessandro } 3009f48ad614SDennis Dalessandro 3010f48ad614SDennis Dalessandro /* Sanity check */ 30116fe1a9b9SGustavo A. R. Silva response_data_size = struct_size(req, port[0].vls, num_vls); 3012f48ad614SDennis Dalessandro 3013f48ad614SDennis Dalessandro if (response_data_size > sizeof(pmp->data)) { 3014f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3015f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3016f48ad614SDennis Dalessandro } 3017f48ad614SDennis Dalessandro 3018f48ad614SDennis Dalessandro /* 3019f48ad614SDennis Dalessandro * The bit set in the mask needs to be consistent with the 3020f48ad614SDennis Dalessandro * port the request came in on. 3021f48ad614SDennis Dalessandro */ 3022f48ad614SDennis Dalessandro port_mask = be64_to_cpu(req->port_select_mask[3]); 3023f48ad614SDennis Dalessandro port_num = find_first_bit((unsigned long *)&port_mask, 30246aaa382fSChristophe Jaillet sizeof(port_mask) * 8); 3025f48ad614SDennis Dalessandro 302661a28d2bSChristophe Jaillet if (port_num != port) { 3027f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3028f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3029f48ad614SDennis Dalessandro } 3030f48ad614SDennis Dalessandro 3031f48ad614SDennis Dalessandro rsp = &req->port[0]; 3032f48ad614SDennis Dalessandro memset(rsp, 0, sizeof(*rsp)); 3033f48ad614SDennis Dalessandro 3034f48ad614SDennis Dalessandro rsp->port_number = port; 3035f48ad614SDennis Dalessandro /* 3036f48ad614SDennis Dalessandro * Note that link_quality_indicator is a 32 bit quantity in 3037f48ad614SDennis Dalessandro * 'datacounters' queries (as opposed to 'portinfo' queries, 3038f48ad614SDennis Dalessandro * where it's a byte). 3039f48ad614SDennis Dalessandro */ 3040f48ad614SDennis Dalessandro hfi1_read_link_quality(dd, &lq); 3041f48ad614SDennis Dalessandro rsp->link_quality_indicator = cpu_to_be32((u32)lq); 3042f48ad614SDennis Dalessandro pma_get_opa_port_dctrs(ibdev, rsp); 3043f48ad614SDennis Dalessandro 304407190076SKamenee Arumugam /* 304507190076SKamenee Arumugam * Convert PortXmitWait counter from TXE 304607190076SKamenee Arumugam * cycle times to flit times. 304707190076SKamenee Arumugam */ 304807190076SKamenee Arumugam link_width = 304907190076SKamenee Arumugam tx_link_width(ppd->link_width_downgrade_tx_active); 305007190076SKamenee Arumugam link_speed = get_link_speed(ppd->link_speed_active); 3051f48ad614SDennis Dalessandro rsp->port_xmit_wait = 305207190076SKamenee Arumugam cpu_to_be64(get_xmit_wait_counters(ppd, link_width, 305307190076SKamenee Arumugam link_speed, C_VL_COUNT)); 3054f48ad614SDennis Dalessandro rsp->port_rcv_fecn = 3055f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN, CNTR_INVALID_VL)); 3056f48ad614SDennis Dalessandro rsp->port_rcv_becn = 3057f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL)); 3058f48ad614SDennis Dalessandro rsp->port_error_counter_summary = 3059f48ad614SDennis Dalessandro cpu_to_be64(get_error_counter_summary(ibdev, port, 3060f48ad614SDennis Dalessandro res_lli, res_ler)); 3061f48ad614SDennis Dalessandro 3062f48ad614SDennis Dalessandro vlinfo = &rsp->vls[0]; 3063f48ad614SDennis Dalessandro vfi = 0; 3064f48ad614SDennis Dalessandro /* The vl_select_mask has been checked above, and we know 3065f48ad614SDennis Dalessandro * that it contains only entries which represent valid VLs. 3066f48ad614SDennis Dalessandro * So in the for_each_set_bit() loop below, we don't need 3067f48ad614SDennis Dalessandro * any additional checks for vl. 3068f48ad614SDennis Dalessandro */ 3069f8659d68SIra Weiny for_each_set_bit(vl, &vl_select_mask, BITS_PER_LONG) { 3070f48ad614SDennis Dalessandro memset(vlinfo, 0, sizeof(*vlinfo)); 3071f48ad614SDennis Dalessandro 3072f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_data = 3073f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_FLIT_VL, 3074f48ad614SDennis Dalessandro idx_from_vl(vl))); 3075f48ad614SDennis Dalessandro 3076f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_data = 3077f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RX_FLIT_VL, 3078f48ad614SDennis Dalessandro idx_from_vl(vl))); 3079f48ad614SDennis Dalessandro 3080f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_pkts = 3081f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_TX_PKT_VL, 3082f48ad614SDennis Dalessandro idx_from_vl(vl))); 3083f48ad614SDennis Dalessandro 3084f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_pkts = 3085f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RX_PKT_VL, 3086f48ad614SDennis Dalessandro idx_from_vl(vl))); 3087f48ad614SDennis Dalessandro 308807190076SKamenee Arumugam /* 308907190076SKamenee Arumugam * Convert PortVlXmitWait counter from TXE 309007190076SKamenee Arumugam * cycle times to flit times. 309107190076SKamenee Arumugam */ 3092f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_xmit_wait = 309307190076SKamenee Arumugam cpu_to_be64(get_xmit_wait_counters(ppd, link_width, 309407190076SKamenee Arumugam link_speed, 3095f48ad614SDennis Dalessandro idx_from_vl(vl))); 3096f48ad614SDennis Dalessandro 3097f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_fecn = 3098f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN_VL, 3099f48ad614SDennis Dalessandro idx_from_vl(vl))); 3100f48ad614SDennis Dalessandro rsp->vls[vfi].port_vl_rcv_becn = 3101f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN_VL, 3102f48ad614SDennis Dalessandro idx_from_vl(vl))); 3103f48ad614SDennis Dalessandro 3104f48ad614SDennis Dalessandro /* rsp->port_vl_xmit_time_cong is 0 for HFIs */ 3105f48ad614SDennis Dalessandro /* rsp->port_vl_xmit_wasted_bw ??? */ 3106f48ad614SDennis Dalessandro /* port_vl_xmit_wait_data - TXE (table 13-9 HFI spec) ??? 3107f48ad614SDennis Dalessandro * does this differ from rsp->vls[vfi].port_vl_xmit_wait 3108f48ad614SDennis Dalessandro */ 3109f48ad614SDennis Dalessandro /*rsp->vls[vfi].port_vl_mark_fecn = 3110f48ad614SDennis Dalessandro * cpu_to_be64(read_csr(dd, DCC_PRF_PORT_VL_MARK_FECN_CNT 3111f48ad614SDennis Dalessandro * + offset)); 3112f48ad614SDennis Dalessandro */ 3113f48ad614SDennis Dalessandro vlinfo++; 3114f48ad614SDennis Dalessandro vfi++; 3115f48ad614SDennis Dalessandro } 3116f48ad614SDennis Dalessandro 3117f8659d68SIra Weiny a0_datacounters(ppd, rsp); 3118f48ad614SDennis Dalessandro 3119f48ad614SDennis Dalessandro if (resp_len) 3120f48ad614SDennis Dalessandro *resp_len += response_data_size; 3121f48ad614SDennis Dalessandro 3122f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3123f48ad614SDennis Dalessandro } 3124f48ad614SDennis Dalessandro 3125f48ad614SDennis Dalessandro static int pma_get_ib_portcounters_ext(struct ib_pma_mad *pmp, 3126f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port) 3127f48ad614SDennis Dalessandro { 3128f48ad614SDennis Dalessandro struct ib_pma_portcounters_ext *p = (struct ib_pma_portcounters_ext *) 3129f48ad614SDennis Dalessandro pmp->data; 3130f48ad614SDennis Dalessandro struct _port_dctrs rsp; 3131f48ad614SDennis Dalessandro 3132f48ad614SDennis Dalessandro if (pmp->mad_hdr.attr_mod != 0 || p->port_select != port) { 3133f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3134f48ad614SDennis Dalessandro goto bail; 3135f48ad614SDennis Dalessandro } 3136f48ad614SDennis Dalessandro 3137f48ad614SDennis Dalessandro memset(&rsp, 0, sizeof(rsp)); 3138f48ad614SDennis Dalessandro pma_get_opa_port_dctrs(ibdev, &rsp); 3139f48ad614SDennis Dalessandro 3140f48ad614SDennis Dalessandro p->port_xmit_data = rsp.port_xmit_data; 3141f48ad614SDennis Dalessandro p->port_rcv_data = rsp.port_rcv_data; 3142f48ad614SDennis Dalessandro p->port_xmit_packets = rsp.port_xmit_pkts; 3143f48ad614SDennis Dalessandro p->port_rcv_packets = rsp.port_rcv_pkts; 3144f48ad614SDennis Dalessandro p->port_unicast_xmit_packets = 0; 3145f48ad614SDennis Dalessandro p->port_unicast_rcv_packets = 0; 3146f48ad614SDennis Dalessandro p->port_multicast_xmit_packets = rsp.port_multicast_xmit_pkts; 3147f48ad614SDennis Dalessandro p->port_multicast_rcv_packets = rsp.port_multicast_rcv_pkts; 3148f48ad614SDennis Dalessandro 3149f48ad614SDennis Dalessandro bail: 3150f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3151f48ad614SDennis Dalessandro } 3152f48ad614SDennis Dalessandro 3153f48ad614SDennis Dalessandro static void pma_get_opa_port_ectrs(struct ib_device *ibdev, 3154f48ad614SDennis Dalessandro struct _port_ectrs *rsp, u8 port) 3155f48ad614SDennis Dalessandro { 3156f48ad614SDennis Dalessandro u64 tmp, tmp2; 3157f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 3158f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3159f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3160f48ad614SDennis Dalessandro 3161f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); 3162f48ad614SDennis Dalessandro tmp2 = tmp + read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, 3163f48ad614SDennis Dalessandro CNTR_INVALID_VL); 3164f48ad614SDennis Dalessandro if (tmp2 > (u32)UINT_MAX || tmp2 < tmp) { 3165f48ad614SDennis Dalessandro /* overflow/wrapped */ 3166f48ad614SDennis Dalessandro rsp->link_error_recovery = cpu_to_be32(~0); 3167f48ad614SDennis Dalessandro } else { 3168f48ad614SDennis Dalessandro rsp->link_error_recovery = cpu_to_be32(tmp2); 3169f48ad614SDennis Dalessandro } 3170f48ad614SDennis Dalessandro 3171f48ad614SDennis Dalessandro rsp->link_downed = cpu_to_be32(read_port_cntr(ppd, C_SW_LINK_DOWN, 3172f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 3173f48ad614SDennis Dalessandro rsp->port_rcv_errors = 3174f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL)); 3175f48ad614SDennis Dalessandro rsp->port_rcv_remote_physical_errors = 3176f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR, 3177f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 3178f48ad614SDennis Dalessandro rsp->port_rcv_switch_relay_errors = 0; 3179f48ad614SDennis Dalessandro rsp->port_xmit_discards = 3180f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD, 3181f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 3182f48ad614SDennis Dalessandro rsp->port_xmit_constraint_errors = 3183f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, 3184f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 3185f48ad614SDennis Dalessandro rsp->port_rcv_constraint_errors = 3186f48ad614SDennis Dalessandro cpu_to_be64(read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, 3187f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 31883210314aSJakub Pawlak rsp->local_link_integrity_errors = 31893210314aSJakub Pawlak cpu_to_be64(read_dev_cntr(dd, C_DC_RX_REPLAY, 31903210314aSJakub Pawlak CNTR_INVALID_VL)); 3191f48ad614SDennis Dalessandro rsp->excessive_buffer_overruns = 3192f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL)); 3193f48ad614SDennis Dalessandro } 3194f48ad614SDennis Dalessandro 3195f48ad614SDennis Dalessandro static int pma_get_opa_porterrors(struct opa_pma_mad *pmp, 3196f48ad614SDennis Dalessandro struct ib_device *ibdev, 3197f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 3198f48ad614SDennis Dalessandro { 3199f48ad614SDennis Dalessandro size_t response_data_size; 3200f48ad614SDennis Dalessandro struct _port_ectrs *rsp; 3201f48ad614SDennis Dalessandro u8 port_num; 3202f48ad614SDennis Dalessandro struct opa_port_error_counters64_msg *req; 3203f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 3204f48ad614SDennis Dalessandro u32 num_ports; 3205f48ad614SDennis Dalessandro u8 num_pslm; 3206f48ad614SDennis Dalessandro u8 num_vls; 3207f48ad614SDennis Dalessandro struct hfi1_ibport *ibp; 3208f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd; 3209f48ad614SDennis Dalessandro struct _vls_ectrs *vlinfo; 3210f48ad614SDennis Dalessandro unsigned long vl; 3211f48ad614SDennis Dalessandro u64 port_mask, tmp; 3212f8659d68SIra Weiny unsigned long vl_select_mask; 3213f48ad614SDennis Dalessandro int vfi; 3214f48ad614SDennis Dalessandro 3215f48ad614SDennis Dalessandro req = (struct opa_port_error_counters64_msg *)pmp->data; 3216f48ad614SDennis Dalessandro 3217f48ad614SDennis Dalessandro num_ports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; 3218f48ad614SDennis Dalessandro 3219f48ad614SDennis Dalessandro num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); 3220f48ad614SDennis Dalessandro num_vls = hweight32(be32_to_cpu(req->vl_select_mask)); 3221f48ad614SDennis Dalessandro 3222f48ad614SDennis Dalessandro if (num_ports != 1 || num_ports != num_pslm) { 3223f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3224f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3225f48ad614SDennis Dalessandro } 3226f48ad614SDennis Dalessandro 32276fe1a9b9SGustavo A. R. Silva response_data_size = struct_size(req, port[0].vls, num_vls); 3228f48ad614SDennis Dalessandro 3229f48ad614SDennis Dalessandro if (response_data_size > sizeof(pmp->data)) { 3230f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3231f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3232f48ad614SDennis Dalessandro } 3233f48ad614SDennis Dalessandro /* 3234f48ad614SDennis Dalessandro * The bit set in the mask needs to be consistent with the 3235f48ad614SDennis Dalessandro * port the request came in on. 3236f48ad614SDennis Dalessandro */ 3237f48ad614SDennis Dalessandro port_mask = be64_to_cpu(req->port_select_mask[3]); 3238f48ad614SDennis Dalessandro port_num = find_first_bit((unsigned long *)&port_mask, 32396aaa382fSChristophe Jaillet sizeof(port_mask) * 8); 3240f48ad614SDennis Dalessandro 3241f48ad614SDennis Dalessandro if (port_num != port) { 3242f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3243f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3244f48ad614SDennis Dalessandro } 3245f48ad614SDennis Dalessandro 3246f48ad614SDennis Dalessandro rsp = &req->port[0]; 3247f48ad614SDennis Dalessandro 3248f48ad614SDennis Dalessandro ibp = to_iport(ibdev, port_num); 3249f48ad614SDennis Dalessandro ppd = ppd_from_ibp(ibp); 3250f48ad614SDennis Dalessandro 3251f48ad614SDennis Dalessandro memset(rsp, 0, sizeof(*rsp)); 3252f48ad614SDennis Dalessandro rsp->port_number = port_num; 3253f48ad614SDennis Dalessandro 3254f48ad614SDennis Dalessandro pma_get_opa_port_ectrs(ibdev, rsp, port_num); 3255f48ad614SDennis Dalessandro 3256f48ad614SDennis Dalessandro rsp->port_rcv_remote_physical_errors = 3257f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR, 3258f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 3259f48ad614SDennis Dalessandro rsp->fm_config_errors = 3260f48ad614SDennis Dalessandro cpu_to_be64(read_dev_cntr(dd, C_DC_FM_CFG_ERR, 3261f48ad614SDennis Dalessandro CNTR_INVALID_VL)); 3262f48ad614SDennis Dalessandro tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); 3263f48ad614SDennis Dalessandro 3264f48ad614SDennis Dalessandro rsp->uncorrectable_errors = tmp < 0x100 ? (tmp & 0xff) : 0xff; 32652b719046SJakub Pawlak rsp->port_rcv_errors = 32662b719046SJakub Pawlak cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL)); 3267f48ad614SDennis Dalessandro vlinfo = &rsp->vls[0]; 3268f48ad614SDennis Dalessandro vfi = 0; 3269f48ad614SDennis Dalessandro vl_select_mask = be32_to_cpu(req->vl_select_mask); 3270f8659d68SIra Weiny for_each_set_bit(vl, &vl_select_mask, BITS_PER_LONG) { 3271f48ad614SDennis Dalessandro memset(vlinfo, 0, sizeof(*vlinfo)); 3272583eb8b8SJakub Pawlak rsp->vls[vfi].port_vl_xmit_discards = 3273583eb8b8SJakub Pawlak cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD_VL, 3274583eb8b8SJakub Pawlak idx_from_vl(vl))); 3275f48ad614SDennis Dalessandro vlinfo += 1; 3276f48ad614SDennis Dalessandro vfi++; 3277f48ad614SDennis Dalessandro } 3278f48ad614SDennis Dalessandro 3279f48ad614SDennis Dalessandro if (resp_len) 3280f48ad614SDennis Dalessandro *resp_len += response_data_size; 3281f48ad614SDennis Dalessandro 3282f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3283f48ad614SDennis Dalessandro } 3284f48ad614SDennis Dalessandro 3285f48ad614SDennis Dalessandro static int pma_get_ib_portcounters(struct ib_pma_mad *pmp, 3286f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port) 3287f48ad614SDennis Dalessandro { 3288f48ad614SDennis Dalessandro struct ib_pma_portcounters *p = (struct ib_pma_portcounters *) 3289f48ad614SDennis Dalessandro pmp->data; 3290f48ad614SDennis Dalessandro struct _port_ectrs rsp; 3291f48ad614SDennis Dalessandro u64 temp_link_overrun_errors; 3292f48ad614SDennis Dalessandro u64 temp_64; 3293f48ad614SDennis Dalessandro u32 temp_32; 3294f48ad614SDennis Dalessandro 3295f48ad614SDennis Dalessandro memset(&rsp, 0, sizeof(rsp)); 3296f48ad614SDennis Dalessandro pma_get_opa_port_ectrs(ibdev, &rsp, port); 3297f48ad614SDennis Dalessandro 3298f48ad614SDennis Dalessandro if (pmp->mad_hdr.attr_mod != 0 || p->port_select != port) { 3299f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3300f48ad614SDennis Dalessandro goto bail; 3301f48ad614SDennis Dalessandro } 3302f48ad614SDennis Dalessandro 3303f48ad614SDennis Dalessandro p->symbol_error_counter = 0; /* N/A for OPA */ 3304f48ad614SDennis Dalessandro 3305f48ad614SDennis Dalessandro temp_32 = be32_to_cpu(rsp.link_error_recovery); 3306f48ad614SDennis Dalessandro if (temp_32 > 0xFFUL) 3307f48ad614SDennis Dalessandro p->link_error_recovery_counter = 0xFF; 3308f48ad614SDennis Dalessandro else 3309f48ad614SDennis Dalessandro p->link_error_recovery_counter = (u8)temp_32; 3310f48ad614SDennis Dalessandro 3311f48ad614SDennis Dalessandro temp_32 = be32_to_cpu(rsp.link_downed); 3312f48ad614SDennis Dalessandro if (temp_32 > 0xFFUL) 3313f48ad614SDennis Dalessandro p->link_downed_counter = 0xFF; 3314f48ad614SDennis Dalessandro else 3315f48ad614SDennis Dalessandro p->link_downed_counter = (u8)temp_32; 3316f48ad614SDennis Dalessandro 3317f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_rcv_errors); 3318f48ad614SDennis Dalessandro if (temp_64 > 0xFFFFUL) 3319f48ad614SDennis Dalessandro p->port_rcv_errors = cpu_to_be16(0xFFFF); 3320f48ad614SDennis Dalessandro else 3321f48ad614SDennis Dalessandro p->port_rcv_errors = cpu_to_be16((u16)temp_64); 3322f48ad614SDennis Dalessandro 3323f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_rcv_remote_physical_errors); 3324f48ad614SDennis Dalessandro if (temp_64 > 0xFFFFUL) 3325f48ad614SDennis Dalessandro p->port_rcv_remphys_errors = cpu_to_be16(0xFFFF); 3326f48ad614SDennis Dalessandro else 3327f48ad614SDennis Dalessandro p->port_rcv_remphys_errors = cpu_to_be16((u16)temp_64); 3328f48ad614SDennis Dalessandro 3329f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_rcv_switch_relay_errors); 3330f48ad614SDennis Dalessandro p->port_rcv_switch_relay_errors = cpu_to_be16((u16)temp_64); 3331f48ad614SDennis Dalessandro 3332f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_xmit_discards); 3333f48ad614SDennis Dalessandro if (temp_64 > 0xFFFFUL) 3334f48ad614SDennis Dalessandro p->port_xmit_discards = cpu_to_be16(0xFFFF); 3335f48ad614SDennis Dalessandro else 3336f48ad614SDennis Dalessandro p->port_xmit_discards = cpu_to_be16((u16)temp_64); 3337f48ad614SDennis Dalessandro 3338f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_xmit_constraint_errors); 3339f48ad614SDennis Dalessandro if (temp_64 > 0xFFUL) 3340f48ad614SDennis Dalessandro p->port_xmit_constraint_errors = 0xFF; 3341f48ad614SDennis Dalessandro else 3342f48ad614SDennis Dalessandro p->port_xmit_constraint_errors = (u8)temp_64; 3343f48ad614SDennis Dalessandro 3344f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.port_rcv_constraint_errors); 3345f48ad614SDennis Dalessandro if (temp_64 > 0xFFUL) 3346f48ad614SDennis Dalessandro p->port_rcv_constraint_errors = 0xFFUL; 3347f48ad614SDennis Dalessandro else 3348f48ad614SDennis Dalessandro p->port_rcv_constraint_errors = (u8)temp_64; 3349f48ad614SDennis Dalessandro 3350f48ad614SDennis Dalessandro /* LocalLink: 7:4, BufferOverrun: 3:0 */ 3351f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.local_link_integrity_errors); 3352f48ad614SDennis Dalessandro if (temp_64 > 0xFUL) 3353f48ad614SDennis Dalessandro temp_64 = 0xFUL; 3354f48ad614SDennis Dalessandro 3355f48ad614SDennis Dalessandro temp_link_overrun_errors = temp_64 << 4; 3356f48ad614SDennis Dalessandro 3357f48ad614SDennis Dalessandro temp_64 = be64_to_cpu(rsp.excessive_buffer_overruns); 3358f48ad614SDennis Dalessandro if (temp_64 > 0xFUL) 3359f48ad614SDennis Dalessandro temp_64 = 0xFUL; 3360f48ad614SDennis Dalessandro temp_link_overrun_errors |= temp_64; 3361f48ad614SDennis Dalessandro 3362f48ad614SDennis Dalessandro p->link_overrun_errors = (u8)temp_link_overrun_errors; 3363f48ad614SDennis Dalessandro 3364f48ad614SDennis Dalessandro p->vl15_dropped = 0; /* N/A for OPA */ 3365f48ad614SDennis Dalessandro 3366f48ad614SDennis Dalessandro bail: 3367f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3368f48ad614SDennis Dalessandro } 3369f48ad614SDennis Dalessandro 3370f48ad614SDennis Dalessandro static int pma_get_opa_errorinfo(struct opa_pma_mad *pmp, 3371f48ad614SDennis Dalessandro struct ib_device *ibdev, 3372f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 3373f48ad614SDennis Dalessandro { 3374f48ad614SDennis Dalessandro size_t response_data_size; 3375f48ad614SDennis Dalessandro struct _port_ei *rsp; 3376f48ad614SDennis Dalessandro struct opa_port_error_info_msg *req; 3377f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 3378f48ad614SDennis Dalessandro u64 port_mask; 3379f48ad614SDennis Dalessandro u32 num_ports; 3380f48ad614SDennis Dalessandro u8 port_num; 3381f48ad614SDennis Dalessandro u8 num_pslm; 3382f48ad614SDennis Dalessandro u64 reg; 3383f48ad614SDennis Dalessandro 3384f48ad614SDennis Dalessandro req = (struct opa_port_error_info_msg *)pmp->data; 3385f48ad614SDennis Dalessandro rsp = &req->port[0]; 3386f48ad614SDennis Dalessandro 3387f48ad614SDennis Dalessandro num_ports = OPA_AM_NPORT(be32_to_cpu(pmp->mad_hdr.attr_mod)); 3388f48ad614SDennis Dalessandro num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); 3389f48ad614SDennis Dalessandro 3390f48ad614SDennis Dalessandro memset(rsp, 0, sizeof(*rsp)); 3391f48ad614SDennis Dalessandro 3392f48ad614SDennis Dalessandro if (num_ports != 1 || num_ports != num_pslm) { 3393f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3394f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3395f48ad614SDennis Dalessandro } 3396f48ad614SDennis Dalessandro 3397f48ad614SDennis Dalessandro /* Sanity check */ 3398f48ad614SDennis Dalessandro response_data_size = sizeof(struct opa_port_error_info_msg); 3399f48ad614SDennis Dalessandro 3400f48ad614SDennis Dalessandro if (response_data_size > sizeof(pmp->data)) { 3401f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3402f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3403f48ad614SDennis Dalessandro } 3404f48ad614SDennis Dalessandro 3405f48ad614SDennis Dalessandro /* 3406f48ad614SDennis Dalessandro * The bit set in the mask needs to be consistent with the port 3407f48ad614SDennis Dalessandro * the request came in on. 3408f48ad614SDennis Dalessandro */ 3409f48ad614SDennis Dalessandro port_mask = be64_to_cpu(req->port_select_mask[3]); 3410f48ad614SDennis Dalessandro port_num = find_first_bit((unsigned long *)&port_mask, 34116aaa382fSChristophe Jaillet sizeof(port_mask) * 8); 3412f48ad614SDennis Dalessandro 3413f48ad614SDennis Dalessandro if (port_num != port) { 3414f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3415f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3416f48ad614SDennis Dalessandro } 34175938d94cSMichael J. Ruhl rsp->port_number = port; 3418f48ad614SDennis Dalessandro 3419f48ad614SDennis Dalessandro /* PortRcvErrorInfo */ 3420f48ad614SDennis Dalessandro rsp->port_rcv_ei.status_and_code = 3421f48ad614SDennis Dalessandro dd->err_info_rcvport.status_and_code; 3422f48ad614SDennis Dalessandro memcpy(&rsp->port_rcv_ei.ei.ei1to12.packet_flit1, 3423f48ad614SDennis Dalessandro &dd->err_info_rcvport.packet_flit1, sizeof(u64)); 3424f48ad614SDennis Dalessandro memcpy(&rsp->port_rcv_ei.ei.ei1to12.packet_flit2, 3425f48ad614SDennis Dalessandro &dd->err_info_rcvport.packet_flit2, sizeof(u64)); 3426f48ad614SDennis Dalessandro 3427f48ad614SDennis Dalessandro /* ExcessiverBufferOverrunInfo */ 3428f48ad614SDennis Dalessandro reg = read_csr(dd, RCV_ERR_INFO); 3429f48ad614SDennis Dalessandro if (reg & RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SMASK) { 3430f48ad614SDennis Dalessandro /* 3431f48ad614SDennis Dalessandro * if the RcvExcessBufferOverrun bit is set, save SC of 3432f48ad614SDennis Dalessandro * first pkt that encountered an excess buffer overrun 3433f48ad614SDennis Dalessandro */ 3434f48ad614SDennis Dalessandro u8 tmp = (u8)reg; 3435f48ad614SDennis Dalessandro 3436f48ad614SDennis Dalessandro tmp &= RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SC_SMASK; 3437f48ad614SDennis Dalessandro tmp <<= 2; 3438f48ad614SDennis Dalessandro rsp->excessive_buffer_overrun_ei.status_and_sc = tmp; 3439f48ad614SDennis Dalessandro /* set the status bit */ 3440f48ad614SDennis Dalessandro rsp->excessive_buffer_overrun_ei.status_and_sc |= 0x80; 3441f48ad614SDennis Dalessandro } 3442f48ad614SDennis Dalessandro 3443f48ad614SDennis Dalessandro rsp->port_xmit_constraint_ei.status = 3444f48ad614SDennis Dalessandro dd->err_info_xmit_constraint.status; 3445f48ad614SDennis Dalessandro rsp->port_xmit_constraint_ei.pkey = 3446f48ad614SDennis Dalessandro cpu_to_be16(dd->err_info_xmit_constraint.pkey); 3447f48ad614SDennis Dalessandro rsp->port_xmit_constraint_ei.slid = 3448f48ad614SDennis Dalessandro cpu_to_be32(dd->err_info_xmit_constraint.slid); 3449f48ad614SDennis Dalessandro 3450f48ad614SDennis Dalessandro rsp->port_rcv_constraint_ei.status = 3451f48ad614SDennis Dalessandro dd->err_info_rcv_constraint.status; 3452f48ad614SDennis Dalessandro rsp->port_rcv_constraint_ei.pkey = 3453f48ad614SDennis Dalessandro cpu_to_be16(dd->err_info_rcv_constraint.pkey); 3454f48ad614SDennis Dalessandro rsp->port_rcv_constraint_ei.slid = 3455f48ad614SDennis Dalessandro cpu_to_be32(dd->err_info_rcv_constraint.slid); 3456f48ad614SDennis Dalessandro 3457f48ad614SDennis Dalessandro /* UncorrectableErrorInfo */ 3458f48ad614SDennis Dalessandro rsp->uncorrectable_ei.status_and_code = dd->err_info_uncorrectable; 3459f48ad614SDennis Dalessandro 3460f48ad614SDennis Dalessandro /* FMConfigErrorInfo */ 3461f48ad614SDennis Dalessandro rsp->fm_config_ei.status_and_code = dd->err_info_fmconfig; 3462f48ad614SDennis Dalessandro 3463f48ad614SDennis Dalessandro if (resp_len) 3464f48ad614SDennis Dalessandro *resp_len += response_data_size; 3465f48ad614SDennis Dalessandro 3466f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3467f48ad614SDennis Dalessandro } 3468f48ad614SDennis Dalessandro 3469f48ad614SDennis Dalessandro static int pma_set_opa_portstatus(struct opa_pma_mad *pmp, 3470f48ad614SDennis Dalessandro struct ib_device *ibdev, 3471f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 3472f48ad614SDennis Dalessandro { 3473f48ad614SDennis Dalessandro struct opa_clear_port_status *req = 3474f48ad614SDennis Dalessandro (struct opa_clear_port_status *)pmp->data; 3475f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 3476f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3477f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3478f48ad614SDennis Dalessandro u32 nports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; 3479f48ad614SDennis Dalessandro u64 portn = be64_to_cpu(req->port_select_mask[3]); 3480f48ad614SDennis Dalessandro u32 counter_select = be32_to_cpu(req->counter_select_mask); 3481f8659d68SIra Weiny unsigned long vl_select_mask = VL_MASK_ALL; /* clear all per-vl cnts */ 3482f48ad614SDennis Dalessandro unsigned long vl; 3483f48ad614SDennis Dalessandro 3484f48ad614SDennis Dalessandro if ((nports != 1) || (portn != 1 << port)) { 3485f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3486f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3487f48ad614SDennis Dalessandro } 3488f48ad614SDennis Dalessandro /* 3489f48ad614SDennis Dalessandro * only counters returned by pma_get_opa_portstatus() are 3490f48ad614SDennis Dalessandro * handled, so when pma_get_opa_portstatus() gets a fix, 3491f48ad614SDennis Dalessandro * the corresponding change should be made here as well. 3492f48ad614SDennis Dalessandro */ 3493f48ad614SDennis Dalessandro 3494f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_DATA) 3495f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_XMIT_FLITS, CNTR_INVALID_VL, 0); 3496f48ad614SDennis Dalessandro 3497f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_DATA) 3498f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_FLITS, CNTR_INVALID_VL, 0); 3499f48ad614SDennis Dalessandro 3500f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_PKTS) 3501f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_XMIT_PKTS, CNTR_INVALID_VL, 0); 3502f48ad614SDennis Dalessandro 3503f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_PKTS) 3504f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_PKTS, CNTR_INVALID_VL, 0); 3505f48ad614SDennis Dalessandro 3506f48ad614SDennis Dalessandro if (counter_select & CS_PORT_MCAST_XMIT_PKTS) 3507f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_MC_XMIT_PKTS, CNTR_INVALID_VL, 0); 3508f48ad614SDennis Dalessandro 3509f48ad614SDennis Dalessandro if (counter_select & CS_PORT_MCAST_RCV_PKTS) 3510f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_MC_RCV_PKTS, CNTR_INVALID_VL, 0); 3511f48ad614SDennis Dalessandro 351207190076SKamenee Arumugam if (counter_select & CS_PORT_XMIT_WAIT) { 3513f48ad614SDennis Dalessandro write_port_cntr(ppd, C_TX_WAIT, CNTR_INVALID_VL, 0); 351407190076SKamenee Arumugam ppd->port_vl_xmit_wait_last[C_VL_COUNT] = 0; 351507190076SKamenee Arumugam ppd->vl_xmit_flit_cnt[C_VL_COUNT] = 0; 351607190076SKamenee Arumugam } 3517f48ad614SDennis Dalessandro /* ignore cs_sw_portCongestion for HFIs */ 3518f48ad614SDennis Dalessandro 3519f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_FECN) 3520f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_FCN, CNTR_INVALID_VL, 0); 3521f48ad614SDennis Dalessandro 3522f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_BECN) 3523f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL, 0); 3524f48ad614SDennis Dalessandro 3525f48ad614SDennis Dalessandro /* ignore cs_port_xmit_time_cong for HFIs */ 3526f48ad614SDennis Dalessandro /* ignore cs_port_xmit_wasted_bw for now */ 3527f48ad614SDennis Dalessandro /* ignore cs_port_xmit_wait_data for now */ 3528f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_BUBBLE) 3529f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_BBL, CNTR_INVALID_VL, 0); 3530f48ad614SDennis Dalessandro 3531f48ad614SDennis Dalessandro /* Only applicable for switch */ 3532f48ad614SDennis Dalessandro /* if (counter_select & CS_PORT_MARK_FECN) 3533f48ad614SDennis Dalessandro * write_csr(dd, DCC_PRF_PORT_MARK_FECN_CNT, 0); 3534f48ad614SDennis Dalessandro */ 3535f48ad614SDennis Dalessandro 3536f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_CONSTRAINT_ERRORS) 3537f48ad614SDennis Dalessandro write_port_cntr(ppd, C_SW_RCV_CSTR_ERR, CNTR_INVALID_VL, 0); 3538f48ad614SDennis Dalessandro 3539f48ad614SDennis Dalessandro /* ignore cs_port_rcv_switch_relay_errors for HFIs */ 3540f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_DISCARDS) 3541f48ad614SDennis Dalessandro write_port_cntr(ppd, C_SW_XMIT_DSCD, CNTR_INVALID_VL, 0); 3542f48ad614SDennis Dalessandro 3543f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_CONSTRAINT_ERRORS) 3544f48ad614SDennis Dalessandro write_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, CNTR_INVALID_VL, 0); 3545f48ad614SDennis Dalessandro 3546f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_REMOTE_PHYSICAL_ERRORS) 3547f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RMT_PHY_ERR, CNTR_INVALID_VL, 0); 3548f48ad614SDennis Dalessandro 35493210314aSJakub Pawlak if (counter_select & CS_LOCAL_LINK_INTEGRITY_ERRORS) 3550f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0); 3551f48ad614SDennis Dalessandro 3552f48ad614SDennis Dalessandro if (counter_select & CS_LINK_ERROR_RECOVERY) { 3553f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0); 3554f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, 3555f48ad614SDennis Dalessandro CNTR_INVALID_VL, 0); 3556f48ad614SDennis Dalessandro } 3557f48ad614SDennis Dalessandro 3558f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_ERRORS) 3559f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL, 0); 3560f48ad614SDennis Dalessandro 3561f48ad614SDennis Dalessandro if (counter_select & CS_EXCESSIVE_BUFFER_OVERRUNS) { 3562f48ad614SDennis Dalessandro write_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL, 0); 3563f48ad614SDennis Dalessandro dd->rcv_ovfl_cnt = 0; 3564f48ad614SDennis Dalessandro } 3565f48ad614SDennis Dalessandro 3566f48ad614SDennis Dalessandro if (counter_select & CS_FM_CONFIG_ERRORS) 3567f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_FM_CFG_ERR, CNTR_INVALID_VL, 0); 3568f48ad614SDennis Dalessandro 3569f48ad614SDennis Dalessandro if (counter_select & CS_LINK_DOWNED) 3570f48ad614SDennis Dalessandro write_port_cntr(ppd, C_SW_LINK_DOWN, CNTR_INVALID_VL, 0); 3571f48ad614SDennis Dalessandro 3572f48ad614SDennis Dalessandro if (counter_select & CS_UNCORRECTABLE_ERRORS) 3573f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL, 0); 3574f48ad614SDennis Dalessandro 3575f8659d68SIra Weiny for_each_set_bit(vl, &vl_select_mask, BITS_PER_LONG) { 3576f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_DATA) 3577f48ad614SDennis Dalessandro write_port_cntr(ppd, C_TX_FLIT_VL, idx_from_vl(vl), 0); 3578f48ad614SDennis Dalessandro 3579f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_DATA) 3580f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RX_FLIT_VL, idx_from_vl(vl), 0); 3581f48ad614SDennis Dalessandro 3582f48ad614SDennis Dalessandro if (counter_select & CS_PORT_XMIT_PKTS) 3583f48ad614SDennis Dalessandro write_port_cntr(ppd, C_TX_PKT_VL, idx_from_vl(vl), 0); 3584f48ad614SDennis Dalessandro 3585f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_PKTS) 3586f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RX_PKT_VL, idx_from_vl(vl), 0); 3587f48ad614SDennis Dalessandro 358807190076SKamenee Arumugam if (counter_select & CS_PORT_XMIT_WAIT) { 3589f48ad614SDennis Dalessandro write_port_cntr(ppd, C_TX_WAIT_VL, idx_from_vl(vl), 0); 359007190076SKamenee Arumugam ppd->port_vl_xmit_wait_last[idx_from_vl(vl)] = 0; 359107190076SKamenee Arumugam ppd->vl_xmit_flit_cnt[idx_from_vl(vl)] = 0; 359207190076SKamenee Arumugam } 3593f48ad614SDennis Dalessandro 3594f48ad614SDennis Dalessandro /* sw_port_vl_congestion is 0 for HFIs */ 3595f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_FECN) 3596f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_FCN_VL, idx_from_vl(vl), 0); 3597f48ad614SDennis Dalessandro 3598f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_BECN) 3599f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_BCN_VL, idx_from_vl(vl), 0); 3600f48ad614SDennis Dalessandro 3601f48ad614SDennis Dalessandro /* port_vl_xmit_time_cong is 0 for HFIs */ 3602f48ad614SDennis Dalessandro /* port_vl_xmit_wasted_bw ??? */ 3603f48ad614SDennis Dalessandro /* port_vl_xmit_wait_data - TXE (table 13-9 HFI spec) ??? */ 3604f48ad614SDennis Dalessandro if (counter_select & CS_PORT_RCV_BUBBLE) 3605f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_BBL_VL, idx_from_vl(vl), 0); 3606f48ad614SDennis Dalessandro 3607f48ad614SDennis Dalessandro /* if (counter_select & CS_PORT_MARK_FECN) 3608f48ad614SDennis Dalessandro * write_csr(dd, DCC_PRF_PORT_VL_MARK_FECN_CNT + offset, 0); 3609f48ad614SDennis Dalessandro */ 3610583eb8b8SJakub Pawlak if (counter_select & C_SW_XMIT_DSCD_VL) 3611583eb8b8SJakub Pawlak write_port_cntr(ppd, C_SW_XMIT_DSCD_VL, 3612583eb8b8SJakub Pawlak idx_from_vl(vl), 0); 3613f48ad614SDennis Dalessandro } 3614f48ad614SDennis Dalessandro 3615f48ad614SDennis Dalessandro if (resp_len) 3616f48ad614SDennis Dalessandro *resp_len += sizeof(*req); 3617f48ad614SDennis Dalessandro 3618f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3619f48ad614SDennis Dalessandro } 3620f48ad614SDennis Dalessandro 3621f48ad614SDennis Dalessandro static int pma_set_opa_errorinfo(struct opa_pma_mad *pmp, 3622f48ad614SDennis Dalessandro struct ib_device *ibdev, 3623f48ad614SDennis Dalessandro u8 port, u32 *resp_len) 3624f48ad614SDennis Dalessandro { 3625f48ad614SDennis Dalessandro struct _port_ei *rsp; 3626f48ad614SDennis Dalessandro struct opa_port_error_info_msg *req; 3627f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 3628f48ad614SDennis Dalessandro u64 port_mask; 3629f48ad614SDennis Dalessandro u32 num_ports; 3630f48ad614SDennis Dalessandro u8 port_num; 3631f48ad614SDennis Dalessandro u8 num_pslm; 3632f48ad614SDennis Dalessandro u32 error_info_select; 3633f48ad614SDennis Dalessandro 3634f48ad614SDennis Dalessandro req = (struct opa_port_error_info_msg *)pmp->data; 3635f48ad614SDennis Dalessandro rsp = &req->port[0]; 3636f48ad614SDennis Dalessandro 3637f48ad614SDennis Dalessandro num_ports = OPA_AM_NPORT(be32_to_cpu(pmp->mad_hdr.attr_mod)); 3638f48ad614SDennis Dalessandro num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); 3639f48ad614SDennis Dalessandro 3640f48ad614SDennis Dalessandro memset(rsp, 0, sizeof(*rsp)); 3641f48ad614SDennis Dalessandro 3642f48ad614SDennis Dalessandro if (num_ports != 1 || num_ports != num_pslm) { 3643f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3644f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3645f48ad614SDennis Dalessandro } 3646f48ad614SDennis Dalessandro 3647f48ad614SDennis Dalessandro /* 3648f48ad614SDennis Dalessandro * The bit set in the mask needs to be consistent with the port 3649f48ad614SDennis Dalessandro * the request came in on. 3650f48ad614SDennis Dalessandro */ 3651f48ad614SDennis Dalessandro port_mask = be64_to_cpu(req->port_select_mask[3]); 3652f48ad614SDennis Dalessandro port_num = find_first_bit((unsigned long *)&port_mask, 36536aaa382fSChristophe Jaillet sizeof(port_mask) * 8); 3654f48ad614SDennis Dalessandro 3655f48ad614SDennis Dalessandro if (port_num != port) { 3656f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; 3657f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3658f48ad614SDennis Dalessandro } 3659f48ad614SDennis Dalessandro 3660f48ad614SDennis Dalessandro error_info_select = be32_to_cpu(req->error_info_select_mask); 3661f48ad614SDennis Dalessandro 3662f48ad614SDennis Dalessandro /* PortRcvErrorInfo */ 3663f48ad614SDennis Dalessandro if (error_info_select & ES_PORT_RCV_ERROR_INFO) 3664f48ad614SDennis Dalessandro /* turn off status bit */ 3665f48ad614SDennis Dalessandro dd->err_info_rcvport.status_and_code &= ~OPA_EI_STATUS_SMASK; 3666f48ad614SDennis Dalessandro 3667f48ad614SDennis Dalessandro /* ExcessiverBufferOverrunInfo */ 3668f48ad614SDennis Dalessandro if (error_info_select & ES_EXCESSIVE_BUFFER_OVERRUN_INFO) 3669f48ad614SDennis Dalessandro /* 3670f48ad614SDennis Dalessandro * status bit is essentially kept in the h/w - bit 5 of 3671f48ad614SDennis Dalessandro * RCV_ERR_INFO 3672f48ad614SDennis Dalessandro */ 3673f48ad614SDennis Dalessandro write_csr(dd, RCV_ERR_INFO, 3674f48ad614SDennis Dalessandro RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SMASK); 3675f48ad614SDennis Dalessandro 3676f48ad614SDennis Dalessandro if (error_info_select & ES_PORT_XMIT_CONSTRAINT_ERROR_INFO) 3677f48ad614SDennis Dalessandro dd->err_info_xmit_constraint.status &= ~OPA_EI_STATUS_SMASK; 3678f48ad614SDennis Dalessandro 3679f48ad614SDennis Dalessandro if (error_info_select & ES_PORT_RCV_CONSTRAINT_ERROR_INFO) 3680f48ad614SDennis Dalessandro dd->err_info_rcv_constraint.status &= ~OPA_EI_STATUS_SMASK; 3681f48ad614SDennis Dalessandro 3682f48ad614SDennis Dalessandro /* UncorrectableErrorInfo */ 3683f48ad614SDennis Dalessandro if (error_info_select & ES_UNCORRECTABLE_ERROR_INFO) 3684f48ad614SDennis Dalessandro /* turn off status bit */ 3685f48ad614SDennis Dalessandro dd->err_info_uncorrectable &= ~OPA_EI_STATUS_SMASK; 3686f48ad614SDennis Dalessandro 3687f48ad614SDennis Dalessandro /* FMConfigErrorInfo */ 3688f48ad614SDennis Dalessandro if (error_info_select & ES_FM_CONFIG_ERROR_INFO) 3689f48ad614SDennis Dalessandro /* turn off status bit */ 3690f48ad614SDennis Dalessandro dd->err_info_fmconfig &= ~OPA_EI_STATUS_SMASK; 3691f48ad614SDennis Dalessandro 3692f48ad614SDennis Dalessandro if (resp_len) 3693f48ad614SDennis Dalessandro *resp_len += sizeof(*req); 3694f48ad614SDennis Dalessandro 3695f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 3696f48ad614SDennis Dalessandro } 3697f48ad614SDennis Dalessandro 3698f48ad614SDennis Dalessandro struct opa_congestion_info_attr { 3699f48ad614SDennis Dalessandro __be16 congestion_info; 3700f48ad614SDennis Dalessandro u8 control_table_cap; /* Multiple of 64 entry unit CCTs */ 3701f48ad614SDennis Dalessandro u8 congestion_log_length; 3702f48ad614SDennis Dalessandro } __packed; 3703f48ad614SDennis Dalessandro 3704f48ad614SDennis Dalessandro static int __subn_get_opa_cong_info(struct opa_smp *smp, u32 am, u8 *data, 3705f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3706f1685179SNeel Desai u32 *resp_len, u32 max_len) 3707f48ad614SDennis Dalessandro { 3708f48ad614SDennis Dalessandro struct opa_congestion_info_attr *p = 3709f48ad614SDennis Dalessandro (struct opa_congestion_info_attr *)data; 3710f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3711f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3712f48ad614SDennis Dalessandro 3713f1685179SNeel Desai if (smp_length_check(sizeof(*p), max_len)) { 3714f1685179SNeel Desai smp->status |= IB_SMP_INVALID_FIELD; 3715f1685179SNeel Desai return reply((struct ib_mad_hdr *)smp); 3716f1685179SNeel Desai } 3717f1685179SNeel Desai 3718f48ad614SDennis Dalessandro p->congestion_info = 0; 3719f48ad614SDennis Dalessandro p->control_table_cap = ppd->cc_max_table_entries; 3720f48ad614SDennis Dalessandro p->congestion_log_length = OPA_CONG_LOG_ELEMS; 3721f48ad614SDennis Dalessandro 3722f48ad614SDennis Dalessandro if (resp_len) 3723f48ad614SDennis Dalessandro *resp_len += sizeof(*p); 3724f48ad614SDennis Dalessandro 3725f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3726f48ad614SDennis Dalessandro } 3727f48ad614SDennis Dalessandro 3728f48ad614SDennis Dalessandro static int __subn_get_opa_cong_setting(struct opa_smp *smp, u32 am, 3729f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, 3730f1685179SNeel Desai u8 port, u32 *resp_len, u32 max_len) 3731f48ad614SDennis Dalessandro { 3732f48ad614SDennis Dalessandro int i; 3733f48ad614SDennis Dalessandro struct opa_congestion_setting_attr *p = 3734f48ad614SDennis Dalessandro (struct opa_congestion_setting_attr *)data; 3735f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3736f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3737f48ad614SDennis Dalessandro struct opa_congestion_setting_entry_shadow *entries; 3738f48ad614SDennis Dalessandro struct cc_state *cc_state; 3739f48ad614SDennis Dalessandro 3740f1685179SNeel Desai if (smp_length_check(sizeof(*p), max_len)) { 3741f1685179SNeel Desai smp->status |= IB_SMP_INVALID_FIELD; 3742f1685179SNeel Desai return reply((struct ib_mad_hdr *)smp); 3743f1685179SNeel Desai } 3744f1685179SNeel Desai 3745f48ad614SDennis Dalessandro rcu_read_lock(); 3746f48ad614SDennis Dalessandro 3747f48ad614SDennis Dalessandro cc_state = get_cc_state(ppd); 3748f48ad614SDennis Dalessandro 3749f48ad614SDennis Dalessandro if (!cc_state) { 3750f48ad614SDennis Dalessandro rcu_read_unlock(); 3751f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3752f48ad614SDennis Dalessandro } 3753f48ad614SDennis Dalessandro 3754f48ad614SDennis Dalessandro entries = cc_state->cong_setting.entries; 3755f48ad614SDennis Dalessandro p->port_control = cpu_to_be16(cc_state->cong_setting.port_control); 3756f48ad614SDennis Dalessandro p->control_map = cpu_to_be32(cc_state->cong_setting.control_map); 3757f48ad614SDennis Dalessandro for (i = 0; i < OPA_MAX_SLS; i++) { 3758f48ad614SDennis Dalessandro p->entries[i].ccti_increase = entries[i].ccti_increase; 3759f48ad614SDennis Dalessandro p->entries[i].ccti_timer = cpu_to_be16(entries[i].ccti_timer); 3760f48ad614SDennis Dalessandro p->entries[i].trigger_threshold = 3761f48ad614SDennis Dalessandro entries[i].trigger_threshold; 3762f48ad614SDennis Dalessandro p->entries[i].ccti_min = entries[i].ccti_min; 3763f48ad614SDennis Dalessandro } 3764f48ad614SDennis Dalessandro 3765f48ad614SDennis Dalessandro rcu_read_unlock(); 3766f48ad614SDennis Dalessandro 3767f48ad614SDennis Dalessandro if (resp_len) 3768f48ad614SDennis Dalessandro *resp_len += sizeof(*p); 3769f48ad614SDennis Dalessandro 3770f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3771f48ad614SDennis Dalessandro } 3772f48ad614SDennis Dalessandro 3773f48ad614SDennis Dalessandro /* 3774f48ad614SDennis Dalessandro * Apply congestion control information stored in the ppd to the 3775f48ad614SDennis Dalessandro * active structure. 3776f48ad614SDennis Dalessandro */ 3777f48ad614SDennis Dalessandro static void apply_cc_state(struct hfi1_pportdata *ppd) 3778f48ad614SDennis Dalessandro { 3779f48ad614SDennis Dalessandro struct cc_state *old_cc_state, *new_cc_state; 3780f48ad614SDennis Dalessandro 3781f48ad614SDennis Dalessandro new_cc_state = kzalloc(sizeof(*new_cc_state), GFP_KERNEL); 3782f48ad614SDennis Dalessandro if (!new_cc_state) 3783f48ad614SDennis Dalessandro return; 3784f48ad614SDennis Dalessandro 3785f48ad614SDennis Dalessandro /* 3786f48ad614SDennis Dalessandro * Hold the lock for updating *and* to prevent ppd information 3787f48ad614SDennis Dalessandro * from changing during the update. 3788f48ad614SDennis Dalessandro */ 3789f48ad614SDennis Dalessandro spin_lock(&ppd->cc_state_lock); 3790f48ad614SDennis Dalessandro 37918adf71faSJianxin Xiong old_cc_state = get_cc_state_protected(ppd); 3792f48ad614SDennis Dalessandro if (!old_cc_state) { 3793f48ad614SDennis Dalessandro /* never active, or shutting down */ 3794f48ad614SDennis Dalessandro spin_unlock(&ppd->cc_state_lock); 3795f48ad614SDennis Dalessandro kfree(new_cc_state); 3796f48ad614SDennis Dalessandro return; 3797f48ad614SDennis Dalessandro } 3798f48ad614SDennis Dalessandro 3799f48ad614SDennis Dalessandro *new_cc_state = *old_cc_state; 3800f48ad614SDennis Dalessandro 3801685894ddSDennis Dalessandro if (ppd->total_cct_entry) 3802f48ad614SDennis Dalessandro new_cc_state->cct.ccti_limit = ppd->total_cct_entry - 1; 3803685894ddSDennis Dalessandro else 3804685894ddSDennis Dalessandro new_cc_state->cct.ccti_limit = 0; 3805685894ddSDennis Dalessandro 3806f48ad614SDennis Dalessandro memcpy(new_cc_state->cct.entries, ppd->ccti_entries, 3807f48ad614SDennis Dalessandro ppd->total_cct_entry * sizeof(struct ib_cc_table_entry)); 3808f48ad614SDennis Dalessandro 3809f48ad614SDennis Dalessandro new_cc_state->cong_setting.port_control = IB_CC_CCS_PC_SL_BASED; 3810f48ad614SDennis Dalessandro new_cc_state->cong_setting.control_map = ppd->cc_sl_control_map; 3811f48ad614SDennis Dalessandro memcpy(new_cc_state->cong_setting.entries, ppd->congestion_entries, 3812f48ad614SDennis Dalessandro OPA_MAX_SLS * sizeof(struct opa_congestion_setting_entry)); 3813f48ad614SDennis Dalessandro 3814f48ad614SDennis Dalessandro rcu_assign_pointer(ppd->cc_state, new_cc_state); 3815f48ad614SDennis Dalessandro 3816f48ad614SDennis Dalessandro spin_unlock(&ppd->cc_state_lock); 3817f48ad614SDennis Dalessandro 3818476d95bdSWei Yongjun kfree_rcu(old_cc_state, rcu); 3819f48ad614SDennis Dalessandro } 3820f48ad614SDennis Dalessandro 3821f48ad614SDennis Dalessandro static int __subn_set_opa_cong_setting(struct opa_smp *smp, u32 am, u8 *data, 3822f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3823f1685179SNeel Desai u32 *resp_len, u32 max_len) 3824f48ad614SDennis Dalessandro { 3825f48ad614SDennis Dalessandro struct opa_congestion_setting_attr *p = 3826f48ad614SDennis Dalessandro (struct opa_congestion_setting_attr *)data; 3827f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3828f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3829f48ad614SDennis Dalessandro struct opa_congestion_setting_entry_shadow *entries; 3830f48ad614SDennis Dalessandro int i; 3831f48ad614SDennis Dalessandro 3832f1685179SNeel Desai if (smp_length_check(sizeof(*p), max_len)) { 3833f1685179SNeel Desai smp->status |= IB_SMP_INVALID_FIELD; 3834f1685179SNeel Desai return reply((struct ib_mad_hdr *)smp); 3835f1685179SNeel Desai } 3836f1685179SNeel Desai 3837f48ad614SDennis Dalessandro /* 3838f48ad614SDennis Dalessandro * Save details from packet into the ppd. Hold the cc_state_lock so 3839f48ad614SDennis Dalessandro * our information is consistent with anyone trying to apply the state. 3840f48ad614SDennis Dalessandro */ 3841f48ad614SDennis Dalessandro spin_lock(&ppd->cc_state_lock); 3842f48ad614SDennis Dalessandro ppd->cc_sl_control_map = be32_to_cpu(p->control_map); 3843f48ad614SDennis Dalessandro 3844f48ad614SDennis Dalessandro entries = ppd->congestion_entries; 3845f48ad614SDennis Dalessandro for (i = 0; i < OPA_MAX_SLS; i++) { 3846f48ad614SDennis Dalessandro entries[i].ccti_increase = p->entries[i].ccti_increase; 3847f48ad614SDennis Dalessandro entries[i].ccti_timer = be16_to_cpu(p->entries[i].ccti_timer); 3848f48ad614SDennis Dalessandro entries[i].trigger_threshold = 3849f48ad614SDennis Dalessandro p->entries[i].trigger_threshold; 3850f48ad614SDennis Dalessandro entries[i].ccti_min = p->entries[i].ccti_min; 3851f48ad614SDennis Dalessandro } 3852f48ad614SDennis Dalessandro spin_unlock(&ppd->cc_state_lock); 3853f48ad614SDennis Dalessandro 3854f48ad614SDennis Dalessandro /* now apply the information */ 3855f48ad614SDennis Dalessandro apply_cc_state(ppd); 3856f48ad614SDennis Dalessandro 3857f48ad614SDennis Dalessandro return __subn_get_opa_cong_setting(smp, am, data, ibdev, port, 3858f1685179SNeel Desai resp_len, max_len); 3859f48ad614SDennis Dalessandro } 3860f48ad614SDennis Dalessandro 3861f48ad614SDennis Dalessandro static int __subn_get_opa_hfi1_cong_log(struct opa_smp *smp, u32 am, 3862f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, 3863f1685179SNeel Desai u8 port, u32 *resp_len, u32 max_len) 3864f48ad614SDennis Dalessandro { 3865f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3866f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3867f48ad614SDennis Dalessandro struct opa_hfi1_cong_log *cong_log = (struct opa_hfi1_cong_log *)data; 3868d61ea075SMike Marciniszyn u64 ts; 3869f48ad614SDennis Dalessandro int i; 3870f48ad614SDennis Dalessandro 3871f1685179SNeel Desai if (am || smp_length_check(sizeof(*cong_log), max_len)) { 3872f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3873f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3874f48ad614SDennis Dalessandro } 3875f48ad614SDennis Dalessandro 3876f48ad614SDennis Dalessandro spin_lock_irq(&ppd->cc_log_lock); 3877f48ad614SDennis Dalessandro 3878f48ad614SDennis Dalessandro cong_log->log_type = OPA_CC_LOG_TYPE_HFI; 3879f48ad614SDennis Dalessandro cong_log->congestion_flags = 0; 3880f48ad614SDennis Dalessandro cong_log->threshold_event_counter = 3881f48ad614SDennis Dalessandro cpu_to_be16(ppd->threshold_event_counter); 3882f48ad614SDennis Dalessandro memcpy(cong_log->threshold_cong_event_map, 3883f48ad614SDennis Dalessandro ppd->threshold_cong_event_map, 3884f48ad614SDennis Dalessandro sizeof(cong_log->threshold_cong_event_map)); 3885f48ad614SDennis Dalessandro /* keep timestamp in units of 1.024 usec */ 3886d61ea075SMike Marciniszyn ts = ktime_get_ns() / 1024; 3887f48ad614SDennis Dalessandro cong_log->current_time_stamp = cpu_to_be32(ts); 3888f48ad614SDennis Dalessandro for (i = 0; i < OPA_CONG_LOG_ELEMS; i++) { 3889f48ad614SDennis Dalessandro struct opa_hfi1_cong_log_event_internal *cce = 3890f48ad614SDennis Dalessandro &ppd->cc_events[ppd->cc_mad_idx++]; 3891f48ad614SDennis Dalessandro if (ppd->cc_mad_idx == OPA_CONG_LOG_ELEMS) 3892f48ad614SDennis Dalessandro ppd->cc_mad_idx = 0; 3893f48ad614SDennis Dalessandro /* 3894f48ad614SDennis Dalessandro * Entries which are older than twice the time 3895f48ad614SDennis Dalessandro * required to wrap the counter are supposed to 3896f48ad614SDennis Dalessandro * be zeroed (CA10-49 IBTA, release 1.2.1, V1). 3897f48ad614SDennis Dalessandro */ 3898d61ea075SMike Marciniszyn if ((ts - cce->timestamp) / 2 > U32_MAX) 3899f48ad614SDennis Dalessandro continue; 3900f48ad614SDennis Dalessandro memcpy(cong_log->events[i].local_qp_cn_entry, &cce->lqpn, 3); 3901f48ad614SDennis Dalessandro memcpy(cong_log->events[i].remote_qp_number_cn_entry, 3902f48ad614SDennis Dalessandro &cce->rqpn, 3); 3903f48ad614SDennis Dalessandro cong_log->events[i].sl_svc_type_cn_entry = 3904f48ad614SDennis Dalessandro ((cce->sl & 0x1f) << 3) | (cce->svc_type & 0x7); 3905f48ad614SDennis Dalessandro cong_log->events[i].remote_lid_cn_entry = 3906f48ad614SDennis Dalessandro cpu_to_be32(cce->rlid); 3907f48ad614SDennis Dalessandro cong_log->events[i].timestamp_cn_entry = 3908f48ad614SDennis Dalessandro cpu_to_be32(cce->timestamp); 3909f48ad614SDennis Dalessandro } 3910f48ad614SDennis Dalessandro 3911f48ad614SDennis Dalessandro /* 3912f48ad614SDennis Dalessandro * Reset threshold_cong_event_map, and threshold_event_counter 3913f48ad614SDennis Dalessandro * to 0 when log is read. 3914f48ad614SDennis Dalessandro */ 3915f48ad614SDennis Dalessandro memset(ppd->threshold_cong_event_map, 0x0, 3916f48ad614SDennis Dalessandro sizeof(ppd->threshold_cong_event_map)); 3917f48ad614SDennis Dalessandro ppd->threshold_event_counter = 0; 3918f48ad614SDennis Dalessandro 3919f48ad614SDennis Dalessandro spin_unlock_irq(&ppd->cc_log_lock); 3920f48ad614SDennis Dalessandro 3921f48ad614SDennis Dalessandro if (resp_len) 3922f48ad614SDennis Dalessandro *resp_len += sizeof(struct opa_hfi1_cong_log); 3923f48ad614SDennis Dalessandro 3924f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3925f48ad614SDennis Dalessandro } 3926f48ad614SDennis Dalessandro 3927f48ad614SDennis Dalessandro static int __subn_get_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data, 3928f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3929f1685179SNeel Desai u32 *resp_len, u32 max_len) 3930f48ad614SDennis Dalessandro { 3931f48ad614SDennis Dalessandro struct ib_cc_table_attr *cc_table_attr = 3932f48ad614SDennis Dalessandro (struct ib_cc_table_attr *)data; 3933f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3934f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3935f48ad614SDennis Dalessandro u32 start_block = OPA_AM_START_BLK(am); 3936f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NBLK(am); 3937f48ad614SDennis Dalessandro struct ib_cc_table_entry_shadow *entries; 3938f48ad614SDennis Dalessandro int i, j; 3939f48ad614SDennis Dalessandro u32 sentry, eentry; 3940f48ad614SDennis Dalessandro struct cc_state *cc_state; 3941f1685179SNeel Desai u32 size = sizeof(u16) * (IB_CCT_ENTRIES * n_blocks + 1); 3942f48ad614SDennis Dalessandro 3943f48ad614SDennis Dalessandro /* sanity check n_blocks, start_block */ 3944f1685179SNeel Desai if (n_blocks == 0 || smp_length_check(size, max_len) || 3945f48ad614SDennis Dalessandro start_block + n_blocks > ppd->cc_max_table_entries) { 3946f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3947f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3948f48ad614SDennis Dalessandro } 3949f48ad614SDennis Dalessandro 3950f48ad614SDennis Dalessandro rcu_read_lock(); 3951f48ad614SDennis Dalessandro 3952f48ad614SDennis Dalessandro cc_state = get_cc_state(ppd); 3953f48ad614SDennis Dalessandro 3954f48ad614SDennis Dalessandro if (!cc_state) { 3955f48ad614SDennis Dalessandro rcu_read_unlock(); 3956f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3957f48ad614SDennis Dalessandro } 3958f48ad614SDennis Dalessandro 3959f48ad614SDennis Dalessandro sentry = start_block * IB_CCT_ENTRIES; 3960f48ad614SDennis Dalessandro eentry = sentry + (IB_CCT_ENTRIES * n_blocks); 3961f48ad614SDennis Dalessandro 3962f48ad614SDennis Dalessandro cc_table_attr->ccti_limit = cpu_to_be16(cc_state->cct.ccti_limit); 3963f48ad614SDennis Dalessandro 3964f48ad614SDennis Dalessandro entries = cc_state->cct.entries; 3965f48ad614SDennis Dalessandro 3966f48ad614SDennis Dalessandro /* return n_blocks, though the last block may not be full */ 3967f48ad614SDennis Dalessandro for (j = 0, i = sentry; i < eentry; j++, i++) 3968f48ad614SDennis Dalessandro cc_table_attr->ccti_entries[j].entry = 3969f48ad614SDennis Dalessandro cpu_to_be16(entries[i].entry); 3970f48ad614SDennis Dalessandro 3971f48ad614SDennis Dalessandro rcu_read_unlock(); 3972f48ad614SDennis Dalessandro 3973f48ad614SDennis Dalessandro if (resp_len) 3974f1685179SNeel Desai *resp_len += size; 3975f48ad614SDennis Dalessandro 3976f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3977f48ad614SDennis Dalessandro } 3978f48ad614SDennis Dalessandro 3979f48ad614SDennis Dalessandro static int __subn_set_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data, 3980f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 3981f1685179SNeel Desai u32 *resp_len, u32 max_len) 3982f48ad614SDennis Dalessandro { 3983f48ad614SDennis Dalessandro struct ib_cc_table_attr *p = (struct ib_cc_table_attr *)data; 3984f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 3985f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 3986f48ad614SDennis Dalessandro u32 start_block = OPA_AM_START_BLK(am); 3987f48ad614SDennis Dalessandro u32 n_blocks = OPA_AM_NBLK(am); 3988f48ad614SDennis Dalessandro struct ib_cc_table_entry_shadow *entries; 3989f48ad614SDennis Dalessandro int i, j; 3990f48ad614SDennis Dalessandro u32 sentry, eentry; 3991f48ad614SDennis Dalessandro u16 ccti_limit; 3992f1685179SNeel Desai u32 size = sizeof(u16) * (IB_CCT_ENTRIES * n_blocks + 1); 3993f48ad614SDennis Dalessandro 3994f48ad614SDennis Dalessandro /* sanity check n_blocks, start_block */ 3995f1685179SNeel Desai if (n_blocks == 0 || smp_length_check(size, max_len) || 3996f48ad614SDennis Dalessandro start_block + n_blocks > ppd->cc_max_table_entries) { 3997f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 3998f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 3999f48ad614SDennis Dalessandro } 4000f48ad614SDennis Dalessandro 4001f48ad614SDennis Dalessandro sentry = start_block * IB_CCT_ENTRIES; 4002f48ad614SDennis Dalessandro eentry = sentry + ((n_blocks - 1) * IB_CCT_ENTRIES) + 4003f48ad614SDennis Dalessandro (be16_to_cpu(p->ccti_limit)) % IB_CCT_ENTRIES + 1; 4004f48ad614SDennis Dalessandro 4005f48ad614SDennis Dalessandro /* sanity check ccti_limit */ 4006f48ad614SDennis Dalessandro ccti_limit = be16_to_cpu(p->ccti_limit); 4007f48ad614SDennis Dalessandro if (ccti_limit + 1 > eentry) { 4008f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 4009f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4010f48ad614SDennis Dalessandro } 4011f48ad614SDennis Dalessandro 4012f48ad614SDennis Dalessandro /* 4013f48ad614SDennis Dalessandro * Save details from packet into the ppd. Hold the cc_state_lock so 4014f48ad614SDennis Dalessandro * our information is consistent with anyone trying to apply the state. 4015f48ad614SDennis Dalessandro */ 4016f48ad614SDennis Dalessandro spin_lock(&ppd->cc_state_lock); 4017f48ad614SDennis Dalessandro ppd->total_cct_entry = ccti_limit + 1; 4018f48ad614SDennis Dalessandro entries = ppd->ccti_entries; 4019f48ad614SDennis Dalessandro for (j = 0, i = sentry; i < eentry; j++, i++) 4020f48ad614SDennis Dalessandro entries[i].entry = be16_to_cpu(p->ccti_entries[j].entry); 4021f48ad614SDennis Dalessandro spin_unlock(&ppd->cc_state_lock); 4022f48ad614SDennis Dalessandro 4023f48ad614SDennis Dalessandro /* now apply the information */ 4024f48ad614SDennis Dalessandro apply_cc_state(ppd); 4025f48ad614SDennis Dalessandro 4026f1685179SNeel Desai return __subn_get_opa_cc_table(smp, am, data, ibdev, port, resp_len, 4027f1685179SNeel Desai max_len); 4028f48ad614SDennis Dalessandro } 4029f48ad614SDennis Dalessandro 4030f48ad614SDennis Dalessandro struct opa_led_info { 4031f48ad614SDennis Dalessandro __be32 rsvd_led_mask; 4032f48ad614SDennis Dalessandro __be32 rsvd; 4033f48ad614SDennis Dalessandro }; 4034f48ad614SDennis Dalessandro 4035f48ad614SDennis Dalessandro #define OPA_LED_SHIFT 31 4036f48ad614SDennis Dalessandro #define OPA_LED_MASK BIT(OPA_LED_SHIFT) 4037f48ad614SDennis Dalessandro 4038f48ad614SDennis Dalessandro static int __subn_get_opa_led_info(struct opa_smp *smp, u32 am, u8 *data, 4039f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 4040f1685179SNeel Desai u32 *resp_len, u32 max_len) 4041f48ad614SDennis Dalessandro { 4042f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 4043f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = dd->pport; 4044f48ad614SDennis Dalessandro struct opa_led_info *p = (struct opa_led_info *)data; 4045f48ad614SDennis Dalessandro u32 nport = OPA_AM_NPORT(am); 4046f48ad614SDennis Dalessandro u32 is_beaconing_active; 4047f48ad614SDennis Dalessandro 4048f1685179SNeel Desai if (nport != 1 || smp_length_check(sizeof(*p), max_len)) { 4049f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 4050f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4051f48ad614SDennis Dalessandro } 4052f48ad614SDennis Dalessandro 4053f48ad614SDennis Dalessandro /* 4054f48ad614SDennis Dalessandro * This pairs with the memory barrier in hfi1_start_led_override to 4055f48ad614SDennis Dalessandro * ensure that we read the correct state of LED beaconing represented 4056f48ad614SDennis Dalessandro * by led_override_timer_active 4057f48ad614SDennis Dalessandro */ 4058f48ad614SDennis Dalessandro smp_rmb(); 4059f48ad614SDennis Dalessandro is_beaconing_active = !!atomic_read(&ppd->led_override_timer_active); 4060f48ad614SDennis Dalessandro p->rsvd_led_mask = cpu_to_be32(is_beaconing_active << OPA_LED_SHIFT); 4061f48ad614SDennis Dalessandro 4062f48ad614SDennis Dalessandro if (resp_len) 4063f48ad614SDennis Dalessandro *resp_len += sizeof(struct opa_led_info); 4064f48ad614SDennis Dalessandro 4065f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4066f48ad614SDennis Dalessandro } 4067f48ad614SDennis Dalessandro 4068f48ad614SDennis Dalessandro static int __subn_set_opa_led_info(struct opa_smp *smp, u32 am, u8 *data, 4069f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 4070f1685179SNeel Desai u32 *resp_len, u32 max_len) 4071f48ad614SDennis Dalessandro { 4072f48ad614SDennis Dalessandro struct hfi1_devdata *dd = dd_from_ibdev(ibdev); 4073f48ad614SDennis Dalessandro struct opa_led_info *p = (struct opa_led_info *)data; 4074f48ad614SDennis Dalessandro u32 nport = OPA_AM_NPORT(am); 4075f48ad614SDennis Dalessandro int on = !!(be32_to_cpu(p->rsvd_led_mask) & OPA_LED_MASK); 4076f48ad614SDennis Dalessandro 4077f1685179SNeel Desai if (nport != 1 || smp_length_check(sizeof(*p), max_len)) { 4078f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 4079f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4080f48ad614SDennis Dalessandro } 4081f48ad614SDennis Dalessandro 4082f48ad614SDennis Dalessandro if (on) 4083f48ad614SDennis Dalessandro hfi1_start_led_override(dd->pport, 2000, 1500); 4084f48ad614SDennis Dalessandro else 4085f48ad614SDennis Dalessandro shutdown_led_override(dd->pport); 4086f48ad614SDennis Dalessandro 4087f1685179SNeel Desai return __subn_get_opa_led_info(smp, am, data, ibdev, port, resp_len, 4088f1685179SNeel Desai max_len); 4089f48ad614SDennis Dalessandro } 4090f48ad614SDennis Dalessandro 4091f48ad614SDennis Dalessandro static int subn_get_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am, 4092f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, u8 port, 4093f1685179SNeel Desai u32 *resp_len, u32 max_len) 4094f48ad614SDennis Dalessandro { 4095f48ad614SDennis Dalessandro int ret; 4096f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 4097f48ad614SDennis Dalessandro 4098f48ad614SDennis Dalessandro switch (attr_id) { 4099f48ad614SDennis Dalessandro case IB_SMP_ATTR_NODE_DESC: 4100f48ad614SDennis Dalessandro ret = __subn_get_opa_nodedesc(smp, am, data, ibdev, port, 4101f1685179SNeel Desai resp_len, max_len); 4102f48ad614SDennis Dalessandro break; 4103f48ad614SDennis Dalessandro case IB_SMP_ATTR_NODE_INFO: 4104f48ad614SDennis Dalessandro ret = __subn_get_opa_nodeinfo(smp, am, data, ibdev, port, 4105f1685179SNeel Desai resp_len, max_len); 4106f48ad614SDennis Dalessandro break; 4107f48ad614SDennis Dalessandro case IB_SMP_ATTR_PORT_INFO: 4108f48ad614SDennis Dalessandro ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port, 4109f1685179SNeel Desai resp_len, max_len); 4110f48ad614SDennis Dalessandro break; 4111f48ad614SDennis Dalessandro case IB_SMP_ATTR_PKEY_TABLE: 4112f48ad614SDennis Dalessandro ret = __subn_get_opa_pkeytable(smp, am, data, ibdev, port, 4113f1685179SNeel Desai resp_len, max_len); 4114f48ad614SDennis Dalessandro break; 4115f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SL_TO_SC_MAP: 4116f48ad614SDennis Dalessandro ret = __subn_get_opa_sl_to_sc(smp, am, data, ibdev, port, 4117f1685179SNeel Desai resp_len, max_len); 4118f48ad614SDennis Dalessandro break; 4119f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_SL_MAP: 4120f48ad614SDennis Dalessandro ret = __subn_get_opa_sc_to_sl(smp, am, data, ibdev, port, 4121f1685179SNeel Desai resp_len, max_len); 4122f48ad614SDennis Dalessandro break; 4123f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_VLT_MAP: 4124f48ad614SDennis Dalessandro ret = __subn_get_opa_sc_to_vlt(smp, am, data, ibdev, port, 4125f1685179SNeel Desai resp_len, max_len); 4126f48ad614SDennis Dalessandro break; 4127f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_VLNT_MAP: 4128f48ad614SDennis Dalessandro ret = __subn_get_opa_sc_to_vlnt(smp, am, data, ibdev, port, 4129f1685179SNeel Desai resp_len, max_len); 4130f48ad614SDennis Dalessandro break; 4131f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_PORT_STATE_INFO: 4132f48ad614SDennis Dalessandro ret = __subn_get_opa_psi(smp, am, data, ibdev, port, 4133f1685179SNeel Desai resp_len, max_len); 4134f48ad614SDennis Dalessandro break; 4135f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_BUFFER_CONTROL_TABLE: 4136f48ad614SDennis Dalessandro ret = __subn_get_opa_bct(smp, am, data, ibdev, port, 4137f1685179SNeel Desai resp_len, max_len); 4138f48ad614SDennis Dalessandro break; 4139f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_CABLE_INFO: 4140f48ad614SDennis Dalessandro ret = __subn_get_opa_cable_info(smp, am, data, ibdev, port, 4141f1685179SNeel Desai resp_len, max_len); 4142f48ad614SDennis Dalessandro break; 4143f48ad614SDennis Dalessandro case IB_SMP_ATTR_VL_ARB_TABLE: 4144f48ad614SDennis Dalessandro ret = __subn_get_opa_vl_arb(smp, am, data, ibdev, port, 4145f1685179SNeel Desai resp_len, max_len); 4146f48ad614SDennis Dalessandro break; 4147f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_CONGESTION_INFO: 4148f48ad614SDennis Dalessandro ret = __subn_get_opa_cong_info(smp, am, data, ibdev, port, 4149f1685179SNeel Desai resp_len, max_len); 4150f48ad614SDennis Dalessandro break; 4151f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_HFI_CONGESTION_SETTING: 4152f48ad614SDennis Dalessandro ret = __subn_get_opa_cong_setting(smp, am, data, ibdev, 4153f1685179SNeel Desai port, resp_len, max_len); 4154f48ad614SDennis Dalessandro break; 4155f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_HFI_CONGESTION_LOG: 4156f48ad614SDennis Dalessandro ret = __subn_get_opa_hfi1_cong_log(smp, am, data, ibdev, 4157f1685179SNeel Desai port, resp_len, max_len); 4158f48ad614SDennis Dalessandro break; 4159f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_CONGESTION_CONTROL_TABLE: 4160f48ad614SDennis Dalessandro ret = __subn_get_opa_cc_table(smp, am, data, ibdev, port, 4161f1685179SNeel Desai resp_len, max_len); 4162f48ad614SDennis Dalessandro break; 4163f48ad614SDennis Dalessandro case IB_SMP_ATTR_LED_INFO: 4164f48ad614SDennis Dalessandro ret = __subn_get_opa_led_info(smp, am, data, ibdev, port, 4165f1685179SNeel Desai resp_len, max_len); 4166f48ad614SDennis Dalessandro break; 4167f48ad614SDennis Dalessandro case IB_SMP_ATTR_SM_INFO: 4168f48ad614SDennis Dalessandro if (ibp->rvp.port_cap_flags & IB_PORT_SM_DISABLED) 4169f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 4170f48ad614SDennis Dalessandro if (ibp->rvp.port_cap_flags & IB_PORT_SM) 4171f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS; 41726f24b159SGustavo A. R. Silva fallthrough; 4173f48ad614SDennis Dalessandro default: 4174f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 4175f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4176f48ad614SDennis Dalessandro break; 4177f48ad614SDennis Dalessandro } 4178f48ad614SDennis Dalessandro return ret; 4179f48ad614SDennis Dalessandro } 4180f48ad614SDennis Dalessandro 4181f48ad614SDennis Dalessandro static int subn_set_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am, 4182f48ad614SDennis Dalessandro u8 *data, struct ib_device *ibdev, u8 port, 4183959f2d17SAlex Estrin u32 *resp_len, u32 max_len, int local_mad) 4184f48ad614SDennis Dalessandro { 4185f48ad614SDennis Dalessandro int ret; 4186f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 4187f48ad614SDennis Dalessandro 4188f48ad614SDennis Dalessandro switch (attr_id) { 4189f48ad614SDennis Dalessandro case IB_SMP_ATTR_PORT_INFO: 4190f48ad614SDennis Dalessandro ret = __subn_set_opa_portinfo(smp, am, data, ibdev, port, 4191959f2d17SAlex Estrin resp_len, max_len, local_mad); 4192f48ad614SDennis Dalessandro break; 4193f48ad614SDennis Dalessandro case IB_SMP_ATTR_PKEY_TABLE: 4194f48ad614SDennis Dalessandro ret = __subn_set_opa_pkeytable(smp, am, data, ibdev, port, 4195f1685179SNeel Desai resp_len, max_len); 4196f48ad614SDennis Dalessandro break; 4197f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SL_TO_SC_MAP: 4198f48ad614SDennis Dalessandro ret = __subn_set_opa_sl_to_sc(smp, am, data, ibdev, port, 4199f1685179SNeel Desai resp_len, max_len); 4200f48ad614SDennis Dalessandro break; 4201f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_SL_MAP: 4202f48ad614SDennis Dalessandro ret = __subn_set_opa_sc_to_sl(smp, am, data, ibdev, port, 4203f1685179SNeel Desai resp_len, max_len); 4204f48ad614SDennis Dalessandro break; 4205f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_VLT_MAP: 4206f48ad614SDennis Dalessandro ret = __subn_set_opa_sc_to_vlt(smp, am, data, ibdev, port, 4207f1685179SNeel Desai resp_len, max_len); 4208f48ad614SDennis Dalessandro break; 4209f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_SC_TO_VLNT_MAP: 4210f48ad614SDennis Dalessandro ret = __subn_set_opa_sc_to_vlnt(smp, am, data, ibdev, port, 4211f1685179SNeel Desai resp_len, max_len); 4212f48ad614SDennis Dalessandro break; 4213f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_PORT_STATE_INFO: 4214f48ad614SDennis Dalessandro ret = __subn_set_opa_psi(smp, am, data, ibdev, port, 4215959f2d17SAlex Estrin resp_len, max_len, local_mad); 4216f48ad614SDennis Dalessandro break; 4217f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_BUFFER_CONTROL_TABLE: 4218f48ad614SDennis Dalessandro ret = __subn_set_opa_bct(smp, am, data, ibdev, port, 4219f1685179SNeel Desai resp_len, max_len); 4220f48ad614SDennis Dalessandro break; 4221f48ad614SDennis Dalessandro case IB_SMP_ATTR_VL_ARB_TABLE: 4222f48ad614SDennis Dalessandro ret = __subn_set_opa_vl_arb(smp, am, data, ibdev, port, 4223f1685179SNeel Desai resp_len, max_len); 4224f48ad614SDennis Dalessandro break; 4225f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_HFI_CONGESTION_SETTING: 4226f48ad614SDennis Dalessandro ret = __subn_set_opa_cong_setting(smp, am, data, ibdev, 4227f1685179SNeel Desai port, resp_len, max_len); 4228f48ad614SDennis Dalessandro break; 4229f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_CONGESTION_CONTROL_TABLE: 4230f48ad614SDennis Dalessandro ret = __subn_set_opa_cc_table(smp, am, data, ibdev, port, 4231f1685179SNeel Desai resp_len, max_len); 4232f48ad614SDennis Dalessandro break; 4233f48ad614SDennis Dalessandro case IB_SMP_ATTR_LED_INFO: 4234f48ad614SDennis Dalessandro ret = __subn_set_opa_led_info(smp, am, data, ibdev, port, 4235f1685179SNeel Desai resp_len, max_len); 4236f48ad614SDennis Dalessandro break; 4237f48ad614SDennis Dalessandro case IB_SMP_ATTR_SM_INFO: 4238f48ad614SDennis Dalessandro if (ibp->rvp.port_cap_flags & IB_PORT_SM_DISABLED) 4239f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 4240f48ad614SDennis Dalessandro if (ibp->rvp.port_cap_flags & IB_PORT_SM) 4241f48ad614SDennis Dalessandro return IB_MAD_RESULT_SUCCESS; 42426f24b159SGustavo A. R. Silva fallthrough; 4243f48ad614SDennis Dalessandro default: 4244f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 4245f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4246f48ad614SDennis Dalessandro break; 4247f48ad614SDennis Dalessandro } 4248f48ad614SDennis Dalessandro return ret; 4249f48ad614SDennis Dalessandro } 4250f48ad614SDennis Dalessandro 4251f48ad614SDennis Dalessandro static inline void set_aggr_error(struct opa_aggregate *ag) 4252f48ad614SDennis Dalessandro { 4253f48ad614SDennis Dalessandro ag->err_reqlength |= cpu_to_be16(0x8000); 4254f48ad614SDennis Dalessandro } 4255f48ad614SDennis Dalessandro 4256f48ad614SDennis Dalessandro static int subn_get_opa_aggregate(struct opa_smp *smp, 4257f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 4258f48ad614SDennis Dalessandro u32 *resp_len) 4259f48ad614SDennis Dalessandro { 4260f48ad614SDennis Dalessandro int i; 4261f48ad614SDennis Dalessandro u32 num_attr = be32_to_cpu(smp->attr_mod) & 0x000000ff; 4262f48ad614SDennis Dalessandro u8 *next_smp = opa_get_smp_data(smp); 4263f48ad614SDennis Dalessandro 4264f48ad614SDennis Dalessandro if (num_attr < 1 || num_attr > 117) { 4265f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 4266f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4267f48ad614SDennis Dalessandro } 4268f48ad614SDennis Dalessandro 4269f48ad614SDennis Dalessandro for (i = 0; i < num_attr; i++) { 4270f48ad614SDennis Dalessandro struct opa_aggregate *agg; 4271f48ad614SDennis Dalessandro size_t agg_data_len; 4272f48ad614SDennis Dalessandro size_t agg_size; 4273f48ad614SDennis Dalessandro u32 am; 4274f48ad614SDennis Dalessandro 4275f48ad614SDennis Dalessandro agg = (struct opa_aggregate *)next_smp; 4276f48ad614SDennis Dalessandro agg_data_len = (be16_to_cpu(agg->err_reqlength) & 0x007f) * 8; 4277f48ad614SDennis Dalessandro agg_size = sizeof(*agg) + agg_data_len; 4278f48ad614SDennis Dalessandro am = be32_to_cpu(agg->attr_mod); 4279f48ad614SDennis Dalessandro 4280f48ad614SDennis Dalessandro *resp_len += agg_size; 4281f48ad614SDennis Dalessandro 4282f48ad614SDennis Dalessandro if (next_smp + agg_size > ((u8 *)smp) + sizeof(*smp)) { 4283f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 4284f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4285f48ad614SDennis Dalessandro } 4286f48ad614SDennis Dalessandro 4287f48ad614SDennis Dalessandro /* zero the payload for this segment */ 4288f48ad614SDennis Dalessandro memset(next_smp + sizeof(*agg), 0, agg_data_len); 4289f48ad614SDennis Dalessandro 4290f48ad614SDennis Dalessandro (void)subn_get_opa_sma(agg->attr_id, smp, am, agg->data, 4291f1685179SNeel Desai ibdev, port, NULL, (u32)agg_data_len); 4292f1685179SNeel Desai 4293f1685179SNeel Desai if (smp->status & IB_SMP_INVALID_FIELD) 4294f1685179SNeel Desai break; 4295f48ad614SDennis Dalessandro if (smp->status & ~IB_SMP_DIRECTION) { 4296f48ad614SDennis Dalessandro set_aggr_error(agg); 4297f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4298f48ad614SDennis Dalessandro } 4299f48ad614SDennis Dalessandro next_smp += agg_size; 4300f48ad614SDennis Dalessandro } 4301f48ad614SDennis Dalessandro 4302f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4303f48ad614SDennis Dalessandro } 4304f48ad614SDennis Dalessandro 4305f48ad614SDennis Dalessandro static int subn_set_opa_aggregate(struct opa_smp *smp, 4306f48ad614SDennis Dalessandro struct ib_device *ibdev, u8 port, 4307959f2d17SAlex Estrin u32 *resp_len, int local_mad) 4308f48ad614SDennis Dalessandro { 4309f48ad614SDennis Dalessandro int i; 4310f48ad614SDennis Dalessandro u32 num_attr = be32_to_cpu(smp->attr_mod) & 0x000000ff; 4311f48ad614SDennis Dalessandro u8 *next_smp = opa_get_smp_data(smp); 4312f48ad614SDennis Dalessandro 4313f48ad614SDennis Dalessandro if (num_attr < 1 || num_attr > 117) { 4314f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 4315f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4316f48ad614SDennis Dalessandro } 4317f48ad614SDennis Dalessandro 4318f48ad614SDennis Dalessandro for (i = 0; i < num_attr; i++) { 4319f48ad614SDennis Dalessandro struct opa_aggregate *agg; 4320f48ad614SDennis Dalessandro size_t agg_data_len; 4321f48ad614SDennis Dalessandro size_t agg_size; 4322f48ad614SDennis Dalessandro u32 am; 4323f48ad614SDennis Dalessandro 4324f48ad614SDennis Dalessandro agg = (struct opa_aggregate *)next_smp; 4325f48ad614SDennis Dalessandro agg_data_len = (be16_to_cpu(agg->err_reqlength) & 0x007f) * 8; 4326f48ad614SDennis Dalessandro agg_size = sizeof(*agg) + agg_data_len; 4327f48ad614SDennis Dalessandro am = be32_to_cpu(agg->attr_mod); 4328f48ad614SDennis Dalessandro 4329f48ad614SDennis Dalessandro *resp_len += agg_size; 4330f48ad614SDennis Dalessandro 4331f48ad614SDennis Dalessandro if (next_smp + agg_size > ((u8 *)smp) + sizeof(*smp)) { 4332f48ad614SDennis Dalessandro smp->status |= IB_SMP_INVALID_FIELD; 4333f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4334f48ad614SDennis Dalessandro } 4335f48ad614SDennis Dalessandro 4336f48ad614SDennis Dalessandro (void)subn_set_opa_sma(agg->attr_id, smp, am, agg->data, 4337959f2d17SAlex Estrin ibdev, port, NULL, (u32)agg_data_len, 4338959f2d17SAlex Estrin local_mad); 4339959f2d17SAlex Estrin 4340f1685179SNeel Desai if (smp->status & IB_SMP_INVALID_FIELD) 4341f1685179SNeel Desai break; 4342f48ad614SDennis Dalessandro if (smp->status & ~IB_SMP_DIRECTION) { 4343f48ad614SDennis Dalessandro set_aggr_error(agg); 4344f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4345f48ad614SDennis Dalessandro } 4346f48ad614SDennis Dalessandro next_smp += agg_size; 4347f48ad614SDennis Dalessandro } 4348f48ad614SDennis Dalessandro 4349f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)smp); 4350f48ad614SDennis Dalessandro } 4351f48ad614SDennis Dalessandro 4352f48ad614SDennis Dalessandro /* 4353f48ad614SDennis Dalessandro * OPAv1 specifies that, on the transition to link up, these counters 4354f48ad614SDennis Dalessandro * are cleared: 4355f48ad614SDennis Dalessandro * PortRcvErrors [*] 4356f48ad614SDennis Dalessandro * LinkErrorRecovery 4357f48ad614SDennis Dalessandro * LocalLinkIntegrityErrors 4358f48ad614SDennis Dalessandro * ExcessiveBufferOverruns [*] 4359f48ad614SDennis Dalessandro * 4360f48ad614SDennis Dalessandro * [*] Error info associated with these counters is retained, but the 4361f48ad614SDennis Dalessandro * error info status is reset to 0. 4362f48ad614SDennis Dalessandro */ 4363f48ad614SDennis Dalessandro void clear_linkup_counters(struct hfi1_devdata *dd) 4364f48ad614SDennis Dalessandro { 4365f48ad614SDennis Dalessandro /* PortRcvErrors */ 4366f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL, 0); 4367f48ad614SDennis Dalessandro dd->err_info_rcvport.status_and_code &= ~OPA_EI_STATUS_SMASK; 4368f48ad614SDennis Dalessandro /* LinkErrorRecovery */ 4369f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0); 4370f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL, 0); 4371f48ad614SDennis Dalessandro /* LocalLinkIntegrityErrors */ 4372f48ad614SDennis Dalessandro write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0); 4373f48ad614SDennis Dalessandro /* ExcessiveBufferOverruns */ 4374f48ad614SDennis Dalessandro write_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL, 0); 4375f48ad614SDennis Dalessandro dd->rcv_ovfl_cnt = 0; 4376f48ad614SDennis Dalessandro dd->err_info_xmit_constraint.status &= ~OPA_EI_STATUS_SMASK; 4377f48ad614SDennis Dalessandro } 4378f48ad614SDennis Dalessandro 4379406310c6SSebastian Sanchez static int is_full_mgmt_pkey_in_table(struct hfi1_ibport *ibp) 4380406310c6SSebastian Sanchez { 4381406310c6SSebastian Sanchez unsigned int i; 4382406310c6SSebastian Sanchez struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 4383406310c6SSebastian Sanchez 4384406310c6SSebastian Sanchez for (i = 0; i < ARRAY_SIZE(ppd->pkeys); ++i) 4385406310c6SSebastian Sanchez if (ppd->pkeys[i] == FULL_MGMT_P_KEY) 4386406310c6SSebastian Sanchez return 1; 4387406310c6SSebastian Sanchez 4388406310c6SSebastian Sanchez return 0; 4389406310c6SSebastian Sanchez } 4390406310c6SSebastian Sanchez 4391f48ad614SDennis Dalessandro /* 4392f48ad614SDennis Dalessandro * is_local_mad() returns 1 if 'mad' is sent from, and destined to the 4393f48ad614SDennis Dalessandro * local node, 0 otherwise. 4394f48ad614SDennis Dalessandro */ 4395f48ad614SDennis Dalessandro static int is_local_mad(struct hfi1_ibport *ibp, const struct opa_mad *mad, 4396f48ad614SDennis Dalessandro const struct ib_wc *in_wc) 4397f48ad614SDennis Dalessandro { 4398f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 4399f48ad614SDennis Dalessandro const struct opa_smp *smp = (const struct opa_smp *)mad; 4400f48ad614SDennis Dalessandro 4401f48ad614SDennis Dalessandro if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 4402f48ad614SDennis Dalessandro return (smp->hop_cnt == 0 && 4403f48ad614SDennis Dalessandro smp->route.dr.dr_slid == OPA_LID_PERMISSIVE && 4404f48ad614SDennis Dalessandro smp->route.dr.dr_dlid == OPA_LID_PERMISSIVE); 4405f48ad614SDennis Dalessandro } 4406f48ad614SDennis Dalessandro 4407f48ad614SDennis Dalessandro return (in_wc->slid == ppd->lid); 4408f48ad614SDennis Dalessandro } 4409f48ad614SDennis Dalessandro 4410f48ad614SDennis Dalessandro /* 4411f48ad614SDennis Dalessandro * opa_local_smp_check() should only be called on MADs for which 4412f48ad614SDennis Dalessandro * is_local_mad() returns true. It applies the SMP checks that are 4413f48ad614SDennis Dalessandro * specific to SMPs which are sent from, and destined to this node. 4414f48ad614SDennis Dalessandro * opa_local_smp_check() returns 0 if the SMP passes its checks, 1 4415f48ad614SDennis Dalessandro * otherwise. 4416f48ad614SDennis Dalessandro * 4417f48ad614SDennis Dalessandro * SMPs which arrive from other nodes are instead checked by 4418f48ad614SDennis Dalessandro * opa_smp_check(). 4419f48ad614SDennis Dalessandro */ 4420f48ad614SDennis Dalessandro static int opa_local_smp_check(struct hfi1_ibport *ibp, 4421f48ad614SDennis Dalessandro const struct ib_wc *in_wc) 4422f48ad614SDennis Dalessandro { 4423f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 4424f48ad614SDennis Dalessandro u16 pkey; 4425f48ad614SDennis Dalessandro 4426f48ad614SDennis Dalessandro if (in_wc->pkey_index >= ARRAY_SIZE(ppd->pkeys)) 4427f48ad614SDennis Dalessandro return 1; 4428f48ad614SDennis Dalessandro 4429f48ad614SDennis Dalessandro pkey = ppd->pkeys[in_wc->pkey_index]; 4430f48ad614SDennis Dalessandro /* 4431f48ad614SDennis Dalessandro * We need to do the "node-local" checks specified in OPAv1, 4432f48ad614SDennis Dalessandro * rev 0.90, section 9.10.26, which are: 4433f48ad614SDennis Dalessandro * - pkey is 0x7fff, or 0xffff 4434f48ad614SDennis Dalessandro * - Source QPN == 0 || Destination QPN == 0 4435f48ad614SDennis Dalessandro * - the MAD header's management class is either 4436f48ad614SDennis Dalessandro * IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE or 4437f48ad614SDennis Dalessandro * IB_MGMT_CLASS_SUBN_LID_ROUTED 4438f48ad614SDennis Dalessandro * - SLID != 0 4439f48ad614SDennis Dalessandro * 4440f48ad614SDennis Dalessandro * However, we know (and so don't need to check again) that, 4441f48ad614SDennis Dalessandro * for local SMPs, the MAD stack passes MADs with: 4442f48ad614SDennis Dalessandro * - Source QPN of 0 4443f48ad614SDennis Dalessandro * - MAD mgmt_class is IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 4444f48ad614SDennis Dalessandro * - SLID is either: OPA_LID_PERMISSIVE (0xFFFFFFFF), or 4445f48ad614SDennis Dalessandro * our own port's lid 4446f48ad614SDennis Dalessandro * 4447f48ad614SDennis Dalessandro */ 4448f48ad614SDennis Dalessandro if (pkey == LIM_MGMT_P_KEY || pkey == FULL_MGMT_P_KEY) 4449f48ad614SDennis Dalessandro return 0; 44502e903b61SDon Hiatt ingress_pkey_table_fail(ppd, pkey, in_wc->slid); 4451f48ad614SDennis Dalessandro return 1; 4452f48ad614SDennis Dalessandro } 4453f48ad614SDennis Dalessandro 4454406310c6SSebastian Sanchez /** 4455406310c6SSebastian Sanchez * hfi1_pkey_validation_pma - It validates PKEYs for incoming PMA MAD packets. 4456406310c6SSebastian Sanchez * @ibp: IB port data 4457406310c6SSebastian Sanchez * @in_mad: MAD packet with header and data 4458406310c6SSebastian Sanchez * @in_wc: Work completion data such as source LID, port number, etc. 4459406310c6SSebastian Sanchez * 4460406310c6SSebastian Sanchez * These are all the possible logic rules for validating a pkey: 4461406310c6SSebastian Sanchez * 4462406310c6SSebastian Sanchez * a) If pkey neither FULL_MGMT_P_KEY nor LIM_MGMT_P_KEY, 4463406310c6SSebastian Sanchez * and NOT self-originated packet: 4464406310c6SSebastian Sanchez * Drop MAD packet as it should always be part of the 4465406310c6SSebastian Sanchez * management partition unless it's a self-originated packet. 4466406310c6SSebastian Sanchez * 4467406310c6SSebastian Sanchez * b) If pkey_index -> FULL_MGMT_P_KEY, and LIM_MGMT_P_KEY in pkey table: 4468406310c6SSebastian Sanchez * The packet is coming from a management node and the receiving node 4469406310c6SSebastian Sanchez * is also a management node, so it is safe for the packet to go through. 4470406310c6SSebastian Sanchez * 4471406310c6SSebastian Sanchez * c) If pkey_index -> FULL_MGMT_P_KEY, and LIM_MGMT_P_KEY is NOT in pkey table: 4472406310c6SSebastian Sanchez * Drop the packet as LIM_MGMT_P_KEY should always be in the pkey table. 4473406310c6SSebastian Sanchez * It could be an FM misconfiguration. 4474406310c6SSebastian Sanchez * 4475406310c6SSebastian Sanchez * d) If pkey_index -> LIM_MGMT_P_KEY and FULL_MGMT_P_KEY is NOT in pkey table: 4476406310c6SSebastian Sanchez * It is safe for the packet to go through since a non-management node is 4477406310c6SSebastian Sanchez * talking to another non-management node. 4478406310c6SSebastian Sanchez * 4479406310c6SSebastian Sanchez * e) If pkey_index -> LIM_MGMT_P_KEY and FULL_MGMT_P_KEY in pkey table: 4480406310c6SSebastian Sanchez * Drop the packet because a non-management node is talking to a 4481406310c6SSebastian Sanchez * management node, and it could be an attack. 4482406310c6SSebastian Sanchez * 4483406310c6SSebastian Sanchez * For the implementation, these rules can be simplied to only checking 4484406310c6SSebastian Sanchez * for (a) and (e). There's no need to check for rule (b) as 4485406310c6SSebastian Sanchez * the packet doesn't need to be dropped. Rule (c) is not possible in 4486406310c6SSebastian Sanchez * the driver as LIM_MGMT_P_KEY is always in the pkey table. 4487406310c6SSebastian Sanchez * 4488406310c6SSebastian Sanchez * Return: 4489406310c6SSebastian Sanchez * 0 - pkey is okay, -EINVAL it's a bad pkey 4490406310c6SSebastian Sanchez */ 4491406310c6SSebastian Sanchez static int hfi1_pkey_validation_pma(struct hfi1_ibport *ibp, 4492406310c6SSebastian Sanchez const struct opa_mad *in_mad, 4493406310c6SSebastian Sanchez const struct ib_wc *in_wc) 4494406310c6SSebastian Sanchez { 4495406310c6SSebastian Sanchez u16 pkey_value = hfi1_lookup_pkey_value(ibp, in_wc->pkey_index); 4496406310c6SSebastian Sanchez 4497406310c6SSebastian Sanchez /* Rule (a) from above */ 4498406310c6SSebastian Sanchez if (!is_local_mad(ibp, in_mad, in_wc) && 4499406310c6SSebastian Sanchez pkey_value != LIM_MGMT_P_KEY && 4500406310c6SSebastian Sanchez pkey_value != FULL_MGMT_P_KEY) 4501406310c6SSebastian Sanchez return -EINVAL; 4502406310c6SSebastian Sanchez 4503406310c6SSebastian Sanchez /* Rule (e) from above */ 4504406310c6SSebastian Sanchez if (pkey_value == LIM_MGMT_P_KEY && 4505406310c6SSebastian Sanchez is_full_mgmt_pkey_in_table(ibp)) 4506406310c6SSebastian Sanchez return -EINVAL; 4507406310c6SSebastian Sanchez 4508406310c6SSebastian Sanchez return 0; 4509406310c6SSebastian Sanchez } 4510406310c6SSebastian Sanchez 4511f48ad614SDennis Dalessandro static int process_subn_opa(struct ib_device *ibdev, int mad_flags, 4512f48ad614SDennis Dalessandro u8 port, const struct opa_mad *in_mad, 4513f48ad614SDennis Dalessandro struct opa_mad *out_mad, 4514959f2d17SAlex Estrin u32 *resp_len, int local_mad) 4515f48ad614SDennis Dalessandro { 4516f48ad614SDennis Dalessandro struct opa_smp *smp = (struct opa_smp *)out_mad; 4517f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 4518f48ad614SDennis Dalessandro u8 *data; 4519f1685179SNeel Desai u32 am, data_size; 4520f48ad614SDennis Dalessandro __be16 attr_id; 4521f48ad614SDennis Dalessandro int ret; 4522f48ad614SDennis Dalessandro 4523f48ad614SDennis Dalessandro *out_mad = *in_mad; 4524f48ad614SDennis Dalessandro data = opa_get_smp_data(smp); 4525f1685179SNeel Desai data_size = (u32)opa_get_smp_data_size(smp); 4526f48ad614SDennis Dalessandro 4527f48ad614SDennis Dalessandro am = be32_to_cpu(smp->attr_mod); 4528f48ad614SDennis Dalessandro attr_id = smp->attr_id; 45299fa240bbSHal Rosenstock if (smp->class_version != OPA_SM_CLASS_VERSION) { 4530f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_VERSION; 4531f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4532f48ad614SDennis Dalessandro return ret; 4533f48ad614SDennis Dalessandro } 4534f48ad614SDennis Dalessandro ret = check_mkey(ibp, (struct ib_mad_hdr *)smp, mad_flags, smp->mkey, 4535f48ad614SDennis Dalessandro smp->route.dr.dr_slid, smp->route.dr.return_path, 4536f48ad614SDennis Dalessandro smp->hop_cnt); 4537f48ad614SDennis Dalessandro if (ret) { 4538f48ad614SDennis Dalessandro u32 port_num = be32_to_cpu(smp->attr_mod); 4539f48ad614SDennis Dalessandro 4540f48ad614SDennis Dalessandro /* 4541f48ad614SDennis Dalessandro * If this is a get/set portinfo, we already check the 4542f48ad614SDennis Dalessandro * M_Key if the MAD is for another port and the M_Key 4543f48ad614SDennis Dalessandro * is OK on the receiving port. This check is needed 4544f48ad614SDennis Dalessandro * to increment the error counters when the M_Key 4545f48ad614SDennis Dalessandro * fails to match on *both* ports. 4546f48ad614SDennis Dalessandro */ 4547f48ad614SDennis Dalessandro if (attr_id == IB_SMP_ATTR_PORT_INFO && 4548f48ad614SDennis Dalessandro (smp->method == IB_MGMT_METHOD_GET || 4549f48ad614SDennis Dalessandro smp->method == IB_MGMT_METHOD_SET) && 4550f48ad614SDennis Dalessandro port_num && port_num <= ibdev->phys_port_cnt && 4551f48ad614SDennis Dalessandro port != port_num) 4552f48ad614SDennis Dalessandro (void)check_mkey(to_iport(ibdev, port_num), 4553f48ad614SDennis Dalessandro (struct ib_mad_hdr *)smp, 0, 4554f48ad614SDennis Dalessandro smp->mkey, smp->route.dr.dr_slid, 4555f48ad614SDennis Dalessandro smp->route.dr.return_path, 4556f48ad614SDennis Dalessandro smp->hop_cnt); 4557f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_FAILURE; 4558f48ad614SDennis Dalessandro return ret; 4559f48ad614SDennis Dalessandro } 4560f48ad614SDennis Dalessandro 4561f48ad614SDennis Dalessandro *resp_len = opa_get_smp_header_size(smp); 4562f48ad614SDennis Dalessandro 4563f48ad614SDennis Dalessandro switch (smp->method) { 4564f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 4565f48ad614SDennis Dalessandro switch (attr_id) { 4566f48ad614SDennis Dalessandro default: 4567f48ad614SDennis Dalessandro clear_opa_smp_data(smp); 4568f48ad614SDennis Dalessandro ret = subn_get_opa_sma(attr_id, smp, am, data, 4569f1685179SNeel Desai ibdev, port, resp_len, 4570f1685179SNeel Desai data_size); 4571f48ad614SDennis Dalessandro break; 4572f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_AGGREGATE: 4573f48ad614SDennis Dalessandro ret = subn_get_opa_aggregate(smp, ibdev, port, 4574f48ad614SDennis Dalessandro resp_len); 4575f48ad614SDennis Dalessandro break; 4576f48ad614SDennis Dalessandro } 4577f48ad614SDennis Dalessandro break; 4578f48ad614SDennis Dalessandro case IB_MGMT_METHOD_SET: 4579f48ad614SDennis Dalessandro switch (attr_id) { 4580f48ad614SDennis Dalessandro default: 4581f48ad614SDennis Dalessandro ret = subn_set_opa_sma(attr_id, smp, am, data, 4582f1685179SNeel Desai ibdev, port, resp_len, 4583959f2d17SAlex Estrin data_size, local_mad); 4584f48ad614SDennis Dalessandro break; 4585f48ad614SDennis Dalessandro case OPA_ATTRIB_ID_AGGREGATE: 4586f48ad614SDennis Dalessandro ret = subn_set_opa_aggregate(smp, ibdev, port, 4587959f2d17SAlex Estrin resp_len, local_mad); 4588f48ad614SDennis Dalessandro break; 4589f48ad614SDennis Dalessandro } 4590f48ad614SDennis Dalessandro break; 4591f48ad614SDennis Dalessandro case IB_MGMT_METHOD_TRAP: 4592f48ad614SDennis Dalessandro case IB_MGMT_METHOD_REPORT: 4593f48ad614SDennis Dalessandro case IB_MGMT_METHOD_REPORT_RESP: 4594f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET_RESP: 4595f48ad614SDennis Dalessandro /* 4596f48ad614SDennis Dalessandro * The ib_mad module will call us to process responses 4597f48ad614SDennis Dalessandro * before checking for other consumers. 4598f48ad614SDennis Dalessandro * Just tell the caller to process it normally. 4599f48ad614SDennis Dalessandro */ 4600f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4601f48ad614SDennis Dalessandro break; 4602bf90aaddSMichael J. Ruhl case IB_MGMT_METHOD_TRAP_REPRESS: 4603bf90aaddSMichael J. Ruhl subn_handle_opa_trap_repress(ibp, smp); 4604bf90aaddSMichael J. Ruhl /* Always successful */ 4605bf90aaddSMichael J. Ruhl ret = IB_MAD_RESULT_SUCCESS; 4606bf90aaddSMichael J. Ruhl break; 4607f48ad614SDennis Dalessandro default: 4608f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METHOD; 4609f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4610f48ad614SDennis Dalessandro break; 4611f48ad614SDennis Dalessandro } 4612f48ad614SDennis Dalessandro 4613f48ad614SDennis Dalessandro return ret; 4614f48ad614SDennis Dalessandro } 4615f48ad614SDennis Dalessandro 4616f48ad614SDennis Dalessandro static int process_subn(struct ib_device *ibdev, int mad_flags, 4617f48ad614SDennis Dalessandro u8 port, const struct ib_mad *in_mad, 4618f48ad614SDennis Dalessandro struct ib_mad *out_mad) 4619f48ad614SDennis Dalessandro { 4620f48ad614SDennis Dalessandro struct ib_smp *smp = (struct ib_smp *)out_mad; 4621f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 4622f48ad614SDennis Dalessandro int ret; 4623f48ad614SDennis Dalessandro 4624f48ad614SDennis Dalessandro *out_mad = *in_mad; 4625f48ad614SDennis Dalessandro if (smp->class_version != 1) { 4626f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_VERSION; 4627f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4628f48ad614SDennis Dalessandro return ret; 4629f48ad614SDennis Dalessandro } 4630f48ad614SDennis Dalessandro 4631f48ad614SDennis Dalessandro ret = check_mkey(ibp, (struct ib_mad_hdr *)smp, mad_flags, 4632f48ad614SDennis Dalessandro smp->mkey, (__force __be32)smp->dr_slid, 4633f48ad614SDennis Dalessandro smp->return_path, smp->hop_cnt); 4634f48ad614SDennis Dalessandro if (ret) { 4635f48ad614SDennis Dalessandro u32 port_num = be32_to_cpu(smp->attr_mod); 4636f48ad614SDennis Dalessandro 4637f48ad614SDennis Dalessandro /* 4638f48ad614SDennis Dalessandro * If this is a get/set portinfo, we already check the 4639f48ad614SDennis Dalessandro * M_Key if the MAD is for another port and the M_Key 4640f48ad614SDennis Dalessandro * is OK on the receiving port. This check is needed 4641f48ad614SDennis Dalessandro * to increment the error counters when the M_Key 4642f48ad614SDennis Dalessandro * fails to match on *both* ports. 4643f48ad614SDennis Dalessandro */ 4644f48ad614SDennis Dalessandro if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && 4645f48ad614SDennis Dalessandro (smp->method == IB_MGMT_METHOD_GET || 4646f48ad614SDennis Dalessandro smp->method == IB_MGMT_METHOD_SET) && 4647f48ad614SDennis Dalessandro port_num && port_num <= ibdev->phys_port_cnt && 4648f48ad614SDennis Dalessandro port != port_num) 4649f48ad614SDennis Dalessandro (void)check_mkey(to_iport(ibdev, port_num), 4650f48ad614SDennis Dalessandro (struct ib_mad_hdr *)smp, 0, 4651f48ad614SDennis Dalessandro smp->mkey, 4652f48ad614SDennis Dalessandro (__force __be32)smp->dr_slid, 4653f48ad614SDennis Dalessandro smp->return_path, smp->hop_cnt); 4654f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_FAILURE; 4655f48ad614SDennis Dalessandro return ret; 4656f48ad614SDennis Dalessandro } 4657f48ad614SDennis Dalessandro 4658f48ad614SDennis Dalessandro switch (smp->method) { 4659f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 4660f48ad614SDennis Dalessandro switch (smp->attr_id) { 4661f48ad614SDennis Dalessandro case IB_SMP_ATTR_NODE_INFO: 4662f48ad614SDennis Dalessandro ret = subn_get_nodeinfo(smp, ibdev, port); 4663f48ad614SDennis Dalessandro break; 4664f48ad614SDennis Dalessandro default: 4665f48ad614SDennis Dalessandro smp->status |= IB_SMP_UNSUP_METH_ATTR; 4666f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)smp); 4667f48ad614SDennis Dalessandro break; 4668f48ad614SDennis Dalessandro } 4669f48ad614SDennis Dalessandro break; 4670f48ad614SDennis Dalessandro } 4671f48ad614SDennis Dalessandro 4672f48ad614SDennis Dalessandro return ret; 4673f48ad614SDennis Dalessandro } 4674f48ad614SDennis Dalessandro 4675f48ad614SDennis Dalessandro static int process_perf(struct ib_device *ibdev, u8 port, 4676f48ad614SDennis Dalessandro const struct ib_mad *in_mad, 4677f48ad614SDennis Dalessandro struct ib_mad *out_mad) 4678f48ad614SDennis Dalessandro { 4679f48ad614SDennis Dalessandro struct ib_pma_mad *pmp = (struct ib_pma_mad *)out_mad; 4680f48ad614SDennis Dalessandro struct ib_class_port_info *cpi = (struct ib_class_port_info *) 4681f48ad614SDennis Dalessandro &pmp->data; 4682f48ad614SDennis Dalessandro int ret = IB_MAD_RESULT_FAILURE; 4683f48ad614SDennis Dalessandro 4684f48ad614SDennis Dalessandro *out_mad = *in_mad; 4685f48ad614SDennis Dalessandro if (pmp->mad_hdr.class_version != 1) { 4686f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_VERSION; 4687f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4688f48ad614SDennis Dalessandro return ret; 4689f48ad614SDennis Dalessandro } 4690f48ad614SDennis Dalessandro 4691f48ad614SDennis Dalessandro switch (pmp->mad_hdr.method) { 4692f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 4693f48ad614SDennis Dalessandro switch (pmp->mad_hdr.attr_id) { 4694f48ad614SDennis Dalessandro case IB_PMA_PORT_COUNTERS: 4695f48ad614SDennis Dalessandro ret = pma_get_ib_portcounters(pmp, ibdev, port); 4696f48ad614SDennis Dalessandro break; 4697f48ad614SDennis Dalessandro case IB_PMA_PORT_COUNTERS_EXT: 4698f48ad614SDennis Dalessandro ret = pma_get_ib_portcounters_ext(pmp, ibdev, port); 4699f48ad614SDennis Dalessandro break; 4700f48ad614SDennis Dalessandro case IB_PMA_CLASS_PORT_INFO: 4701f48ad614SDennis Dalessandro cpi->capability_mask = IB_PMA_CLASS_CAP_EXT_WIDTH; 4702f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4703f48ad614SDennis Dalessandro break; 4704f48ad614SDennis Dalessandro default: 4705f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; 4706f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4707f48ad614SDennis Dalessandro break; 4708f48ad614SDennis Dalessandro } 4709f48ad614SDennis Dalessandro break; 4710f48ad614SDennis Dalessandro 4711f48ad614SDennis Dalessandro case IB_MGMT_METHOD_SET: 4712f48ad614SDennis Dalessandro if (pmp->mad_hdr.attr_id) { 4713f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; 4714f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4715f48ad614SDennis Dalessandro } 4716f48ad614SDennis Dalessandro break; 4717f48ad614SDennis Dalessandro 4718f48ad614SDennis Dalessandro case IB_MGMT_METHOD_TRAP: 4719f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET_RESP: 4720f48ad614SDennis Dalessandro /* 4721f48ad614SDennis Dalessandro * The ib_mad module will call us to process responses 4722f48ad614SDennis Dalessandro * before checking for other consumers. 4723f48ad614SDennis Dalessandro * Just tell the caller to process it normally. 4724f48ad614SDennis Dalessandro */ 4725f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4726f48ad614SDennis Dalessandro break; 4727f48ad614SDennis Dalessandro 4728f48ad614SDennis Dalessandro default: 4729f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METHOD; 4730f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4731f48ad614SDennis Dalessandro break; 4732f48ad614SDennis Dalessandro } 4733f48ad614SDennis Dalessandro 4734f48ad614SDennis Dalessandro return ret; 4735f48ad614SDennis Dalessandro } 4736f48ad614SDennis Dalessandro 4737f48ad614SDennis Dalessandro static int process_perf_opa(struct ib_device *ibdev, u8 port, 4738f48ad614SDennis Dalessandro const struct opa_mad *in_mad, 4739f48ad614SDennis Dalessandro struct opa_mad *out_mad, u32 *resp_len) 4740f48ad614SDennis Dalessandro { 4741f48ad614SDennis Dalessandro struct opa_pma_mad *pmp = (struct opa_pma_mad *)out_mad; 4742f48ad614SDennis Dalessandro int ret; 4743f48ad614SDennis Dalessandro 4744f48ad614SDennis Dalessandro *out_mad = *in_mad; 4745f48ad614SDennis Dalessandro 47469fa240bbSHal Rosenstock if (pmp->mad_hdr.class_version != OPA_SM_CLASS_VERSION) { 4747f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_VERSION; 4748f48ad614SDennis Dalessandro return reply((struct ib_mad_hdr *)pmp); 4749f48ad614SDennis Dalessandro } 4750f48ad614SDennis Dalessandro 4751f48ad614SDennis Dalessandro *resp_len = sizeof(pmp->mad_hdr); 4752f48ad614SDennis Dalessandro 4753f48ad614SDennis Dalessandro switch (pmp->mad_hdr.method) { 4754f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET: 4755f48ad614SDennis Dalessandro switch (pmp->mad_hdr.attr_id) { 4756f48ad614SDennis Dalessandro case IB_PMA_CLASS_PORT_INFO: 4757f48ad614SDennis Dalessandro ret = pma_get_opa_classportinfo(pmp, ibdev, resp_len); 4758f48ad614SDennis Dalessandro break; 4759f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_PORT_STATUS: 4760f48ad614SDennis Dalessandro ret = pma_get_opa_portstatus(pmp, ibdev, port, 4761f48ad614SDennis Dalessandro resp_len); 4762f48ad614SDennis Dalessandro break; 4763f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_DATA_PORT_COUNTERS: 4764f48ad614SDennis Dalessandro ret = pma_get_opa_datacounters(pmp, ibdev, port, 4765f48ad614SDennis Dalessandro resp_len); 4766f48ad614SDennis Dalessandro break; 4767f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_ERROR_PORT_COUNTERS: 4768f48ad614SDennis Dalessandro ret = pma_get_opa_porterrors(pmp, ibdev, port, 4769f48ad614SDennis Dalessandro resp_len); 4770f48ad614SDennis Dalessandro break; 4771f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_ERROR_INFO: 4772f48ad614SDennis Dalessandro ret = pma_get_opa_errorinfo(pmp, ibdev, port, 4773f48ad614SDennis Dalessandro resp_len); 4774f48ad614SDennis Dalessandro break; 4775f48ad614SDennis Dalessandro default: 4776f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; 4777f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4778f48ad614SDennis Dalessandro break; 4779f48ad614SDennis Dalessandro } 4780f48ad614SDennis Dalessandro break; 4781f48ad614SDennis Dalessandro 4782f48ad614SDennis Dalessandro case IB_MGMT_METHOD_SET: 4783f48ad614SDennis Dalessandro switch (pmp->mad_hdr.attr_id) { 4784f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_CLEAR_PORT_STATUS: 4785f48ad614SDennis Dalessandro ret = pma_set_opa_portstatus(pmp, ibdev, port, 4786f48ad614SDennis Dalessandro resp_len); 4787f48ad614SDennis Dalessandro break; 4788f48ad614SDennis Dalessandro case OPA_PM_ATTRIB_ID_ERROR_INFO: 4789f48ad614SDennis Dalessandro ret = pma_set_opa_errorinfo(pmp, ibdev, port, 4790f48ad614SDennis Dalessandro resp_len); 4791f48ad614SDennis Dalessandro break; 4792f48ad614SDennis Dalessandro default: 4793f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; 4794f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4795f48ad614SDennis Dalessandro break; 4796f48ad614SDennis Dalessandro } 4797f48ad614SDennis Dalessandro break; 4798f48ad614SDennis Dalessandro 4799f48ad614SDennis Dalessandro case IB_MGMT_METHOD_TRAP: 4800f48ad614SDennis Dalessandro case IB_MGMT_METHOD_GET_RESP: 4801f48ad614SDennis Dalessandro /* 4802f48ad614SDennis Dalessandro * The ib_mad module will call us to process responses 4803f48ad614SDennis Dalessandro * before checking for other consumers. 4804f48ad614SDennis Dalessandro * Just tell the caller to process it normally. 4805f48ad614SDennis Dalessandro */ 4806f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4807f48ad614SDennis Dalessandro break; 4808f48ad614SDennis Dalessandro 4809f48ad614SDennis Dalessandro default: 4810f48ad614SDennis Dalessandro pmp->mad_hdr.status |= IB_SMP_UNSUP_METHOD; 4811f48ad614SDennis Dalessandro ret = reply((struct ib_mad_hdr *)pmp); 4812f48ad614SDennis Dalessandro break; 4813f48ad614SDennis Dalessandro } 4814f48ad614SDennis Dalessandro 4815f48ad614SDennis Dalessandro return ret; 4816f48ad614SDennis Dalessandro } 4817f48ad614SDennis Dalessandro 4818f48ad614SDennis Dalessandro static int hfi1_process_opa_mad(struct ib_device *ibdev, int mad_flags, 4819f48ad614SDennis Dalessandro u8 port, const struct ib_wc *in_wc, 4820f48ad614SDennis Dalessandro const struct ib_grh *in_grh, 4821f48ad614SDennis Dalessandro const struct opa_mad *in_mad, 4822f48ad614SDennis Dalessandro struct opa_mad *out_mad, size_t *out_mad_size, 4823f48ad614SDennis Dalessandro u16 *out_mad_pkey_index) 4824f48ad614SDennis Dalessandro { 4825f48ad614SDennis Dalessandro int ret; 4826f48ad614SDennis Dalessandro int pkey_idx; 4827959f2d17SAlex Estrin int local_mad = 0; 4828935c84acSMichael J. Ruhl u32 resp_len = in_wc->byte_len - sizeof(*in_grh); 4829f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = to_iport(ibdev, port); 4830f48ad614SDennis Dalessandro 4831f48ad614SDennis Dalessandro pkey_idx = hfi1_lookup_pkey_idx(ibp, LIM_MGMT_P_KEY); 4832f48ad614SDennis Dalessandro if (pkey_idx < 0) { 4833f48ad614SDennis Dalessandro pr_warn("failed to find limited mgmt pkey, defaulting 0x%x\n", 4834f48ad614SDennis Dalessandro hfi1_get_pkey(ibp, 1)); 4835f48ad614SDennis Dalessandro pkey_idx = 1; 4836f48ad614SDennis Dalessandro } 4837f48ad614SDennis Dalessandro *out_mad_pkey_index = (u16)pkey_idx; 4838f48ad614SDennis Dalessandro 4839f48ad614SDennis Dalessandro switch (in_mad->mad_hdr.mgmt_class) { 4840f48ad614SDennis Dalessandro case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: 4841f48ad614SDennis Dalessandro case IB_MGMT_CLASS_SUBN_LID_ROUTED: 4842959f2d17SAlex Estrin local_mad = is_local_mad(ibp, in_mad, in_wc); 4843959f2d17SAlex Estrin if (local_mad) { 4844f48ad614SDennis Dalessandro ret = opa_local_smp_check(ibp, in_wc); 4845f48ad614SDennis Dalessandro if (ret) 4846f48ad614SDennis Dalessandro return IB_MAD_RESULT_FAILURE; 4847f48ad614SDennis Dalessandro } 4848f48ad614SDennis Dalessandro ret = process_subn_opa(ibdev, mad_flags, port, in_mad, 4849959f2d17SAlex Estrin out_mad, &resp_len, local_mad); 4850f48ad614SDennis Dalessandro goto bail; 4851f48ad614SDennis Dalessandro case IB_MGMT_CLASS_PERF_MGMT: 4852406310c6SSebastian Sanchez ret = hfi1_pkey_validation_pma(ibp, in_mad, in_wc); 4853406310c6SSebastian Sanchez if (ret) 4854406310c6SSebastian Sanchez return IB_MAD_RESULT_FAILURE; 4855406310c6SSebastian Sanchez 4856406310c6SSebastian Sanchez ret = process_perf_opa(ibdev, port, in_mad, out_mad, &resp_len); 4857f48ad614SDennis Dalessandro goto bail; 4858f48ad614SDennis Dalessandro 4859f48ad614SDennis Dalessandro default: 4860f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4861f48ad614SDennis Dalessandro } 4862f48ad614SDennis Dalessandro 4863f48ad614SDennis Dalessandro bail: 4864f48ad614SDennis Dalessandro if (ret & IB_MAD_RESULT_REPLY) 4865f48ad614SDennis Dalessandro *out_mad_size = round_up(resp_len, 8); 4866f48ad614SDennis Dalessandro else if (ret & IB_MAD_RESULT_SUCCESS) 4867f48ad614SDennis Dalessandro *out_mad_size = in_wc->byte_len - sizeof(struct ib_grh); 4868f48ad614SDennis Dalessandro 4869f48ad614SDennis Dalessandro return ret; 4870f48ad614SDennis Dalessandro } 4871f48ad614SDennis Dalessandro 4872f48ad614SDennis Dalessandro static int hfi1_process_ib_mad(struct ib_device *ibdev, int mad_flags, u8 port, 4873f48ad614SDennis Dalessandro const struct ib_wc *in_wc, 4874f48ad614SDennis Dalessandro const struct ib_grh *in_grh, 4875f48ad614SDennis Dalessandro const struct ib_mad *in_mad, 4876f48ad614SDennis Dalessandro struct ib_mad *out_mad) 4877f48ad614SDennis Dalessandro { 4878f48ad614SDennis Dalessandro int ret; 4879f48ad614SDennis Dalessandro 4880f48ad614SDennis Dalessandro switch (in_mad->mad_hdr.mgmt_class) { 4881f48ad614SDennis Dalessandro case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: 4882f48ad614SDennis Dalessandro case IB_MGMT_CLASS_SUBN_LID_ROUTED: 4883f48ad614SDennis Dalessandro ret = process_subn(ibdev, mad_flags, port, in_mad, out_mad); 4884f48ad614SDennis Dalessandro break; 4885f48ad614SDennis Dalessandro case IB_MGMT_CLASS_PERF_MGMT: 4886f48ad614SDennis Dalessandro ret = process_perf(ibdev, port, in_mad, out_mad); 4887f48ad614SDennis Dalessandro break; 4888f48ad614SDennis Dalessandro default: 4889f48ad614SDennis Dalessandro ret = IB_MAD_RESULT_SUCCESS; 4890f48ad614SDennis Dalessandro break; 4891f48ad614SDennis Dalessandro } 4892f48ad614SDennis Dalessandro 4893f48ad614SDennis Dalessandro return ret; 4894f48ad614SDennis Dalessandro } 4895f48ad614SDennis Dalessandro 4896f48ad614SDennis Dalessandro /** 4897f48ad614SDennis Dalessandro * hfi1_process_mad - process an incoming MAD packet 4898f48ad614SDennis Dalessandro * @ibdev: the infiniband device this packet came in on 4899f48ad614SDennis Dalessandro * @mad_flags: MAD flags 4900f48ad614SDennis Dalessandro * @port: the port number this packet came in on 4901f48ad614SDennis Dalessandro * @in_wc: the work completion entry for this packet 4902f48ad614SDennis Dalessandro * @in_grh: the global route header for this packet 4903f48ad614SDennis Dalessandro * @in_mad: the incoming MAD 4904f48ad614SDennis Dalessandro * @out_mad: any outgoing MAD reply 4905*29f7e5a3SLee Jones * @out_mad_size: size of the outgoing MAD reply 4906*29f7e5a3SLee Jones * @out_mad_pkey_index: used to apss back the packet key index 4907f48ad614SDennis Dalessandro * 4908f48ad614SDennis Dalessandro * Returns IB_MAD_RESULT_SUCCESS if this is a MAD that we are not 4909f48ad614SDennis Dalessandro * interested in processing. 4910f48ad614SDennis Dalessandro * 4911f48ad614SDennis Dalessandro * Note that the verbs framework has already done the MAD sanity checks, 4912f48ad614SDennis Dalessandro * and hop count/pointer updating for IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 4913f48ad614SDennis Dalessandro * MADs. 4914f48ad614SDennis Dalessandro * 4915f48ad614SDennis Dalessandro * This is called by the ib_mad module. 4916f48ad614SDennis Dalessandro */ 4917f48ad614SDennis Dalessandro int hfi1_process_mad(struct ib_device *ibdev, int mad_flags, u8 port, 4918f48ad614SDennis Dalessandro const struct ib_wc *in_wc, const struct ib_grh *in_grh, 4919e26e7b88SLeon Romanovsky const struct ib_mad *in_mad, struct ib_mad *out_mad, 4920e26e7b88SLeon Romanovsky size_t *out_mad_size, u16 *out_mad_pkey_index) 4921f48ad614SDennis Dalessandro { 4922e26e7b88SLeon Romanovsky switch (in_mad->mad_hdr.base_version) { 4923f48ad614SDennis Dalessandro case OPA_MGMT_BASE_VERSION: 4924f48ad614SDennis Dalessandro return hfi1_process_opa_mad(ibdev, mad_flags, port, 4925f48ad614SDennis Dalessandro in_wc, in_grh, 4926f48ad614SDennis Dalessandro (struct opa_mad *)in_mad, 4927f48ad614SDennis Dalessandro (struct opa_mad *)out_mad, 4928f48ad614SDennis Dalessandro out_mad_size, 4929f48ad614SDennis Dalessandro out_mad_pkey_index); 4930f48ad614SDennis Dalessandro case IB_MGMT_BASE_VERSION: 4931e26e7b88SLeon Romanovsky return hfi1_process_ib_mad(ibdev, mad_flags, port, in_wc, 4932e26e7b88SLeon Romanovsky in_grh, in_mad, out_mad); 4933f48ad614SDennis Dalessandro default: 4934f48ad614SDennis Dalessandro break; 4935f48ad614SDennis Dalessandro } 4936f48ad614SDennis Dalessandro 4937f48ad614SDennis Dalessandro return IB_MAD_RESULT_FAILURE; 4938f48ad614SDennis Dalessandro } 4939