18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright(c) 2015-2020 Intel Corporation. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 58c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 148c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 168c2ecf20Sopenharmony_ci * General Public License for more details. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * BSD LICENSE 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 218c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 228c2ecf20Sopenharmony_ci * are met: 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above copyright 258c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 268c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above copyright 278c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 288c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 298c2ecf20Sopenharmony_ci * distribution. 308c2ecf20Sopenharmony_ci * - Neither the name of Intel Corporation nor the names of its 318c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 328c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 358c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 368c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 378c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 388c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 398c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 408c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 418c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 428c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 438c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 448c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 498c2ecf20Sopenharmony_ci#include <linux/pci.h> 508c2ecf20Sopenharmony_ci#include <linux/io.h> 518c2ecf20Sopenharmony_ci#include <linux/delay.h> 528c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 538c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 548c2ecf20Sopenharmony_ci#include <linux/module.h> 558c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 568c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 578c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#include "hfi.h" 608c2ecf20Sopenharmony_ci#include "trace.h" 618c2ecf20Sopenharmony_ci#include "qp.h" 628c2ecf20Sopenharmony_ci#include "sdma.h" 638c2ecf20Sopenharmony_ci#include "debugfs.h" 648c2ecf20Sopenharmony_ci#include "vnic.h" 658c2ecf20Sopenharmony_ci#include "fault.h" 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#include "ipoib.h" 688c2ecf20Sopenharmony_ci#include "netdev.h" 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#undef pr_fmt 718c2ecf20Sopenharmony_ci#define pr_fmt(fmt) DRIVER_NAME ": " fmt 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * The size has to be longer than this string, so we can append 758c2ecf20Sopenharmony_ci * board/chip information to it in the initialization code. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ciconst char ib_hfi1_version[] = HFI1_DRIVER_VERSION "\n"; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciDEFINE_MUTEX(hfi1_mutex); /* general driver use */ 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ciunsigned int hfi1_max_mtu = HFI1_DEFAULT_MAX_MTU; 828c2ecf20Sopenharmony_cimodule_param_named(max_mtu, hfi1_max_mtu, uint, S_IRUGO); 838c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_mtu, "Set max MTU bytes, default is " __stringify( 848c2ecf20Sopenharmony_ci HFI1_DEFAULT_MAX_MTU)); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciunsigned int hfi1_cu = 1; 878c2ecf20Sopenharmony_cimodule_param_named(cu, hfi1_cu, uint, S_IRUGO); 888c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cu, "Credit return units"); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ciunsigned long hfi1_cap_mask = HFI1_CAP_MASK_DEFAULT; 918c2ecf20Sopenharmony_cistatic int hfi1_caps_set(const char *val, const struct kernel_param *kp); 928c2ecf20Sopenharmony_cistatic int hfi1_caps_get(char *buffer, const struct kernel_param *kp); 938c2ecf20Sopenharmony_cistatic const struct kernel_param_ops cap_ops = { 948c2ecf20Sopenharmony_ci .set = hfi1_caps_set, 958c2ecf20Sopenharmony_ci .get = hfi1_caps_get 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_cimodule_param_cb(cap_mask, &cap_ops, &hfi1_cap_mask, S_IWUSR | S_IRUGO); 988c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cap_mask, "Bit mask of enabled/disabled HW features"); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 1018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel Omni-Path Architecture driver"); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * MAX_PKT_RCV is the max # if packets processed per receive interrupt. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ci#define MAX_PKT_RECV 64 1078c2ecf20Sopenharmony_ci/* 1088c2ecf20Sopenharmony_ci * MAX_PKT_THREAD_RCV is the max # of packets processed before 1098c2ecf20Sopenharmony_ci * the qp_wait_list queue is flushed. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci#define MAX_PKT_RECV_THREAD (MAX_PKT_RECV * 4) 1128c2ecf20Sopenharmony_ci#define EGR_HEAD_UPDATE_THRESHOLD 16 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistruct hfi1_ib_stats hfi1_stats; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int hfi1_caps_set(const char *val, const struct kernel_param *kp) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int ret = 0; 1198c2ecf20Sopenharmony_ci unsigned long *cap_mask_ptr = (unsigned long *)kp->arg, 1208c2ecf20Sopenharmony_ci cap_mask = *cap_mask_ptr, value, diff, 1218c2ecf20Sopenharmony_ci write_mask = ((HFI1_CAP_WRITABLE_MASK << HFI1_CAP_USER_SHIFT) | 1228c2ecf20Sopenharmony_ci HFI1_CAP_WRITABLE_MASK); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci ret = kstrtoul(val, 0, &value); 1258c2ecf20Sopenharmony_ci if (ret) { 1268c2ecf20Sopenharmony_ci pr_warn("Invalid module parameter value for 'cap_mask'\n"); 1278c2ecf20Sopenharmony_ci goto done; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci /* Get the changed bits (except the locked bit) */ 1308c2ecf20Sopenharmony_ci diff = value ^ (cap_mask & ~HFI1_CAP_LOCKED_SMASK); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Remove any bits that are not allowed to change after driver load */ 1338c2ecf20Sopenharmony_ci if (HFI1_CAP_LOCKED() && (diff & ~write_mask)) { 1348c2ecf20Sopenharmony_ci pr_warn("Ignoring non-writable capability bits %#lx\n", 1358c2ecf20Sopenharmony_ci diff & ~write_mask); 1368c2ecf20Sopenharmony_ci diff &= write_mask; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Mask off any reserved bits */ 1408c2ecf20Sopenharmony_ci diff &= ~HFI1_CAP_RESERVED_MASK; 1418c2ecf20Sopenharmony_ci /* Clear any previously set and changing bits */ 1428c2ecf20Sopenharmony_ci cap_mask &= ~diff; 1438c2ecf20Sopenharmony_ci /* Update the bits with the new capability */ 1448c2ecf20Sopenharmony_ci cap_mask |= (value & diff); 1458c2ecf20Sopenharmony_ci /* Check for any kernel/user restrictions */ 1468c2ecf20Sopenharmony_ci diff = (cap_mask & (HFI1_CAP_MUST_HAVE_KERN << HFI1_CAP_USER_SHIFT)) ^ 1478c2ecf20Sopenharmony_ci ((cap_mask & HFI1_CAP_MUST_HAVE_KERN) << HFI1_CAP_USER_SHIFT); 1488c2ecf20Sopenharmony_ci cap_mask &= ~diff; 1498c2ecf20Sopenharmony_ci /* Set the bitmask to the final set */ 1508c2ecf20Sopenharmony_ci *cap_mask_ptr = cap_mask; 1518c2ecf20Sopenharmony_cidone: 1528c2ecf20Sopenharmony_ci return ret; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int hfi1_caps_get(char *buffer, const struct kernel_param *kp) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci unsigned long cap_mask = *(unsigned long *)kp->arg; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci cap_mask &= ~HFI1_CAP_LOCKED_SMASK; 1608c2ecf20Sopenharmony_ci cap_mask |= ((cap_mask & HFI1_CAP_K2U) << HFI1_CAP_USER_SHIFT); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return scnprintf(buffer, PAGE_SIZE, "0x%lx", cap_mask); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistruct pci_dev *get_pci_dev(struct rvt_dev_info *rdi) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct hfi1_ibdev *ibdev = container_of(rdi, struct hfi1_ibdev, rdi); 1688c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = container_of(ibdev, 1698c2ecf20Sopenharmony_ci struct hfi1_devdata, verbs_dev); 1708c2ecf20Sopenharmony_ci return dd->pcidev; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* 1748c2ecf20Sopenharmony_ci * Return count of units with at least one port ACTIVE. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ciint hfi1_count_active_units(void) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct hfi1_devdata *dd; 1798c2ecf20Sopenharmony_ci struct hfi1_pportdata *ppd; 1808c2ecf20Sopenharmony_ci unsigned long index, flags; 1818c2ecf20Sopenharmony_ci int pidx, nunits_active = 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci xa_lock_irqsave(&hfi1_dev_table, flags); 1848c2ecf20Sopenharmony_ci xa_for_each(&hfi1_dev_table, index, dd) { 1858c2ecf20Sopenharmony_ci if (!(dd->flags & HFI1_PRESENT) || !dd->kregbase1) 1868c2ecf20Sopenharmony_ci continue; 1878c2ecf20Sopenharmony_ci for (pidx = 0; pidx < dd->num_pports; ++pidx) { 1888c2ecf20Sopenharmony_ci ppd = dd->pport + pidx; 1898c2ecf20Sopenharmony_ci if (ppd->lid && ppd->linkup) { 1908c2ecf20Sopenharmony_ci nunits_active++; 1918c2ecf20Sopenharmony_ci break; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci xa_unlock_irqrestore(&hfi1_dev_table, flags); 1968c2ecf20Sopenharmony_ci return nunits_active; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* 2008c2ecf20Sopenharmony_ci * Get address of eager buffer from it's index (allocated in chunks, not 2018c2ecf20Sopenharmony_ci * contiguous). 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_cistatic inline void *get_egrbuf(const struct hfi1_ctxtdata *rcd, u64 rhf, 2048c2ecf20Sopenharmony_ci u8 *update) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci u32 idx = rhf_egr_index(rhf), offset = rhf_egr_buf_offset(rhf); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci *update |= !(idx & (rcd->egrbufs.threshold - 1)) && !offset; 2098c2ecf20Sopenharmony_ci return (void *)(((u64)(rcd->egrbufs.rcvtids[idx].addr)) + 2108c2ecf20Sopenharmony_ci (offset * RCV_BUF_BLOCK_SIZE)); 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic inline void *hfi1_get_header(struct hfi1_ctxtdata *rcd, 2148c2ecf20Sopenharmony_ci __le32 *rhf_addr) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci u32 offset = rhf_hdrq_offset(rhf_to_cpu(rhf_addr)); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return (void *)(rhf_addr - rcd->rhf_offset + offset); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic inline struct ib_header *hfi1_get_msgheader(struct hfi1_ctxtdata *rcd, 2228c2ecf20Sopenharmony_ci __le32 *rhf_addr) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci return (struct ib_header *)hfi1_get_header(rcd, rhf_addr); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic inline struct hfi1_16b_header 2288c2ecf20Sopenharmony_ci *hfi1_get_16B_header(struct hfi1_ctxtdata *rcd, 2298c2ecf20Sopenharmony_ci __le32 *rhf_addr) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci return (struct hfi1_16b_header *)hfi1_get_header(rcd, rhf_addr); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* 2358c2ecf20Sopenharmony_ci * Validate and encode the a given RcvArray Buffer size. 2368c2ecf20Sopenharmony_ci * The function will check whether the given size falls within 2378c2ecf20Sopenharmony_ci * allowed size ranges for the respective type and, optionally, 2388c2ecf20Sopenharmony_ci * return the proper encoding. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ciint hfi1_rcvbuf_validate(u32 size, u8 type, u16 *encoded) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci if (unlikely(!PAGE_ALIGNED(size))) 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci if (unlikely(size < MIN_EAGER_BUFFER)) 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci if (size > 2478c2ecf20Sopenharmony_ci (type == PT_EAGER ? MAX_EAGER_BUFFER : MAX_EXPECTED_BUFFER)) 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci if (encoded) 2508c2ecf20Sopenharmony_ci *encoded = ilog2(size / PAGE_SIZE) + 1; 2518c2ecf20Sopenharmony_ci return 1; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, 2558c2ecf20Sopenharmony_ci struct hfi1_packet *packet) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct ib_header *rhdr = packet->hdr; 2588c2ecf20Sopenharmony_ci u32 rte = rhf_rcv_type_err(packet->rhf); 2598c2ecf20Sopenharmony_ci u32 mlid_base; 2608c2ecf20Sopenharmony_ci struct hfi1_ibport *ibp = rcd_to_iport(rcd); 2618c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 2628c2ecf20Sopenharmony_ci struct hfi1_ibdev *verbs_dev = &dd->verbs_dev; 2638c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = &verbs_dev->rdi; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if ((packet->rhf & RHF_DC_ERR) && 2668c2ecf20Sopenharmony_ci hfi1_dbg_fault_suppress_err(verbs_dev)) 2678c2ecf20Sopenharmony_ci return; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (packet->rhf & RHF_ICRC_ERR) 2708c2ecf20Sopenharmony_ci return; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (packet->etype == RHF_RCV_TYPE_BYPASS) { 2738c2ecf20Sopenharmony_ci goto drop; 2748c2ecf20Sopenharmony_ci } else { 2758c2ecf20Sopenharmony_ci u8 lnh = ib_get_lnh(rhdr); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci mlid_base = be16_to_cpu(IB_MULTICAST_LID_BASE); 2788c2ecf20Sopenharmony_ci if (lnh == HFI1_LRH_BTH) { 2798c2ecf20Sopenharmony_ci packet->ohdr = &rhdr->u.oth; 2808c2ecf20Sopenharmony_ci } else if (lnh == HFI1_LRH_GRH) { 2818c2ecf20Sopenharmony_ci packet->ohdr = &rhdr->u.l.oth; 2828c2ecf20Sopenharmony_ci packet->grh = &rhdr->u.l.grh; 2838c2ecf20Sopenharmony_ci } else { 2848c2ecf20Sopenharmony_ci goto drop; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (packet->rhf & RHF_TID_ERR) { 2898c2ecf20Sopenharmony_ci /* For TIDERR and RC QPs preemptively schedule a NAK */ 2908c2ecf20Sopenharmony_ci u32 tlen = rhf_pkt_len(packet->rhf); /* in bytes */ 2918c2ecf20Sopenharmony_ci u32 dlid = ib_get_dlid(rhdr); 2928c2ecf20Sopenharmony_ci u32 qp_num; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Sanity check packet */ 2958c2ecf20Sopenharmony_ci if (tlen < 24) 2968c2ecf20Sopenharmony_ci goto drop; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Check for GRH */ 2998c2ecf20Sopenharmony_ci if (packet->grh) { 3008c2ecf20Sopenharmony_ci u32 vtf; 3018c2ecf20Sopenharmony_ci struct ib_grh *grh = packet->grh; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (grh->next_hdr != IB_GRH_NEXT_HDR) 3048c2ecf20Sopenharmony_ci goto drop; 3058c2ecf20Sopenharmony_ci vtf = be32_to_cpu(grh->version_tclass_flow); 3068c2ecf20Sopenharmony_ci if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) 3078c2ecf20Sopenharmony_ci goto drop; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Get the destination QP number. */ 3118c2ecf20Sopenharmony_ci qp_num = ib_bth_get_qpn(packet->ohdr); 3128c2ecf20Sopenharmony_ci if (dlid < mlid_base) { 3138c2ecf20Sopenharmony_ci struct rvt_qp *qp; 3148c2ecf20Sopenharmony_ci unsigned long flags; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci rcu_read_lock(); 3178c2ecf20Sopenharmony_ci qp = rvt_lookup_qpn(rdi, &ibp->rvp, qp_num); 3188c2ecf20Sopenharmony_ci if (!qp) { 3198c2ecf20Sopenharmony_ci rcu_read_unlock(); 3208c2ecf20Sopenharmony_ci goto drop; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* 3248c2ecf20Sopenharmony_ci * Handle only RC QPs - for other QP types drop error 3258c2ecf20Sopenharmony_ci * packet. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->r_lock, flags); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Check for valid receive state. */ 3308c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & 3318c2ecf20Sopenharmony_ci RVT_PROCESS_RECV_OK)) { 3328c2ecf20Sopenharmony_ci ibp->rvp.n_pkt_drops++; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci switch (qp->ibqp.qp_type) { 3368c2ecf20Sopenharmony_ci case IB_QPT_RC: 3378c2ecf20Sopenharmony_ci hfi1_rc_hdrerr(rcd, packet, qp); 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci default: 3408c2ecf20Sopenharmony_ci /* For now don't handle any other QP types */ 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 3458c2ecf20Sopenharmony_ci rcu_read_unlock(); 3468c2ecf20Sopenharmony_ci } /* Unicast QP */ 3478c2ecf20Sopenharmony_ci } /* Valid packet with TIDErr */ 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* handle "RcvTypeErr" flags */ 3508c2ecf20Sopenharmony_ci switch (rte) { 3518c2ecf20Sopenharmony_ci case RHF_RTE_ERROR_OP_CODE_ERR: 3528c2ecf20Sopenharmony_ci { 3538c2ecf20Sopenharmony_ci void *ebuf = NULL; 3548c2ecf20Sopenharmony_ci u8 opcode; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (rhf_use_egr_bfr(packet->rhf)) 3578c2ecf20Sopenharmony_ci ebuf = packet->ebuf; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (!ebuf) 3608c2ecf20Sopenharmony_ci goto drop; /* this should never happen */ 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci opcode = ib_bth_get_opcode(packet->ohdr); 3638c2ecf20Sopenharmony_ci if (opcode == IB_OPCODE_CNP) { 3648c2ecf20Sopenharmony_ci /* 3658c2ecf20Sopenharmony_ci * Only in pre-B0 h/w is the CNP_OPCODE handled 3668c2ecf20Sopenharmony_ci * via this code path. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci struct rvt_qp *qp = NULL; 3698c2ecf20Sopenharmony_ci u32 lqpn, rqpn; 3708c2ecf20Sopenharmony_ci u16 rlid; 3718c2ecf20Sopenharmony_ci u8 svc_type, sl, sc5; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci sc5 = hfi1_9B_get_sc5(rhdr, packet->rhf); 3748c2ecf20Sopenharmony_ci sl = ibp->sc_to_sl[sc5]; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci lqpn = ib_bth_get_qpn(packet->ohdr); 3778c2ecf20Sopenharmony_ci rcu_read_lock(); 3788c2ecf20Sopenharmony_ci qp = rvt_lookup_qpn(rdi, &ibp->rvp, lqpn); 3798c2ecf20Sopenharmony_ci if (!qp) { 3808c2ecf20Sopenharmony_ci rcu_read_unlock(); 3818c2ecf20Sopenharmony_ci goto drop; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci switch (qp->ibqp.qp_type) { 3858c2ecf20Sopenharmony_ci case IB_QPT_UD: 3868c2ecf20Sopenharmony_ci rlid = 0; 3878c2ecf20Sopenharmony_ci rqpn = 0; 3888c2ecf20Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UD; 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci case IB_QPT_UC: 3918c2ecf20Sopenharmony_ci rlid = ib_get_slid(rhdr); 3928c2ecf20Sopenharmony_ci rqpn = qp->remote_qpn; 3938c2ecf20Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UC; 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci default: 3968c2ecf20Sopenharmony_ci rcu_read_unlock(); 3978c2ecf20Sopenharmony_ci goto drop; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type); 4018c2ecf20Sopenharmony_ci rcu_read_unlock(); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci packet->rhf &= ~RHF_RCV_TYPE_ERR_SMASK; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci default: 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cidrop: 4128c2ecf20Sopenharmony_ci return; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic inline void init_packet(struct hfi1_ctxtdata *rcd, 4168c2ecf20Sopenharmony_ci struct hfi1_packet *packet) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci packet->rsize = get_hdrqentsize(rcd); /* words */ 4198c2ecf20Sopenharmony_ci packet->maxcnt = get_hdrq_cnt(rcd) * packet->rsize; /* words */ 4208c2ecf20Sopenharmony_ci packet->rcd = rcd; 4218c2ecf20Sopenharmony_ci packet->updegr = 0; 4228c2ecf20Sopenharmony_ci packet->etail = -1; 4238c2ecf20Sopenharmony_ci packet->rhf_addr = get_rhf_addr(rcd); 4248c2ecf20Sopenharmony_ci packet->rhf = rhf_to_cpu(packet->rhf_addr); 4258c2ecf20Sopenharmony_ci packet->rhqoff = hfi1_rcd_head(rcd); 4268c2ecf20Sopenharmony_ci packet->numpkt = 0; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/* We support only two types - 9B and 16B for now */ 4308c2ecf20Sopenharmony_cistatic const hfi1_handle_cnp hfi1_handle_cnp_tbl[2] = { 4318c2ecf20Sopenharmony_ci [HFI1_PKT_TYPE_9B] = &return_cnp, 4328c2ecf20Sopenharmony_ci [HFI1_PKT_TYPE_16B] = &return_cnp_16B 4338c2ecf20Sopenharmony_ci}; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/** 4368c2ecf20Sopenharmony_ci * hfi1_process_ecn_slowpath - Process FECN or BECN bits 4378c2ecf20Sopenharmony_ci * @qp: The packet's destination QP 4388c2ecf20Sopenharmony_ci * @pkt: The packet itself. 4398c2ecf20Sopenharmony_ci * @prescan: Is the caller the RXQ prescan 4408c2ecf20Sopenharmony_ci * 4418c2ecf20Sopenharmony_ci * Process the packet's FECN or BECN bits. By now, the packet 4428c2ecf20Sopenharmony_ci * has already been evaluated whether processing of those bit should 4438c2ecf20Sopenharmony_ci * be done. 4448c2ecf20Sopenharmony_ci * The significance of the @prescan argument is that if the caller 4458c2ecf20Sopenharmony_ci * is the RXQ prescan, a CNP will be send out instead of waiting for the 4468c2ecf20Sopenharmony_ci * normal packet processing to send an ACK with BECN set (or a CNP). 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_cibool hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt, 4498c2ecf20Sopenharmony_ci bool prescan) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); 4528c2ecf20Sopenharmony_ci struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 4538c2ecf20Sopenharmony_ci struct ib_other_headers *ohdr = pkt->ohdr; 4548c2ecf20Sopenharmony_ci struct ib_grh *grh = pkt->grh; 4558c2ecf20Sopenharmony_ci u32 rqpn = 0; 4568c2ecf20Sopenharmony_ci u16 pkey; 4578c2ecf20Sopenharmony_ci u32 rlid, slid, dlid = 0; 4588c2ecf20Sopenharmony_ci u8 hdr_type, sc, svc_type, opcode; 4598c2ecf20Sopenharmony_ci bool is_mcast = false, ignore_fecn = false, do_cnp = false, 4608c2ecf20Sopenharmony_ci fecn, becn; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* can be called from prescan */ 4638c2ecf20Sopenharmony_ci if (pkt->etype == RHF_RCV_TYPE_BYPASS) { 4648c2ecf20Sopenharmony_ci pkey = hfi1_16B_get_pkey(pkt->hdr); 4658c2ecf20Sopenharmony_ci sc = hfi1_16B_get_sc(pkt->hdr); 4668c2ecf20Sopenharmony_ci dlid = hfi1_16B_get_dlid(pkt->hdr); 4678c2ecf20Sopenharmony_ci slid = hfi1_16B_get_slid(pkt->hdr); 4688c2ecf20Sopenharmony_ci is_mcast = hfi1_is_16B_mcast(dlid); 4698c2ecf20Sopenharmony_ci opcode = ib_bth_get_opcode(ohdr); 4708c2ecf20Sopenharmony_ci hdr_type = HFI1_PKT_TYPE_16B; 4718c2ecf20Sopenharmony_ci fecn = hfi1_16B_get_fecn(pkt->hdr); 4728c2ecf20Sopenharmony_ci becn = hfi1_16B_get_becn(pkt->hdr); 4738c2ecf20Sopenharmony_ci } else { 4748c2ecf20Sopenharmony_ci pkey = ib_bth_get_pkey(ohdr); 4758c2ecf20Sopenharmony_ci sc = hfi1_9B_get_sc5(pkt->hdr, pkt->rhf); 4768c2ecf20Sopenharmony_ci dlid = qp->ibqp.qp_type != IB_QPT_UD ? ib_get_dlid(pkt->hdr) : 4778c2ecf20Sopenharmony_ci ppd->lid; 4788c2ecf20Sopenharmony_ci slid = ib_get_slid(pkt->hdr); 4798c2ecf20Sopenharmony_ci is_mcast = (dlid > be16_to_cpu(IB_MULTICAST_LID_BASE)) && 4808c2ecf20Sopenharmony_ci (dlid != be16_to_cpu(IB_LID_PERMISSIVE)); 4818c2ecf20Sopenharmony_ci opcode = ib_bth_get_opcode(ohdr); 4828c2ecf20Sopenharmony_ci hdr_type = HFI1_PKT_TYPE_9B; 4838c2ecf20Sopenharmony_ci fecn = ib_bth_get_fecn(ohdr); 4848c2ecf20Sopenharmony_ci becn = ib_bth_get_becn(ohdr); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci switch (qp->ibqp.qp_type) { 4888c2ecf20Sopenharmony_ci case IB_QPT_UD: 4898c2ecf20Sopenharmony_ci rlid = slid; 4908c2ecf20Sopenharmony_ci rqpn = ib_get_sqpn(pkt->ohdr); 4918c2ecf20Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UD; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case IB_QPT_SMI: 4948c2ecf20Sopenharmony_ci case IB_QPT_GSI: 4958c2ecf20Sopenharmony_ci rlid = slid; 4968c2ecf20Sopenharmony_ci rqpn = ib_get_sqpn(pkt->ohdr); 4978c2ecf20Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UD; 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci case IB_QPT_UC: 5008c2ecf20Sopenharmony_ci rlid = rdma_ah_get_dlid(&qp->remote_ah_attr); 5018c2ecf20Sopenharmony_ci rqpn = qp->remote_qpn; 5028c2ecf20Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UC; 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci case IB_QPT_RC: 5058c2ecf20Sopenharmony_ci rlid = rdma_ah_get_dlid(&qp->remote_ah_attr); 5068c2ecf20Sopenharmony_ci rqpn = qp->remote_qpn; 5078c2ecf20Sopenharmony_ci svc_type = IB_CC_SVCTYPE_RC; 5088c2ecf20Sopenharmony_ci break; 5098c2ecf20Sopenharmony_ci default: 5108c2ecf20Sopenharmony_ci return false; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci ignore_fecn = is_mcast || (opcode == IB_OPCODE_CNP) || 5148c2ecf20Sopenharmony_ci (opcode == IB_OPCODE_RC_ACKNOWLEDGE); 5158c2ecf20Sopenharmony_ci /* 5168c2ecf20Sopenharmony_ci * ACKNOWLEDGE packets do not get a CNP but this will be 5178c2ecf20Sopenharmony_ci * guarded by ignore_fecn above. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_ci do_cnp = prescan || 5208c2ecf20Sopenharmony_ci (opcode >= IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST && 5218c2ecf20Sopenharmony_ci opcode <= IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE) || 5228c2ecf20Sopenharmony_ci opcode == TID_OP(READ_RESP) || 5238c2ecf20Sopenharmony_ci opcode == TID_OP(ACK); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* Call appropriate CNP handler */ 5268c2ecf20Sopenharmony_ci if (!ignore_fecn && do_cnp && fecn) 5278c2ecf20Sopenharmony_ci hfi1_handle_cnp_tbl[hdr_type](ibp, qp, rqpn, pkey, 5288c2ecf20Sopenharmony_ci dlid, rlid, sc, grh); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (becn) { 5318c2ecf20Sopenharmony_ci u32 lqpn = be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK; 5328c2ecf20Sopenharmony_ci u8 sl = ibp->sc_to_sl[sc]; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci return !ignore_fecn && fecn; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistruct ps_mdata { 5408c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd; 5418c2ecf20Sopenharmony_ci u32 rsize; 5428c2ecf20Sopenharmony_ci u32 maxcnt; 5438c2ecf20Sopenharmony_ci u32 ps_head; 5448c2ecf20Sopenharmony_ci u32 ps_tail; 5458c2ecf20Sopenharmony_ci u32 ps_seq; 5468c2ecf20Sopenharmony_ci}; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic inline void init_ps_mdata(struct ps_mdata *mdata, 5498c2ecf20Sopenharmony_ci struct hfi1_packet *packet) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci mdata->rcd = rcd; 5548c2ecf20Sopenharmony_ci mdata->rsize = packet->rsize; 5558c2ecf20Sopenharmony_ci mdata->maxcnt = packet->maxcnt; 5568c2ecf20Sopenharmony_ci mdata->ps_head = packet->rhqoff; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (get_dma_rtail_setting(rcd)) { 5598c2ecf20Sopenharmony_ci mdata->ps_tail = get_rcvhdrtail(rcd); 5608c2ecf20Sopenharmony_ci if (rcd->ctxt == HFI1_CTRL_CTXT) 5618c2ecf20Sopenharmony_ci mdata->ps_seq = hfi1_seq_cnt(rcd); 5628c2ecf20Sopenharmony_ci else 5638c2ecf20Sopenharmony_ci mdata->ps_seq = 0; /* not used with DMA_RTAIL */ 5648c2ecf20Sopenharmony_ci } else { 5658c2ecf20Sopenharmony_ci mdata->ps_tail = 0; /* used only with DMA_RTAIL*/ 5668c2ecf20Sopenharmony_ci mdata->ps_seq = hfi1_seq_cnt(rcd); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic inline int ps_done(struct ps_mdata *mdata, u64 rhf, 5718c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci if (get_dma_rtail_setting(rcd)) 5748c2ecf20Sopenharmony_ci return mdata->ps_head == mdata->ps_tail; 5758c2ecf20Sopenharmony_ci return mdata->ps_seq != rhf_rcv_seq(rhf); 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic inline int ps_skip(struct ps_mdata *mdata, u64 rhf, 5798c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci /* 5828c2ecf20Sopenharmony_ci * Control context can potentially receive an invalid rhf. 5838c2ecf20Sopenharmony_ci * Drop such packets. 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_ci if ((rcd->ctxt == HFI1_CTRL_CTXT) && (mdata->ps_head != mdata->ps_tail)) 5868c2ecf20Sopenharmony_ci return mdata->ps_seq != rhf_rcv_seq(rhf); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return 0; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic inline void update_ps_mdata(struct ps_mdata *mdata, 5928c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci mdata->ps_head += mdata->rsize; 5958c2ecf20Sopenharmony_ci if (mdata->ps_head >= mdata->maxcnt) 5968c2ecf20Sopenharmony_ci mdata->ps_head = 0; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Control context must do seq counting */ 5998c2ecf20Sopenharmony_ci if (!get_dma_rtail_setting(rcd) || 6008c2ecf20Sopenharmony_ci rcd->ctxt == HFI1_CTRL_CTXT) 6018c2ecf20Sopenharmony_ci mdata->ps_seq = hfi1_seq_incr_wrap(mdata->ps_seq); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci/* 6058c2ecf20Sopenharmony_ci * prescan_rxq - search through the receive queue looking for packets 6068c2ecf20Sopenharmony_ci * containing Excplicit Congestion Notifications (FECNs, or BECNs). 6078c2ecf20Sopenharmony_ci * When an ECN is found, process the Congestion Notification, and toggle 6088c2ecf20Sopenharmony_ci * it off. 6098c2ecf20Sopenharmony_ci * This is declared as a macro to allow quick checking of the port to avoid 6108c2ecf20Sopenharmony_ci * the overhead of a function call if not enabled. 6118c2ecf20Sopenharmony_ci */ 6128c2ecf20Sopenharmony_ci#define prescan_rxq(rcd, packet) \ 6138c2ecf20Sopenharmony_ci do { \ 6148c2ecf20Sopenharmony_ci if (rcd->ppd->cc_prescan) \ 6158c2ecf20Sopenharmony_ci __prescan_rxq(packet); \ 6168c2ecf20Sopenharmony_ci } while (0) 6178c2ecf20Sopenharmony_cistatic void __prescan_rxq(struct hfi1_packet *packet) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 6208c2ecf20Sopenharmony_ci struct ps_mdata mdata; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci init_ps_mdata(&mdata, packet); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci while (1) { 6258c2ecf20Sopenharmony_ci struct hfi1_ibport *ibp = rcd_to_iport(rcd); 6268c2ecf20Sopenharmony_ci __le32 *rhf_addr = (__le32 *)rcd->rcvhdrq + mdata.ps_head + 6278c2ecf20Sopenharmony_ci packet->rcd->rhf_offset; 6288c2ecf20Sopenharmony_ci struct rvt_qp *qp; 6298c2ecf20Sopenharmony_ci struct ib_header *hdr; 6308c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = &rcd->dd->verbs_dev.rdi; 6318c2ecf20Sopenharmony_ci u64 rhf = rhf_to_cpu(rhf_addr); 6328c2ecf20Sopenharmony_ci u32 etype = rhf_rcv_type(rhf), qpn, bth1; 6338c2ecf20Sopenharmony_ci u8 lnh; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (ps_done(&mdata, rhf, rcd)) 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (ps_skip(&mdata, rhf, rcd)) 6398c2ecf20Sopenharmony_ci goto next; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (etype != RHF_RCV_TYPE_IB) 6428c2ecf20Sopenharmony_ci goto next; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci packet->hdr = hfi1_get_msgheader(packet->rcd, rhf_addr); 6458c2ecf20Sopenharmony_ci hdr = packet->hdr; 6468c2ecf20Sopenharmony_ci lnh = ib_get_lnh(hdr); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (lnh == HFI1_LRH_BTH) { 6498c2ecf20Sopenharmony_ci packet->ohdr = &hdr->u.oth; 6508c2ecf20Sopenharmony_ci packet->grh = NULL; 6518c2ecf20Sopenharmony_ci } else if (lnh == HFI1_LRH_GRH) { 6528c2ecf20Sopenharmony_ci packet->ohdr = &hdr->u.l.oth; 6538c2ecf20Sopenharmony_ci packet->grh = &hdr->u.l.grh; 6548c2ecf20Sopenharmony_ci } else { 6558c2ecf20Sopenharmony_ci goto next; /* just in case */ 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (!hfi1_may_ecn(packet)) 6598c2ecf20Sopenharmony_ci goto next; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci bth1 = be32_to_cpu(packet->ohdr->bth[1]); 6628c2ecf20Sopenharmony_ci qpn = bth1 & RVT_QPN_MASK; 6638c2ecf20Sopenharmony_ci rcu_read_lock(); 6648c2ecf20Sopenharmony_ci qp = rvt_lookup_qpn(rdi, &ibp->rvp, qpn); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (!qp) { 6678c2ecf20Sopenharmony_ci rcu_read_unlock(); 6688c2ecf20Sopenharmony_ci goto next; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci hfi1_process_ecn_slowpath(qp, packet, true); 6728c2ecf20Sopenharmony_ci rcu_read_unlock(); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* turn off BECN, FECN */ 6758c2ecf20Sopenharmony_ci bth1 &= ~(IB_FECN_SMASK | IB_BECN_SMASK); 6768c2ecf20Sopenharmony_ci packet->ohdr->bth[1] = cpu_to_be32(bth1); 6778c2ecf20Sopenharmony_cinext: 6788c2ecf20Sopenharmony_ci update_ps_mdata(&mdata, rcd); 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic void process_rcv_qp_work(struct hfi1_packet *packet) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct rvt_qp *qp, *nqp; 6858c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* 6888c2ecf20Sopenharmony_ci * Iterate over all QPs waiting to respond. 6898c2ecf20Sopenharmony_ci * The list won't change since the IRQ is only run on one CPU. 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci list_for_each_entry_safe(qp, nqp, &rcd->qp_wait_list, rspwait) { 6928c2ecf20Sopenharmony_ci list_del_init(&qp->rspwait); 6938c2ecf20Sopenharmony_ci if (qp->r_flags & RVT_R_RSP_NAK) { 6948c2ecf20Sopenharmony_ci qp->r_flags &= ~RVT_R_RSP_NAK; 6958c2ecf20Sopenharmony_ci packet->qp = qp; 6968c2ecf20Sopenharmony_ci hfi1_send_rc_ack(packet, 0); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci if (qp->r_flags & RVT_R_RSP_SEND) { 6998c2ecf20Sopenharmony_ci unsigned long flags; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci qp->r_flags &= ~RVT_R_RSP_SEND; 7028c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->s_lock, flags); 7038c2ecf20Sopenharmony_ci if (ib_rvt_state_ops[qp->state] & 7048c2ecf20Sopenharmony_ci RVT_PROCESS_OR_FLUSH_SEND) 7058c2ecf20Sopenharmony_ci hfi1_schedule_send(qp); 7068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->s_lock, flags); 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci rvt_put_qp(qp); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic noinline int max_packet_exceeded(struct hfi1_packet *packet, int thread) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci if (thread) { 7158c2ecf20Sopenharmony_ci if ((packet->numpkt & (MAX_PKT_RECV_THREAD - 1)) == 0) 7168c2ecf20Sopenharmony_ci /* allow defered processing */ 7178c2ecf20Sopenharmony_ci process_rcv_qp_work(packet); 7188c2ecf20Sopenharmony_ci cond_resched(); 7198c2ecf20Sopenharmony_ci return RCV_PKT_OK; 7208c2ecf20Sopenharmony_ci } else { 7218c2ecf20Sopenharmony_ci this_cpu_inc(*packet->rcd->dd->rcv_limit); 7228c2ecf20Sopenharmony_ci return RCV_PKT_LIMIT; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic inline int check_max_packet(struct hfi1_packet *packet, int thread) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci int ret = RCV_PKT_OK; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (unlikely((packet->numpkt & (MAX_PKT_RECV - 1)) == 0)) 7318c2ecf20Sopenharmony_ci ret = max_packet_exceeded(packet, thread); 7328c2ecf20Sopenharmony_ci return ret; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic noinline int skip_rcv_packet(struct hfi1_packet *packet, int thread) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci int ret; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci packet->rcd->dd->ctx0_seq_drop++; 7408c2ecf20Sopenharmony_ci /* Set up for the next packet */ 7418c2ecf20Sopenharmony_ci packet->rhqoff += packet->rsize; 7428c2ecf20Sopenharmony_ci if (packet->rhqoff >= packet->maxcnt) 7438c2ecf20Sopenharmony_ci packet->rhqoff = 0; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci packet->numpkt++; 7468c2ecf20Sopenharmony_ci ret = check_max_packet(packet, thread); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci packet->rhf_addr = (__le32 *)packet->rcd->rcvhdrq + packet->rhqoff + 7498c2ecf20Sopenharmony_ci packet->rcd->rhf_offset; 7508c2ecf20Sopenharmony_ci packet->rhf = rhf_to_cpu(packet->rhf_addr); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci return ret; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic void process_rcv_packet_napi(struct hfi1_packet *packet) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci packet->etype = rhf_rcv_type(packet->rhf); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* total length */ 7608c2ecf20Sopenharmony_ci packet->tlen = rhf_pkt_len(packet->rhf); /* in bytes */ 7618c2ecf20Sopenharmony_ci /* retrieve eager buffer details */ 7628c2ecf20Sopenharmony_ci packet->etail = rhf_egr_index(packet->rhf); 7638c2ecf20Sopenharmony_ci packet->ebuf = get_egrbuf(packet->rcd, packet->rhf, 7648c2ecf20Sopenharmony_ci &packet->updegr); 7658c2ecf20Sopenharmony_ci /* 7668c2ecf20Sopenharmony_ci * Prefetch the contents of the eager buffer. It is 7678c2ecf20Sopenharmony_ci * OK to send a negative length to prefetch_range(). 7688c2ecf20Sopenharmony_ci * The +2 is the size of the RHF. 7698c2ecf20Sopenharmony_ci */ 7708c2ecf20Sopenharmony_ci prefetch_range(packet->ebuf, 7718c2ecf20Sopenharmony_ci packet->tlen - ((packet->rcd->rcvhdrqentsize - 7728c2ecf20Sopenharmony_ci (rhf_hdrq_offset(packet->rhf) 7738c2ecf20Sopenharmony_ci + 2)) * 4)); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci packet->rcd->rhf_rcv_function_map[packet->etype](packet); 7768c2ecf20Sopenharmony_ci packet->numpkt++; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* Set up for the next packet */ 7798c2ecf20Sopenharmony_ci packet->rhqoff += packet->rsize; 7808c2ecf20Sopenharmony_ci if (packet->rhqoff >= packet->maxcnt) 7818c2ecf20Sopenharmony_ci packet->rhqoff = 0; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci packet->rhf_addr = (__le32 *)packet->rcd->rcvhdrq + packet->rhqoff + 7848c2ecf20Sopenharmony_ci packet->rcd->rhf_offset; 7858c2ecf20Sopenharmony_ci packet->rhf = rhf_to_cpu(packet->rhf_addr); 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_cistatic inline int process_rcv_packet(struct hfi1_packet *packet, int thread) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci int ret; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci packet->etype = rhf_rcv_type(packet->rhf); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* total length */ 7958c2ecf20Sopenharmony_ci packet->tlen = rhf_pkt_len(packet->rhf); /* in bytes */ 7968c2ecf20Sopenharmony_ci /* retrieve eager buffer details */ 7978c2ecf20Sopenharmony_ci packet->ebuf = NULL; 7988c2ecf20Sopenharmony_ci if (rhf_use_egr_bfr(packet->rhf)) { 7998c2ecf20Sopenharmony_ci packet->etail = rhf_egr_index(packet->rhf); 8008c2ecf20Sopenharmony_ci packet->ebuf = get_egrbuf(packet->rcd, packet->rhf, 8018c2ecf20Sopenharmony_ci &packet->updegr); 8028c2ecf20Sopenharmony_ci /* 8038c2ecf20Sopenharmony_ci * Prefetch the contents of the eager buffer. It is 8048c2ecf20Sopenharmony_ci * OK to send a negative length to prefetch_range(). 8058c2ecf20Sopenharmony_ci * The +2 is the size of the RHF. 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_ci prefetch_range(packet->ebuf, 8088c2ecf20Sopenharmony_ci packet->tlen - ((get_hdrqentsize(packet->rcd) - 8098c2ecf20Sopenharmony_ci (rhf_hdrq_offset(packet->rhf) 8108c2ecf20Sopenharmony_ci + 2)) * 4)); 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci /* 8148c2ecf20Sopenharmony_ci * Call a type specific handler for the packet. We 8158c2ecf20Sopenharmony_ci * should be able to trust that etype won't be beyond 8168c2ecf20Sopenharmony_ci * the range of valid indexes. If so something is really 8178c2ecf20Sopenharmony_ci * wrong and we can probably just let things come 8188c2ecf20Sopenharmony_ci * crashing down. There is no need to eat another 8198c2ecf20Sopenharmony_ci * comparison in this performance critical code. 8208c2ecf20Sopenharmony_ci */ 8218c2ecf20Sopenharmony_ci packet->rcd->rhf_rcv_function_map[packet->etype](packet); 8228c2ecf20Sopenharmony_ci packet->numpkt++; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* Set up for the next packet */ 8258c2ecf20Sopenharmony_ci packet->rhqoff += packet->rsize; 8268c2ecf20Sopenharmony_ci if (packet->rhqoff >= packet->maxcnt) 8278c2ecf20Sopenharmony_ci packet->rhqoff = 0; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci ret = check_max_packet(packet, thread); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci packet->rhf_addr = (__le32 *)packet->rcd->rcvhdrq + packet->rhqoff + 8328c2ecf20Sopenharmony_ci packet->rcd->rhf_offset; 8338c2ecf20Sopenharmony_ci packet->rhf = rhf_to_cpu(packet->rhf_addr); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci return ret; 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic inline void process_rcv_update(int last, struct hfi1_packet *packet) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci /* 8418c2ecf20Sopenharmony_ci * Update head regs etc., every 16 packets, if not last pkt, 8428c2ecf20Sopenharmony_ci * to help prevent rcvhdrq overflows, when many packets 8438c2ecf20Sopenharmony_ci * are processed and queue is nearly full. 8448c2ecf20Sopenharmony_ci * Don't request an interrupt for intermediate updates. 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_ci if (!last && !(packet->numpkt & 0xf)) { 8478c2ecf20Sopenharmony_ci update_usrhead(packet->rcd, packet->rhqoff, packet->updegr, 8488c2ecf20Sopenharmony_ci packet->etail, 0, 0); 8498c2ecf20Sopenharmony_ci packet->updegr = 0; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci packet->grh = NULL; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistatic inline void finish_packet(struct hfi1_packet *packet) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci /* 8578c2ecf20Sopenharmony_ci * Nothing we need to free for the packet. 8588c2ecf20Sopenharmony_ci * 8598c2ecf20Sopenharmony_ci * The only thing we need to do is a final update and call for an 8608c2ecf20Sopenharmony_ci * interrupt 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_ci update_usrhead(packet->rcd, hfi1_rcd_head(packet->rcd), packet->updegr, 8638c2ecf20Sopenharmony_ci packet->etail, rcv_intr_dynamic, packet->numpkt); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci/* 8678c2ecf20Sopenharmony_ci * handle_receive_interrupt_napi_fp - receive a packet 8688c2ecf20Sopenharmony_ci * @rcd: the context 8698c2ecf20Sopenharmony_ci * @budget: polling budget 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * Called from interrupt handler for receive interrupt. 8728c2ecf20Sopenharmony_ci * This is the fast path interrupt handler 8738c2ecf20Sopenharmony_ci * when executing napi soft irq environment. 8748c2ecf20Sopenharmony_ci */ 8758c2ecf20Sopenharmony_ciint handle_receive_interrupt_napi_fp(struct hfi1_ctxtdata *rcd, int budget) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci struct hfi1_packet packet; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci init_packet(rcd, &packet); 8808c2ecf20Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) 8818c2ecf20Sopenharmony_ci goto bail; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci while (packet.numpkt < budget) { 8848c2ecf20Sopenharmony_ci process_rcv_packet_napi(&packet); 8858c2ecf20Sopenharmony_ci if (hfi1_seq_incr(rcd, rhf_rcv_seq(packet.rhf))) 8868c2ecf20Sopenharmony_ci break; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci process_rcv_update(0, &packet); 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 8918c2ecf20Sopenharmony_cibail: 8928c2ecf20Sopenharmony_ci finish_packet(&packet); 8938c2ecf20Sopenharmony_ci return packet.numpkt; 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci/* 8978c2ecf20Sopenharmony_ci * Handle receive interrupts when using the no dma rtail option. 8988c2ecf20Sopenharmony_ci */ 8998c2ecf20Sopenharmony_ciint handle_receive_interrupt_nodma_rtail(struct hfi1_ctxtdata *rcd, int thread) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci int last = RCV_PKT_OK; 9028c2ecf20Sopenharmony_ci struct hfi1_packet packet; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci init_packet(rcd, &packet); 9058c2ecf20Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) { 9068c2ecf20Sopenharmony_ci last = RCV_PKT_DONE; 9078c2ecf20Sopenharmony_ci goto bail; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci prescan_rxq(rcd, &packet); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci while (last == RCV_PKT_OK) { 9138c2ecf20Sopenharmony_ci last = process_rcv_packet(&packet, thread); 9148c2ecf20Sopenharmony_ci if (hfi1_seq_incr(rcd, rhf_rcv_seq(packet.rhf))) 9158c2ecf20Sopenharmony_ci last = RCV_PKT_DONE; 9168c2ecf20Sopenharmony_ci process_rcv_update(last, &packet); 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci process_rcv_qp_work(&packet); 9198c2ecf20Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 9208c2ecf20Sopenharmony_cibail: 9218c2ecf20Sopenharmony_ci finish_packet(&packet); 9228c2ecf20Sopenharmony_ci return last; 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ciint handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *rcd, int thread) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci u32 hdrqtail; 9288c2ecf20Sopenharmony_ci int last = RCV_PKT_OK; 9298c2ecf20Sopenharmony_ci struct hfi1_packet packet; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci init_packet(rcd, &packet); 9328c2ecf20Sopenharmony_ci hdrqtail = get_rcvhdrtail(rcd); 9338c2ecf20Sopenharmony_ci if (packet.rhqoff == hdrqtail) { 9348c2ecf20Sopenharmony_ci last = RCV_PKT_DONE; 9358c2ecf20Sopenharmony_ci goto bail; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci smp_rmb(); /* prevent speculative reads of dma'ed hdrq */ 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci prescan_rxq(rcd, &packet); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci while (last == RCV_PKT_OK) { 9428c2ecf20Sopenharmony_ci last = process_rcv_packet(&packet, thread); 9438c2ecf20Sopenharmony_ci if (packet.rhqoff == hdrqtail) 9448c2ecf20Sopenharmony_ci last = RCV_PKT_DONE; 9458c2ecf20Sopenharmony_ci process_rcv_update(last, &packet); 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci process_rcv_qp_work(&packet); 9488c2ecf20Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 9498c2ecf20Sopenharmony_cibail: 9508c2ecf20Sopenharmony_ci finish_packet(&packet); 9518c2ecf20Sopenharmony_ci return last; 9528c2ecf20Sopenharmony_ci} 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_cistatic void set_all_fastpath(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci u16 i; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci /* 9598c2ecf20Sopenharmony_ci * For dynamically allocated kernel contexts (like vnic) switch 9608c2ecf20Sopenharmony_ci * interrupt handler only for that context. Otherwise, switch 9618c2ecf20Sopenharmony_ci * interrupt handler for all statically allocated kernel contexts. 9628c2ecf20Sopenharmony_ci */ 9638c2ecf20Sopenharmony_ci if (rcd->ctxt >= dd->first_dyn_alloc_ctxt && !rcd->is_vnic) { 9648c2ecf20Sopenharmony_ci hfi1_rcd_get(rcd); 9658c2ecf20Sopenharmony_ci hfi1_set_fast(rcd); 9668c2ecf20Sopenharmony_ci hfi1_rcd_put(rcd); 9678c2ecf20Sopenharmony_ci return; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci for (i = HFI1_CTRL_CTXT + 1; i < dd->num_rcv_contexts; i++) { 9718c2ecf20Sopenharmony_ci rcd = hfi1_rcd_get_by_index(dd, i); 9728c2ecf20Sopenharmony_ci if (rcd && (i < dd->first_dyn_alloc_ctxt || rcd->is_vnic)) 9738c2ecf20Sopenharmony_ci hfi1_set_fast(rcd); 9748c2ecf20Sopenharmony_ci hfi1_rcd_put(rcd); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_civoid set_all_slowpath(struct hfi1_devdata *dd) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd; 9818c2ecf20Sopenharmony_ci u16 i; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* HFI1_CTRL_CTXT must always use the slow path interrupt handler */ 9848c2ecf20Sopenharmony_ci for (i = HFI1_CTRL_CTXT + 1; i < dd->num_rcv_contexts; i++) { 9858c2ecf20Sopenharmony_ci rcd = hfi1_rcd_get_by_index(dd, i); 9868c2ecf20Sopenharmony_ci if (!rcd) 9878c2ecf20Sopenharmony_ci continue; 9888c2ecf20Sopenharmony_ci if (i < dd->first_dyn_alloc_ctxt || rcd->is_vnic) 9898c2ecf20Sopenharmony_ci rcd->do_interrupt = rcd->slow_handler; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci hfi1_rcd_put(rcd); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cistatic bool __set_armed_to_active(struct hfi1_packet *packet) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci u8 etype = rhf_rcv_type(packet->rhf); 9988c2ecf20Sopenharmony_ci u8 sc = SC15_PACKET; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (etype == RHF_RCV_TYPE_IB) { 10018c2ecf20Sopenharmony_ci struct ib_header *hdr = hfi1_get_msgheader(packet->rcd, 10028c2ecf20Sopenharmony_ci packet->rhf_addr); 10038c2ecf20Sopenharmony_ci sc = hfi1_9B_get_sc5(hdr, packet->rhf); 10048c2ecf20Sopenharmony_ci } else if (etype == RHF_RCV_TYPE_BYPASS) { 10058c2ecf20Sopenharmony_ci struct hfi1_16b_header *hdr = hfi1_get_16B_header( 10068c2ecf20Sopenharmony_ci packet->rcd, 10078c2ecf20Sopenharmony_ci packet->rhf_addr); 10088c2ecf20Sopenharmony_ci sc = hfi1_16B_get_sc(hdr); 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci if (sc != SC15_PACKET) { 10118c2ecf20Sopenharmony_ci int hwstate = driver_lstate(packet->rcd->ppd); 10128c2ecf20Sopenharmony_ci struct work_struct *lsaw = 10138c2ecf20Sopenharmony_ci &packet->rcd->ppd->linkstate_active_work; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (hwstate != IB_PORT_ACTIVE) { 10168c2ecf20Sopenharmony_ci dd_dev_info(packet->rcd->dd, 10178c2ecf20Sopenharmony_ci "Unexpected link state %s\n", 10188c2ecf20Sopenharmony_ci opa_lstate_name(hwstate)); 10198c2ecf20Sopenharmony_ci return false; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci queue_work(packet->rcd->ppd->link_wq, lsaw); 10238c2ecf20Sopenharmony_ci return true; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci return false; 10268c2ecf20Sopenharmony_ci} 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci/** 10298c2ecf20Sopenharmony_ci * armed to active - the fast path for armed to active 10308c2ecf20Sopenharmony_ci * @packet: the packet structure 10318c2ecf20Sopenharmony_ci * 10328c2ecf20Sopenharmony_ci * Return true if packet processing needs to bail. 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_cistatic bool set_armed_to_active(struct hfi1_packet *packet) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci if (likely(packet->rcd->ppd->host_link_state != HLS_UP_ARMED)) 10378c2ecf20Sopenharmony_ci return false; 10388c2ecf20Sopenharmony_ci return __set_armed_to_active(packet); 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci/* 10428c2ecf20Sopenharmony_ci * handle_receive_interrupt - receive a packet 10438c2ecf20Sopenharmony_ci * @rcd: the context 10448c2ecf20Sopenharmony_ci * 10458c2ecf20Sopenharmony_ci * Called from interrupt handler for errors or receive interrupt. 10468c2ecf20Sopenharmony_ci * This is the slow path interrupt handler. 10478c2ecf20Sopenharmony_ci */ 10488c2ecf20Sopenharmony_ciint handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = rcd->dd; 10518c2ecf20Sopenharmony_ci u32 hdrqtail; 10528c2ecf20Sopenharmony_ci int needset, last = RCV_PKT_OK; 10538c2ecf20Sopenharmony_ci struct hfi1_packet packet; 10548c2ecf20Sopenharmony_ci int skip_pkt = 0; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (!rcd->rcvhdrq) 10578c2ecf20Sopenharmony_ci return RCV_PKT_OK; 10588c2ecf20Sopenharmony_ci /* Control context will always use the slow path interrupt handler */ 10598c2ecf20Sopenharmony_ci needset = (rcd->ctxt == HFI1_CTRL_CTXT) ? 0 : 1; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci init_packet(rcd, &packet); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (!get_dma_rtail_setting(rcd)) { 10648c2ecf20Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) { 10658c2ecf20Sopenharmony_ci last = RCV_PKT_DONE; 10668c2ecf20Sopenharmony_ci goto bail; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci hdrqtail = 0; 10698c2ecf20Sopenharmony_ci } else { 10708c2ecf20Sopenharmony_ci hdrqtail = get_rcvhdrtail(rcd); 10718c2ecf20Sopenharmony_ci if (packet.rhqoff == hdrqtail) { 10728c2ecf20Sopenharmony_ci last = RCV_PKT_DONE; 10738c2ecf20Sopenharmony_ci goto bail; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci smp_rmb(); /* prevent speculative reads of dma'ed hdrq */ 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* 10788c2ecf20Sopenharmony_ci * Control context can potentially receive an invalid 10798c2ecf20Sopenharmony_ci * rhf. Drop such packets. 10808c2ecf20Sopenharmony_ci */ 10818c2ecf20Sopenharmony_ci if (rcd->ctxt == HFI1_CTRL_CTXT) 10828c2ecf20Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) 10838c2ecf20Sopenharmony_ci skip_pkt = 1; 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci prescan_rxq(rcd, &packet); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci while (last == RCV_PKT_OK) { 10898c2ecf20Sopenharmony_ci if (hfi1_need_drop(dd)) { 10908c2ecf20Sopenharmony_ci /* On to the next packet */ 10918c2ecf20Sopenharmony_ci packet.rhqoff += packet.rsize; 10928c2ecf20Sopenharmony_ci packet.rhf_addr = (__le32 *)rcd->rcvhdrq + 10938c2ecf20Sopenharmony_ci packet.rhqoff + 10948c2ecf20Sopenharmony_ci rcd->rhf_offset; 10958c2ecf20Sopenharmony_ci packet.rhf = rhf_to_cpu(packet.rhf_addr); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci } else if (skip_pkt) { 10988c2ecf20Sopenharmony_ci last = skip_rcv_packet(&packet, thread); 10998c2ecf20Sopenharmony_ci skip_pkt = 0; 11008c2ecf20Sopenharmony_ci } else { 11018c2ecf20Sopenharmony_ci if (set_armed_to_active(&packet)) 11028c2ecf20Sopenharmony_ci goto bail; 11038c2ecf20Sopenharmony_ci last = process_rcv_packet(&packet, thread); 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if (!get_dma_rtail_setting(rcd)) { 11078c2ecf20Sopenharmony_ci if (hfi1_seq_incr(rcd, rhf_rcv_seq(packet.rhf))) 11088c2ecf20Sopenharmony_ci last = RCV_PKT_DONE; 11098c2ecf20Sopenharmony_ci } else { 11108c2ecf20Sopenharmony_ci if (packet.rhqoff == hdrqtail) 11118c2ecf20Sopenharmony_ci last = RCV_PKT_DONE; 11128c2ecf20Sopenharmony_ci /* 11138c2ecf20Sopenharmony_ci * Control context can potentially receive an invalid 11148c2ecf20Sopenharmony_ci * rhf. Drop such packets. 11158c2ecf20Sopenharmony_ci */ 11168c2ecf20Sopenharmony_ci if (rcd->ctxt == HFI1_CTRL_CTXT) { 11178c2ecf20Sopenharmony_ci bool lseq; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci lseq = hfi1_seq_incr(rcd, 11208c2ecf20Sopenharmony_ci rhf_rcv_seq(packet.rhf)); 11218c2ecf20Sopenharmony_ci if (!last && lseq) 11228c2ecf20Sopenharmony_ci skip_pkt = 1; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (needset) { 11278c2ecf20Sopenharmony_ci needset = false; 11288c2ecf20Sopenharmony_ci set_all_fastpath(dd, rcd); 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci process_rcv_update(last, &packet); 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci process_rcv_qp_work(&packet); 11348c2ecf20Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_cibail: 11378c2ecf20Sopenharmony_ci /* 11388c2ecf20Sopenharmony_ci * Always write head at end, and setup rcv interrupt, even 11398c2ecf20Sopenharmony_ci * if no packets were processed. 11408c2ecf20Sopenharmony_ci */ 11418c2ecf20Sopenharmony_ci finish_packet(&packet); 11428c2ecf20Sopenharmony_ci return last; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci/* 11468c2ecf20Sopenharmony_ci * handle_receive_interrupt_napi_sp - receive a packet 11478c2ecf20Sopenharmony_ci * @rcd: the context 11488c2ecf20Sopenharmony_ci * @budget: polling budget 11498c2ecf20Sopenharmony_ci * 11508c2ecf20Sopenharmony_ci * Called from interrupt handler for errors or receive interrupt. 11518c2ecf20Sopenharmony_ci * This is the slow path interrupt handler 11528c2ecf20Sopenharmony_ci * when executing napi soft irq environment. 11538c2ecf20Sopenharmony_ci */ 11548c2ecf20Sopenharmony_ciint handle_receive_interrupt_napi_sp(struct hfi1_ctxtdata *rcd, int budget) 11558c2ecf20Sopenharmony_ci{ 11568c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = rcd->dd; 11578c2ecf20Sopenharmony_ci int last = RCV_PKT_OK; 11588c2ecf20Sopenharmony_ci bool needset = true; 11598c2ecf20Sopenharmony_ci struct hfi1_packet packet; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci init_packet(rcd, &packet); 11628c2ecf20Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) 11638c2ecf20Sopenharmony_ci goto bail; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci while (last != RCV_PKT_DONE && packet.numpkt < budget) { 11668c2ecf20Sopenharmony_ci if (hfi1_need_drop(dd)) { 11678c2ecf20Sopenharmony_ci /* On to the next packet */ 11688c2ecf20Sopenharmony_ci packet.rhqoff += packet.rsize; 11698c2ecf20Sopenharmony_ci packet.rhf_addr = (__le32 *)rcd->rcvhdrq + 11708c2ecf20Sopenharmony_ci packet.rhqoff + 11718c2ecf20Sopenharmony_ci rcd->rhf_offset; 11728c2ecf20Sopenharmony_ci packet.rhf = rhf_to_cpu(packet.rhf_addr); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci } else { 11758c2ecf20Sopenharmony_ci if (set_armed_to_active(&packet)) 11768c2ecf20Sopenharmony_ci goto bail; 11778c2ecf20Sopenharmony_ci process_rcv_packet_napi(&packet); 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (hfi1_seq_incr(rcd, rhf_rcv_seq(packet.rhf))) 11818c2ecf20Sopenharmony_ci last = RCV_PKT_DONE; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (needset) { 11848c2ecf20Sopenharmony_ci needset = false; 11858c2ecf20Sopenharmony_ci set_all_fastpath(dd, rcd); 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci process_rcv_update(last, &packet); 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cibail: 11948c2ecf20Sopenharmony_ci /* 11958c2ecf20Sopenharmony_ci * Always write head at end, and setup rcv interrupt, even 11968c2ecf20Sopenharmony_ci * if no packets were processed. 11978c2ecf20Sopenharmony_ci */ 11988c2ecf20Sopenharmony_ci finish_packet(&packet); 11998c2ecf20Sopenharmony_ci return packet.numpkt; 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci/* 12038c2ecf20Sopenharmony_ci * We may discover in the interrupt that the hardware link state has 12048c2ecf20Sopenharmony_ci * changed from ARMED to ACTIVE (due to the arrival of a non-SC15 packet), 12058c2ecf20Sopenharmony_ci * and we need to update the driver's notion of the link state. We cannot 12068c2ecf20Sopenharmony_ci * run set_link_state from interrupt context, so we queue this function on 12078c2ecf20Sopenharmony_ci * a workqueue. 12088c2ecf20Sopenharmony_ci * 12098c2ecf20Sopenharmony_ci * We delay the regular interrupt processing until after the state changes 12108c2ecf20Sopenharmony_ci * so that the link will be in the correct state by the time any application 12118c2ecf20Sopenharmony_ci * we wake up attempts to send a reply to any message it received. 12128c2ecf20Sopenharmony_ci * (Subsequent receive interrupts may possibly force the wakeup before we 12138c2ecf20Sopenharmony_ci * update the link state.) 12148c2ecf20Sopenharmony_ci * 12158c2ecf20Sopenharmony_ci * The rcd is freed in hfi1_free_ctxtdata after hfi1_postinit_cleanup invokes 12168c2ecf20Sopenharmony_ci * dd->f_cleanup(dd) to disable the interrupt handler and flush workqueues, 12178c2ecf20Sopenharmony_ci * so we're safe from use-after-free of the rcd. 12188c2ecf20Sopenharmony_ci */ 12198c2ecf20Sopenharmony_civoid receive_interrupt_work(struct work_struct *work) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, 12228c2ecf20Sopenharmony_ci linkstate_active_work); 12238c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 12248c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd; 12258c2ecf20Sopenharmony_ci u16 i; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci /* Received non-SC15 packet implies neighbor_normal */ 12288c2ecf20Sopenharmony_ci ppd->neighbor_normal = 1; 12298c2ecf20Sopenharmony_ci set_link_state(ppd, HLS_UP_ACTIVE); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci /* 12328c2ecf20Sopenharmony_ci * Interrupt all statically allocated kernel contexts that could 12338c2ecf20Sopenharmony_ci * have had an interrupt during auto activation. 12348c2ecf20Sopenharmony_ci */ 12358c2ecf20Sopenharmony_ci for (i = HFI1_CTRL_CTXT; i < dd->first_dyn_alloc_ctxt; i++) { 12368c2ecf20Sopenharmony_ci rcd = hfi1_rcd_get_by_index(dd, i); 12378c2ecf20Sopenharmony_ci if (rcd) 12388c2ecf20Sopenharmony_ci force_recv_intr(rcd); 12398c2ecf20Sopenharmony_ci hfi1_rcd_put(rcd); 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci} 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci/* 12448c2ecf20Sopenharmony_ci * Convert a given MTU size to the on-wire MAD packet enumeration. 12458c2ecf20Sopenharmony_ci * Return -1 if the size is invalid. 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_ciint mtu_to_enum(u32 mtu, int default_if_bad) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci switch (mtu) { 12508c2ecf20Sopenharmony_ci case 0: return OPA_MTU_0; 12518c2ecf20Sopenharmony_ci case 256: return OPA_MTU_256; 12528c2ecf20Sopenharmony_ci case 512: return OPA_MTU_512; 12538c2ecf20Sopenharmony_ci case 1024: return OPA_MTU_1024; 12548c2ecf20Sopenharmony_ci case 2048: return OPA_MTU_2048; 12558c2ecf20Sopenharmony_ci case 4096: return OPA_MTU_4096; 12568c2ecf20Sopenharmony_ci case 8192: return OPA_MTU_8192; 12578c2ecf20Sopenharmony_ci case 10240: return OPA_MTU_10240; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci return default_if_bad; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ciu16 enum_to_mtu(int mtu) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci switch (mtu) { 12658c2ecf20Sopenharmony_ci case OPA_MTU_0: return 0; 12668c2ecf20Sopenharmony_ci case OPA_MTU_256: return 256; 12678c2ecf20Sopenharmony_ci case OPA_MTU_512: return 512; 12688c2ecf20Sopenharmony_ci case OPA_MTU_1024: return 1024; 12698c2ecf20Sopenharmony_ci case OPA_MTU_2048: return 2048; 12708c2ecf20Sopenharmony_ci case OPA_MTU_4096: return 4096; 12718c2ecf20Sopenharmony_ci case OPA_MTU_8192: return 8192; 12728c2ecf20Sopenharmony_ci case OPA_MTU_10240: return 10240; 12738c2ecf20Sopenharmony_ci default: return 0xffff; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci} 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci/* 12788c2ecf20Sopenharmony_ci * set_mtu - set the MTU 12798c2ecf20Sopenharmony_ci * @ppd: the per port data 12808c2ecf20Sopenharmony_ci * 12818c2ecf20Sopenharmony_ci * We can handle "any" incoming size, the issue here is whether we 12828c2ecf20Sopenharmony_ci * need to restrict our outgoing size. We do not deal with what happens 12838c2ecf20Sopenharmony_ci * to programs that are already running when the size changes. 12848c2ecf20Sopenharmony_ci */ 12858c2ecf20Sopenharmony_ciint set_mtu(struct hfi1_pportdata *ppd) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 12888c2ecf20Sopenharmony_ci int i, drain, ret = 0, is_up = 0; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci ppd->ibmtu = 0; 12918c2ecf20Sopenharmony_ci for (i = 0; i < ppd->vls_supported; i++) 12928c2ecf20Sopenharmony_ci if (ppd->ibmtu < dd->vld[i].mtu) 12938c2ecf20Sopenharmony_ci ppd->ibmtu = dd->vld[i].mtu; 12948c2ecf20Sopenharmony_ci ppd->ibmaxlen = ppd->ibmtu + lrh_max_header_bytes(ppd->dd); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci mutex_lock(&ppd->hls_lock); 12978c2ecf20Sopenharmony_ci if (ppd->host_link_state == HLS_UP_INIT || 12988c2ecf20Sopenharmony_ci ppd->host_link_state == HLS_UP_ARMED || 12998c2ecf20Sopenharmony_ci ppd->host_link_state == HLS_UP_ACTIVE) 13008c2ecf20Sopenharmony_ci is_up = 1; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci drain = !is_ax(dd) && is_up; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (drain) 13058c2ecf20Sopenharmony_ci /* 13068c2ecf20Sopenharmony_ci * MTU is specified per-VL. To ensure that no packet gets 13078c2ecf20Sopenharmony_ci * stuck (due, e.g., to the MTU for the packet's VL being 13088c2ecf20Sopenharmony_ci * reduced), empty the per-VL FIFOs before adjusting MTU. 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_ci ret = stop_drain_data_vls(dd); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (ret) { 13138c2ecf20Sopenharmony_ci dd_dev_err(dd, "%s: cannot stop/drain VLs - refusing to change per-VL MTUs\n", 13148c2ecf20Sopenharmony_ci __func__); 13158c2ecf20Sopenharmony_ci goto err; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_MTU, 0); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci if (drain) 13218c2ecf20Sopenharmony_ci open_fill_data_vls(dd); /* reopen all VLs */ 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cierr: 13248c2ecf20Sopenharmony_ci mutex_unlock(&ppd->hls_lock); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci return ret; 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ciint hfi1_set_lid(struct hfi1_pportdata *ppd, u32 lid, u8 lmc) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci ppd->lid = lid; 13348c2ecf20Sopenharmony_ci ppd->lmc = lmc; 13358c2ecf20Sopenharmony_ci hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_LIDLMC, 0); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci dd_dev_info(dd, "port %u: got a lid: 0x%x\n", ppd->port, lid); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci return 0; 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_civoid shutdown_led_override(struct hfi1_pportdata *ppd) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* 13478c2ecf20Sopenharmony_ci * This pairs with the memory barrier in hfi1_start_led_override to 13488c2ecf20Sopenharmony_ci * ensure that we read the correct state of LED beaconing represented 13498c2ecf20Sopenharmony_ci * by led_override_timer_active 13508c2ecf20Sopenharmony_ci */ 13518c2ecf20Sopenharmony_ci smp_rmb(); 13528c2ecf20Sopenharmony_ci if (atomic_read(&ppd->led_override_timer_active)) { 13538c2ecf20Sopenharmony_ci del_timer_sync(&ppd->led_override_timer); 13548c2ecf20Sopenharmony_ci atomic_set(&ppd->led_override_timer_active, 0); 13558c2ecf20Sopenharmony_ci /* Ensure the atomic_set is visible to all CPUs */ 13568c2ecf20Sopenharmony_ci smp_wmb(); 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* Hand control of the LED to the DC for normal operation */ 13608c2ecf20Sopenharmony_ci write_csr(dd, DCC_CFG_LED_CNTRL, 0); 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic void run_led_override(struct timer_list *t) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci struct hfi1_pportdata *ppd = from_timer(ppd, t, led_override_timer); 13668c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 13678c2ecf20Sopenharmony_ci unsigned long timeout; 13688c2ecf20Sopenharmony_ci int phase_idx; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (!(dd->flags & HFI1_INITTED)) 13718c2ecf20Sopenharmony_ci return; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci phase_idx = ppd->led_override_phase & 1; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci setextled(dd, phase_idx); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci timeout = ppd->led_override_vals[phase_idx]; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci /* Set up for next phase */ 13808c2ecf20Sopenharmony_ci ppd->led_override_phase = !ppd->led_override_phase; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci mod_timer(&ppd->led_override_timer, jiffies + timeout); 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci/* 13868c2ecf20Sopenharmony_ci * To have the LED blink in a particular pattern, provide timeon and timeoff 13878c2ecf20Sopenharmony_ci * in milliseconds. 13888c2ecf20Sopenharmony_ci * To turn off custom blinking and return to normal operation, use 13898c2ecf20Sopenharmony_ci * shutdown_led_override() 13908c2ecf20Sopenharmony_ci */ 13918c2ecf20Sopenharmony_civoid hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon, 13928c2ecf20Sopenharmony_ci unsigned int timeoff) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci if (!(ppd->dd->flags & HFI1_INITTED)) 13958c2ecf20Sopenharmony_ci return; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci /* Convert to jiffies for direct use in timer */ 13988c2ecf20Sopenharmony_ci ppd->led_override_vals[0] = msecs_to_jiffies(timeoff); 13998c2ecf20Sopenharmony_ci ppd->led_override_vals[1] = msecs_to_jiffies(timeon); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci /* Arbitrarily start from LED on phase */ 14028c2ecf20Sopenharmony_ci ppd->led_override_phase = 1; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci /* 14058c2ecf20Sopenharmony_ci * If the timer has not already been started, do so. Use a "quick" 14068c2ecf20Sopenharmony_ci * timeout so the handler will be called soon to look at our request. 14078c2ecf20Sopenharmony_ci */ 14088c2ecf20Sopenharmony_ci if (!timer_pending(&ppd->led_override_timer)) { 14098c2ecf20Sopenharmony_ci timer_setup(&ppd->led_override_timer, run_led_override, 0); 14108c2ecf20Sopenharmony_ci ppd->led_override_timer.expires = jiffies + 1; 14118c2ecf20Sopenharmony_ci add_timer(&ppd->led_override_timer); 14128c2ecf20Sopenharmony_ci atomic_set(&ppd->led_override_timer_active, 1); 14138c2ecf20Sopenharmony_ci /* Ensure the atomic_set is visible to all CPUs */ 14148c2ecf20Sopenharmony_ci smp_wmb(); 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci/** 14198c2ecf20Sopenharmony_ci * hfi1_reset_device - reset the chip if possible 14208c2ecf20Sopenharmony_ci * @unit: the device to reset 14218c2ecf20Sopenharmony_ci * 14228c2ecf20Sopenharmony_ci * Whether or not reset is successful, we attempt to re-initialize the chip 14238c2ecf20Sopenharmony_ci * (that is, much like a driver unload/reload). We clear the INITTED flag 14248c2ecf20Sopenharmony_ci * so that the various entry points will fail until we reinitialize. For 14258c2ecf20Sopenharmony_ci * now, we only allow this if no user contexts are open that use chip resources 14268c2ecf20Sopenharmony_ci */ 14278c2ecf20Sopenharmony_ciint hfi1_reset_device(int unit) 14288c2ecf20Sopenharmony_ci{ 14298c2ecf20Sopenharmony_ci int ret; 14308c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = hfi1_lookup(unit); 14318c2ecf20Sopenharmony_ci struct hfi1_pportdata *ppd; 14328c2ecf20Sopenharmony_ci int pidx; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (!dd) { 14358c2ecf20Sopenharmony_ci ret = -ENODEV; 14368c2ecf20Sopenharmony_ci goto bail; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci dd_dev_info(dd, "Reset on unit %u requested\n", unit); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci if (!dd->kregbase1 || !(dd->flags & HFI1_PRESENT)) { 14428c2ecf20Sopenharmony_ci dd_dev_info(dd, 14438c2ecf20Sopenharmony_ci "Invalid unit number %u or not initialized or not present\n", 14448c2ecf20Sopenharmony_ci unit); 14458c2ecf20Sopenharmony_ci ret = -ENXIO; 14468c2ecf20Sopenharmony_ci goto bail; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci /* If there are any user/vnic contexts, we cannot reset */ 14508c2ecf20Sopenharmony_ci mutex_lock(&hfi1_mutex); 14518c2ecf20Sopenharmony_ci if (dd->rcd) 14528c2ecf20Sopenharmony_ci if (hfi1_stats.sps_ctxts) { 14538c2ecf20Sopenharmony_ci mutex_unlock(&hfi1_mutex); 14548c2ecf20Sopenharmony_ci ret = -EBUSY; 14558c2ecf20Sopenharmony_ci goto bail; 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci mutex_unlock(&hfi1_mutex); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci for (pidx = 0; pidx < dd->num_pports; ++pidx) { 14608c2ecf20Sopenharmony_ci ppd = dd->pport + pidx; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci shutdown_led_override(ppd); 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci if (dd->flags & HFI1_HAS_SEND_DMA) 14658c2ecf20Sopenharmony_ci sdma_exit(dd); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci hfi1_reset_cpu_counters(dd); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci ret = hfi1_init(dd, 1); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if (ret) 14728c2ecf20Sopenharmony_ci dd_dev_err(dd, 14738c2ecf20Sopenharmony_ci "Reinitialize unit %u after reset failed with %d\n", 14748c2ecf20Sopenharmony_ci unit, ret); 14758c2ecf20Sopenharmony_ci else 14768c2ecf20Sopenharmony_ci dd_dev_info(dd, "Reinitialized unit %u after resetting\n", 14778c2ecf20Sopenharmony_ci unit); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cibail: 14808c2ecf20Sopenharmony_ci return ret; 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_cistatic inline void hfi1_setup_ib_header(struct hfi1_packet *packet) 14848c2ecf20Sopenharmony_ci{ 14858c2ecf20Sopenharmony_ci packet->hdr = (struct hfi1_ib_message_header *) 14868c2ecf20Sopenharmony_ci hfi1_get_msgheader(packet->rcd, 14878c2ecf20Sopenharmony_ci packet->rhf_addr); 14888c2ecf20Sopenharmony_ci packet->hlen = (u8 *)packet->rhf_addr - (u8 *)packet->hdr; 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cistatic int hfi1_bypass_ingress_pkt_check(struct hfi1_packet *packet) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci struct hfi1_pportdata *ppd = packet->rcd->ppd; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci /* slid and dlid cannot be 0 */ 14968c2ecf20Sopenharmony_ci if ((!packet->slid) || (!packet->dlid)) 14978c2ecf20Sopenharmony_ci return -EINVAL; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* Compare port lid with incoming packet dlid */ 15008c2ecf20Sopenharmony_ci if ((!(hfi1_is_16B_mcast(packet->dlid))) && 15018c2ecf20Sopenharmony_ci (packet->dlid != 15028c2ecf20Sopenharmony_ci opa_get_lid(be32_to_cpu(OPA_LID_PERMISSIVE), 16B))) { 15038c2ecf20Sopenharmony_ci if ((packet->dlid & ~((1 << ppd->lmc) - 1)) != ppd->lid) 15048c2ecf20Sopenharmony_ci return -EINVAL; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci /* No multicast packets with SC15 */ 15088c2ecf20Sopenharmony_ci if ((hfi1_is_16B_mcast(packet->dlid)) && (packet->sc == 0xF)) 15098c2ecf20Sopenharmony_ci return -EINVAL; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci /* Packets with permissive DLID always on SC15 */ 15128c2ecf20Sopenharmony_ci if ((packet->dlid == opa_get_lid(be32_to_cpu(OPA_LID_PERMISSIVE), 15138c2ecf20Sopenharmony_ci 16B)) && 15148c2ecf20Sopenharmony_ci (packet->sc != 0xF)) 15158c2ecf20Sopenharmony_ci return -EINVAL; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci return 0; 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_cistatic int hfi1_setup_9B_packet(struct hfi1_packet *packet) 15218c2ecf20Sopenharmony_ci{ 15228c2ecf20Sopenharmony_ci struct hfi1_ibport *ibp = rcd_to_iport(packet->rcd); 15238c2ecf20Sopenharmony_ci struct ib_header *hdr; 15248c2ecf20Sopenharmony_ci u8 lnh; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci hfi1_setup_ib_header(packet); 15278c2ecf20Sopenharmony_ci hdr = packet->hdr; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci lnh = ib_get_lnh(hdr); 15308c2ecf20Sopenharmony_ci if (lnh == HFI1_LRH_BTH) { 15318c2ecf20Sopenharmony_ci packet->ohdr = &hdr->u.oth; 15328c2ecf20Sopenharmony_ci packet->grh = NULL; 15338c2ecf20Sopenharmony_ci } else if (lnh == HFI1_LRH_GRH) { 15348c2ecf20Sopenharmony_ci u32 vtf; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci packet->ohdr = &hdr->u.l.oth; 15378c2ecf20Sopenharmony_ci packet->grh = &hdr->u.l.grh; 15388c2ecf20Sopenharmony_ci if (packet->grh->next_hdr != IB_GRH_NEXT_HDR) 15398c2ecf20Sopenharmony_ci goto drop; 15408c2ecf20Sopenharmony_ci vtf = be32_to_cpu(packet->grh->version_tclass_flow); 15418c2ecf20Sopenharmony_ci if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) 15428c2ecf20Sopenharmony_ci goto drop; 15438c2ecf20Sopenharmony_ci } else { 15448c2ecf20Sopenharmony_ci goto drop; 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci /* Query commonly used fields from packet header */ 15488c2ecf20Sopenharmony_ci packet->payload = packet->ebuf; 15498c2ecf20Sopenharmony_ci packet->opcode = ib_bth_get_opcode(packet->ohdr); 15508c2ecf20Sopenharmony_ci packet->slid = ib_get_slid(hdr); 15518c2ecf20Sopenharmony_ci packet->dlid = ib_get_dlid(hdr); 15528c2ecf20Sopenharmony_ci if (unlikely((packet->dlid >= be16_to_cpu(IB_MULTICAST_LID_BASE)) && 15538c2ecf20Sopenharmony_ci (packet->dlid != be16_to_cpu(IB_LID_PERMISSIVE)))) 15548c2ecf20Sopenharmony_ci packet->dlid += opa_get_mcast_base(OPA_MCAST_NR) - 15558c2ecf20Sopenharmony_ci be16_to_cpu(IB_MULTICAST_LID_BASE); 15568c2ecf20Sopenharmony_ci packet->sl = ib_get_sl(hdr); 15578c2ecf20Sopenharmony_ci packet->sc = hfi1_9B_get_sc5(hdr, packet->rhf); 15588c2ecf20Sopenharmony_ci packet->pad = ib_bth_get_pad(packet->ohdr); 15598c2ecf20Sopenharmony_ci packet->extra_byte = 0; 15608c2ecf20Sopenharmony_ci packet->pkey = ib_bth_get_pkey(packet->ohdr); 15618c2ecf20Sopenharmony_ci packet->migrated = ib_bth_is_migration(packet->ohdr); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci return 0; 15648c2ecf20Sopenharmony_cidrop: 15658c2ecf20Sopenharmony_ci ibp->rvp.n_pkt_drops++; 15668c2ecf20Sopenharmony_ci return -EINVAL; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic int hfi1_setup_bypass_packet(struct hfi1_packet *packet) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci /* 15728c2ecf20Sopenharmony_ci * Bypass packets have a different header/payload split 15738c2ecf20Sopenharmony_ci * compared to an IB packet. 15748c2ecf20Sopenharmony_ci * Current split is set such that 16 bytes of the actual 15758c2ecf20Sopenharmony_ci * header is in the header buffer and the remining is in 15768c2ecf20Sopenharmony_ci * the eager buffer. We chose 16 since hfi1 driver only 15778c2ecf20Sopenharmony_ci * supports 16B bypass packets and we will be able to 15788c2ecf20Sopenharmony_ci * receive the entire LRH with such a split. 15798c2ecf20Sopenharmony_ci */ 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 15828c2ecf20Sopenharmony_ci struct hfi1_pportdata *ppd = rcd->ppd; 15838c2ecf20Sopenharmony_ci struct hfi1_ibport *ibp = &ppd->ibport_data; 15848c2ecf20Sopenharmony_ci u8 l4; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci packet->hdr = (struct hfi1_16b_header *) 15878c2ecf20Sopenharmony_ci hfi1_get_16B_header(packet->rcd, 15888c2ecf20Sopenharmony_ci packet->rhf_addr); 15898c2ecf20Sopenharmony_ci l4 = hfi1_16B_get_l4(packet->hdr); 15908c2ecf20Sopenharmony_ci if (l4 == OPA_16B_L4_IB_LOCAL) { 15918c2ecf20Sopenharmony_ci packet->ohdr = packet->ebuf; 15928c2ecf20Sopenharmony_ci packet->grh = NULL; 15938c2ecf20Sopenharmony_ci packet->opcode = ib_bth_get_opcode(packet->ohdr); 15948c2ecf20Sopenharmony_ci packet->pad = hfi1_16B_bth_get_pad(packet->ohdr); 15958c2ecf20Sopenharmony_ci /* hdr_len_by_opcode already has an IB LRH factored in */ 15968c2ecf20Sopenharmony_ci packet->hlen = hdr_len_by_opcode[packet->opcode] + 15978c2ecf20Sopenharmony_ci (LRH_16B_BYTES - LRH_9B_BYTES); 15988c2ecf20Sopenharmony_ci packet->migrated = opa_bth_is_migration(packet->ohdr); 15998c2ecf20Sopenharmony_ci } else if (l4 == OPA_16B_L4_IB_GLOBAL) { 16008c2ecf20Sopenharmony_ci u32 vtf; 16018c2ecf20Sopenharmony_ci u8 grh_len = sizeof(struct ib_grh); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci packet->ohdr = packet->ebuf + grh_len; 16048c2ecf20Sopenharmony_ci packet->grh = packet->ebuf; 16058c2ecf20Sopenharmony_ci packet->opcode = ib_bth_get_opcode(packet->ohdr); 16068c2ecf20Sopenharmony_ci packet->pad = hfi1_16B_bth_get_pad(packet->ohdr); 16078c2ecf20Sopenharmony_ci /* hdr_len_by_opcode already has an IB LRH factored in */ 16088c2ecf20Sopenharmony_ci packet->hlen = hdr_len_by_opcode[packet->opcode] + 16098c2ecf20Sopenharmony_ci (LRH_16B_BYTES - LRH_9B_BYTES) + grh_len; 16108c2ecf20Sopenharmony_ci packet->migrated = opa_bth_is_migration(packet->ohdr); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (packet->grh->next_hdr != IB_GRH_NEXT_HDR) 16138c2ecf20Sopenharmony_ci goto drop; 16148c2ecf20Sopenharmony_ci vtf = be32_to_cpu(packet->grh->version_tclass_flow); 16158c2ecf20Sopenharmony_ci if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) 16168c2ecf20Sopenharmony_ci goto drop; 16178c2ecf20Sopenharmony_ci } else if (l4 == OPA_16B_L4_FM) { 16188c2ecf20Sopenharmony_ci packet->mgmt = packet->ebuf; 16198c2ecf20Sopenharmony_ci packet->ohdr = NULL; 16208c2ecf20Sopenharmony_ci packet->grh = NULL; 16218c2ecf20Sopenharmony_ci packet->opcode = IB_OPCODE_UD_SEND_ONLY; 16228c2ecf20Sopenharmony_ci packet->pad = OPA_16B_L4_FM_PAD; 16238c2ecf20Sopenharmony_ci packet->hlen = OPA_16B_L4_FM_HLEN; 16248c2ecf20Sopenharmony_ci packet->migrated = false; 16258c2ecf20Sopenharmony_ci } else { 16268c2ecf20Sopenharmony_ci goto drop; 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci /* Query commonly used fields from packet header */ 16308c2ecf20Sopenharmony_ci packet->payload = packet->ebuf + packet->hlen - LRH_16B_BYTES; 16318c2ecf20Sopenharmony_ci packet->slid = hfi1_16B_get_slid(packet->hdr); 16328c2ecf20Sopenharmony_ci packet->dlid = hfi1_16B_get_dlid(packet->hdr); 16338c2ecf20Sopenharmony_ci if (unlikely(hfi1_is_16B_mcast(packet->dlid))) 16348c2ecf20Sopenharmony_ci packet->dlid += opa_get_mcast_base(OPA_MCAST_NR) - 16358c2ecf20Sopenharmony_ci opa_get_lid(opa_get_mcast_base(OPA_MCAST_NR), 16368c2ecf20Sopenharmony_ci 16B); 16378c2ecf20Sopenharmony_ci packet->sc = hfi1_16B_get_sc(packet->hdr); 16388c2ecf20Sopenharmony_ci packet->sl = ibp->sc_to_sl[packet->sc]; 16398c2ecf20Sopenharmony_ci packet->extra_byte = SIZE_OF_LT; 16408c2ecf20Sopenharmony_ci packet->pkey = hfi1_16B_get_pkey(packet->hdr); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (hfi1_bypass_ingress_pkt_check(packet)) 16438c2ecf20Sopenharmony_ci goto drop; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci return 0; 16468c2ecf20Sopenharmony_cidrop: 16478c2ecf20Sopenharmony_ci hfi1_cdbg(PKT, "%s: packet dropped\n", __func__); 16488c2ecf20Sopenharmony_ci ibp->rvp.n_pkt_drops++; 16498c2ecf20Sopenharmony_ci return -EINVAL; 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic void show_eflags_errs(struct hfi1_packet *packet) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 16558c2ecf20Sopenharmony_ci u32 rte = rhf_rcv_type_err(packet->rhf); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci dd_dev_err(rcd->dd, 16588c2ecf20Sopenharmony_ci "receive context %d: rhf 0x%016llx, errs [ %s%s%s%s%s%s%s] rte 0x%x\n", 16598c2ecf20Sopenharmony_ci rcd->ctxt, packet->rhf, 16608c2ecf20Sopenharmony_ci packet->rhf & RHF_K_HDR_LEN_ERR ? "k_hdr_len " : "", 16618c2ecf20Sopenharmony_ci packet->rhf & RHF_DC_UNC_ERR ? "dc_unc " : "", 16628c2ecf20Sopenharmony_ci packet->rhf & RHF_DC_ERR ? "dc " : "", 16638c2ecf20Sopenharmony_ci packet->rhf & RHF_TID_ERR ? "tid " : "", 16648c2ecf20Sopenharmony_ci packet->rhf & RHF_LEN_ERR ? "len " : "", 16658c2ecf20Sopenharmony_ci packet->rhf & RHF_ECC_ERR ? "ecc " : "", 16668c2ecf20Sopenharmony_ci packet->rhf & RHF_ICRC_ERR ? "icrc " : "", 16678c2ecf20Sopenharmony_ci rte); 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_civoid handle_eflags(struct hfi1_packet *packet) 16718c2ecf20Sopenharmony_ci{ 16728c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci rcv_hdrerr(rcd, rcd->ppd, packet); 16758c2ecf20Sopenharmony_ci if (rhf_err_flags(packet->rhf)) 16768c2ecf20Sopenharmony_ci show_eflags_errs(packet); 16778c2ecf20Sopenharmony_ci} 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_cistatic void hfi1_ipoib_ib_rcv(struct hfi1_packet *packet) 16808c2ecf20Sopenharmony_ci{ 16818c2ecf20Sopenharmony_ci struct hfi1_ibport *ibp; 16828c2ecf20Sopenharmony_ci struct net_device *netdev; 16838c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 16848c2ecf20Sopenharmony_ci struct napi_struct *napi = rcd->napi; 16858c2ecf20Sopenharmony_ci struct sk_buff *skb; 16868c2ecf20Sopenharmony_ci struct hfi1_netdev_rxq *rxq = container_of(napi, 16878c2ecf20Sopenharmony_ci struct hfi1_netdev_rxq, napi); 16888c2ecf20Sopenharmony_ci u32 extra_bytes; 16898c2ecf20Sopenharmony_ci u32 tlen, qpnum; 16908c2ecf20Sopenharmony_ci bool do_work, do_cnp; 16918c2ecf20Sopenharmony_ci struct hfi1_ipoib_dev_priv *priv; 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci trace_hfi1_rcvhdr(packet); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci hfi1_setup_ib_header(packet); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci packet->ohdr = &((struct ib_header *)packet->hdr)->u.oth; 16988c2ecf20Sopenharmony_ci packet->grh = NULL; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 17018c2ecf20Sopenharmony_ci handle_eflags(packet); 17028c2ecf20Sopenharmony_ci return; 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci qpnum = ib_bth_get_qpn(packet->ohdr); 17068c2ecf20Sopenharmony_ci netdev = hfi1_netdev_get_data(rcd->dd, qpnum); 17078c2ecf20Sopenharmony_ci if (!netdev) 17088c2ecf20Sopenharmony_ci goto drop_no_nd; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci trace_input_ibhdr(rcd->dd, packet, !!(rhf_dc_info(packet->rhf))); 17118c2ecf20Sopenharmony_ci trace_ctxt_rsm_hist(rcd->ctxt); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci /* handle congestion notifications */ 17148c2ecf20Sopenharmony_ci do_work = hfi1_may_ecn(packet); 17158c2ecf20Sopenharmony_ci if (unlikely(do_work)) { 17168c2ecf20Sopenharmony_ci do_cnp = (packet->opcode != IB_OPCODE_CNP); 17178c2ecf20Sopenharmony_ci (void)hfi1_process_ecn_slowpath(hfi1_ipoib_priv(netdev)->qp, 17188c2ecf20Sopenharmony_ci packet, do_cnp); 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci /* 17228c2ecf20Sopenharmony_ci * We have split point after last byte of DETH 17238c2ecf20Sopenharmony_ci * lets strip padding and CRC and ICRC. 17248c2ecf20Sopenharmony_ci * tlen is whole packet len so we need to 17258c2ecf20Sopenharmony_ci * subtract header size as well. 17268c2ecf20Sopenharmony_ci */ 17278c2ecf20Sopenharmony_ci tlen = packet->tlen; 17288c2ecf20Sopenharmony_ci extra_bytes = ib_bth_get_pad(packet->ohdr) + (SIZE_OF_CRC << 2) + 17298c2ecf20Sopenharmony_ci packet->hlen; 17308c2ecf20Sopenharmony_ci if (unlikely(tlen < extra_bytes)) 17318c2ecf20Sopenharmony_ci goto drop; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci tlen -= extra_bytes; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci skb = hfi1_ipoib_prepare_skb(rxq, tlen, packet->ebuf); 17368c2ecf20Sopenharmony_ci if (unlikely(!skb)) 17378c2ecf20Sopenharmony_ci goto drop; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci priv = hfi1_ipoib_priv(netdev); 17408c2ecf20Sopenharmony_ci hfi1_ipoib_update_rx_netstats(priv, 1, skb->len); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci skb->dev = netdev; 17438c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_HOST; 17448c2ecf20Sopenharmony_ci netif_receive_skb(skb); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci return; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_cidrop: 17498c2ecf20Sopenharmony_ci ++netdev->stats.rx_dropped; 17508c2ecf20Sopenharmony_cidrop_no_nd: 17518c2ecf20Sopenharmony_ci ibp = rcd_to_iport(packet->rcd); 17528c2ecf20Sopenharmony_ci ++ibp->rvp.n_pkt_drops; 17538c2ecf20Sopenharmony_ci} 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci/* 17568c2ecf20Sopenharmony_ci * The following functions are called by the interrupt handler. They are type 17578c2ecf20Sopenharmony_ci * specific handlers for each packet type. 17588c2ecf20Sopenharmony_ci */ 17598c2ecf20Sopenharmony_cistatic void process_receive_ib(struct hfi1_packet *packet) 17608c2ecf20Sopenharmony_ci{ 17618c2ecf20Sopenharmony_ci if (hfi1_setup_9B_packet(packet)) 17628c2ecf20Sopenharmony_ci return; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (unlikely(hfi1_dbg_should_fault_rx(packet))) 17658c2ecf20Sopenharmony_ci return; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci trace_hfi1_rcvhdr(packet); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 17708c2ecf20Sopenharmony_ci handle_eflags(packet); 17718c2ecf20Sopenharmony_ci return; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci hfi1_ib_rcv(packet); 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cistatic void process_receive_bypass(struct hfi1_packet *packet) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = packet->rcd->dd; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci if (hfi1_setup_bypass_packet(packet)) 17828c2ecf20Sopenharmony_ci return; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci trace_hfi1_rcvhdr(packet); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 17878c2ecf20Sopenharmony_ci handle_eflags(packet); 17888c2ecf20Sopenharmony_ci return; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci if (hfi1_16B_get_l2(packet->hdr) == 0x2) { 17928c2ecf20Sopenharmony_ci hfi1_16B_rcv(packet); 17938c2ecf20Sopenharmony_ci } else { 17948c2ecf20Sopenharmony_ci dd_dev_err(dd, 17958c2ecf20Sopenharmony_ci "Bypass packets other than 16B are not supported in normal operation. Dropping\n"); 17968c2ecf20Sopenharmony_ci incr_cntr64(&dd->sw_rcv_bypass_packet_errors); 17978c2ecf20Sopenharmony_ci if (!(dd->err_info_rcvport.status_and_code & 17988c2ecf20Sopenharmony_ci OPA_EI_STATUS_SMASK)) { 17998c2ecf20Sopenharmony_ci u64 *flits = packet->ebuf; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (flits && !(packet->rhf & RHF_LEN_ERR)) { 18028c2ecf20Sopenharmony_ci dd->err_info_rcvport.packet_flit1 = flits[0]; 18038c2ecf20Sopenharmony_ci dd->err_info_rcvport.packet_flit2 = 18048c2ecf20Sopenharmony_ci packet->tlen > sizeof(flits[0]) ? 18058c2ecf20Sopenharmony_ci flits[1] : 0; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci dd->err_info_rcvport.status_and_code |= 18088c2ecf20Sopenharmony_ci (OPA_EI_STATUS_SMASK | BAD_L2_ERR); 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_cistatic void process_receive_error(struct hfi1_packet *packet) 18148c2ecf20Sopenharmony_ci{ 18158c2ecf20Sopenharmony_ci /* KHdrHCRCErr -- KDETH packet with a bad HCRC */ 18168c2ecf20Sopenharmony_ci if (unlikely( 18178c2ecf20Sopenharmony_ci hfi1_dbg_fault_suppress_err(&packet->rcd->dd->verbs_dev) && 18188c2ecf20Sopenharmony_ci (rhf_rcv_type_err(packet->rhf) == RHF_RCV_TYPE_ERROR || 18198c2ecf20Sopenharmony_ci packet->rhf & RHF_DC_ERR))) 18208c2ecf20Sopenharmony_ci return; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci hfi1_setup_ib_header(packet); 18238c2ecf20Sopenharmony_ci handle_eflags(packet); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) 18268c2ecf20Sopenharmony_ci dd_dev_err(packet->rcd->dd, 18278c2ecf20Sopenharmony_ci "Unhandled error packet received. Dropping.\n"); 18288c2ecf20Sopenharmony_ci} 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_cistatic void kdeth_process_expected(struct hfi1_packet *packet) 18318c2ecf20Sopenharmony_ci{ 18328c2ecf20Sopenharmony_ci hfi1_setup_9B_packet(packet); 18338c2ecf20Sopenharmony_ci if (unlikely(hfi1_dbg_should_fault_rx(packet))) 18348c2ecf20Sopenharmony_ci return; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 18378c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (hfi1_handle_kdeth_eflags(rcd, rcd->ppd, packet)) 18408c2ecf20Sopenharmony_ci return; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci hfi1_kdeth_expected_rcv(packet); 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_cistatic void kdeth_process_eager(struct hfi1_packet *packet) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci hfi1_setup_9B_packet(packet); 18498c2ecf20Sopenharmony_ci if (unlikely(hfi1_dbg_should_fault_rx(packet))) 18508c2ecf20Sopenharmony_ci return; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci trace_hfi1_rcvhdr(packet); 18538c2ecf20Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 18548c2ecf20Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci show_eflags_errs(packet); 18578c2ecf20Sopenharmony_ci if (hfi1_handle_kdeth_eflags(rcd, rcd->ppd, packet)) 18588c2ecf20Sopenharmony_ci return; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci hfi1_kdeth_eager_rcv(packet); 18628c2ecf20Sopenharmony_ci} 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_cistatic void process_receive_invalid(struct hfi1_packet *packet) 18658c2ecf20Sopenharmony_ci{ 18668c2ecf20Sopenharmony_ci dd_dev_err(packet->rcd->dd, "Invalid packet type %d. Dropping\n", 18678c2ecf20Sopenharmony_ci rhf_rcv_type(packet->rhf)); 18688c2ecf20Sopenharmony_ci} 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci#define HFI1_RCVHDR_DUMP_MAX 5 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_civoid seqfile_dump_rcd(struct seq_file *s, struct hfi1_ctxtdata *rcd) 18738c2ecf20Sopenharmony_ci{ 18748c2ecf20Sopenharmony_ci struct hfi1_packet packet; 18758c2ecf20Sopenharmony_ci struct ps_mdata mdata; 18768c2ecf20Sopenharmony_ci int i; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci seq_printf(s, "Rcd %u: RcvHdr cnt %u entsize %u %s ctrl 0x%08llx status 0x%08llx, head %llu tail %llu sw head %u\n", 18798c2ecf20Sopenharmony_ci rcd->ctxt, get_hdrq_cnt(rcd), get_hdrqentsize(rcd), 18808c2ecf20Sopenharmony_ci get_dma_rtail_setting(rcd) ? 18818c2ecf20Sopenharmony_ci "dma_rtail" : "nodma_rtail", 18828c2ecf20Sopenharmony_ci read_kctxt_csr(rcd->dd, rcd->ctxt, RCV_CTXT_CTRL), 18838c2ecf20Sopenharmony_ci read_kctxt_csr(rcd->dd, rcd->ctxt, RCV_CTXT_STATUS), 18848c2ecf20Sopenharmony_ci read_uctxt_csr(rcd->dd, rcd->ctxt, RCV_HDR_HEAD) & 18858c2ecf20Sopenharmony_ci RCV_HDR_HEAD_HEAD_MASK, 18868c2ecf20Sopenharmony_ci read_uctxt_csr(rcd->dd, rcd->ctxt, RCV_HDR_TAIL), 18878c2ecf20Sopenharmony_ci rcd->head); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci init_packet(rcd, &packet); 18908c2ecf20Sopenharmony_ci init_ps_mdata(&mdata, &packet); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci for (i = 0; i < HFI1_RCVHDR_DUMP_MAX; i++) { 18938c2ecf20Sopenharmony_ci __le32 *rhf_addr = (__le32 *)rcd->rcvhdrq + mdata.ps_head + 18948c2ecf20Sopenharmony_ci rcd->rhf_offset; 18958c2ecf20Sopenharmony_ci struct ib_header *hdr; 18968c2ecf20Sopenharmony_ci u64 rhf = rhf_to_cpu(rhf_addr); 18978c2ecf20Sopenharmony_ci u32 etype = rhf_rcv_type(rhf), qpn; 18988c2ecf20Sopenharmony_ci u8 opcode; 18998c2ecf20Sopenharmony_ci u32 psn; 19008c2ecf20Sopenharmony_ci u8 lnh; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci if (ps_done(&mdata, rhf, rcd)) 19038c2ecf20Sopenharmony_ci break; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if (ps_skip(&mdata, rhf, rcd)) 19068c2ecf20Sopenharmony_ci goto next; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (etype > RHF_RCV_TYPE_IB) 19098c2ecf20Sopenharmony_ci goto next; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci packet.hdr = hfi1_get_msgheader(rcd, rhf_addr); 19128c2ecf20Sopenharmony_ci hdr = packet.hdr; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci lnh = be16_to_cpu(hdr->lrh[0]) & 3; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci if (lnh == HFI1_LRH_BTH) 19178c2ecf20Sopenharmony_ci packet.ohdr = &hdr->u.oth; 19188c2ecf20Sopenharmony_ci else if (lnh == HFI1_LRH_GRH) 19198c2ecf20Sopenharmony_ci packet.ohdr = &hdr->u.l.oth; 19208c2ecf20Sopenharmony_ci else 19218c2ecf20Sopenharmony_ci goto next; /* just in case */ 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci opcode = (be32_to_cpu(packet.ohdr->bth[0]) >> 24); 19248c2ecf20Sopenharmony_ci qpn = be32_to_cpu(packet.ohdr->bth[1]) & RVT_QPN_MASK; 19258c2ecf20Sopenharmony_ci psn = mask_psn(be32_to_cpu(packet.ohdr->bth[2])); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci seq_printf(s, "\tEnt %u: opcode 0x%x, qpn 0x%x, psn 0x%x\n", 19288c2ecf20Sopenharmony_ci mdata.ps_head, opcode, qpn, psn); 19298c2ecf20Sopenharmony_cinext: 19308c2ecf20Sopenharmony_ci update_ps_mdata(&mdata, rcd); 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci} 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ciconst rhf_rcv_function_ptr normal_rhf_rcv_functions[] = { 19358c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_EXPECTED] = kdeth_process_expected, 19368c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_EAGER] = kdeth_process_eager, 19378c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_IB] = process_receive_ib, 19388c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_ERROR] = process_receive_error, 19398c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_BYPASS] = process_receive_bypass, 19408c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_INVALID5] = process_receive_invalid, 19418c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_INVALID6] = process_receive_invalid, 19428c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_INVALID7] = process_receive_invalid, 19438c2ecf20Sopenharmony_ci}; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ciconst rhf_rcv_function_ptr netdev_rhf_rcv_functions[] = { 19468c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_EXPECTED] = process_receive_invalid, 19478c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_EAGER] = process_receive_invalid, 19488c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_IB] = hfi1_ipoib_ib_rcv, 19498c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_ERROR] = process_receive_error, 19508c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_BYPASS] = hfi1_vnic_bypass_rcv, 19518c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_INVALID5] = process_receive_invalid, 19528c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_INVALID6] = process_receive_invalid, 19538c2ecf20Sopenharmony_ci [RHF_RCV_TYPE_INVALID7] = process_receive_invalid, 19548c2ecf20Sopenharmony_ci}; 1955