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