162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2015-2020 Intel Corporation. 462306a36Sopenharmony_ci * Copyright(c) 2021 Cornelis Networks. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/spinlock.h> 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/netdevice.h> 1262306a36Sopenharmony_ci#include <linux/vmalloc.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/prefetch.h> 1562306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 1662306a36Sopenharmony_ci#include <linux/etherdevice.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "hfi.h" 1962306a36Sopenharmony_ci#include "trace.h" 2062306a36Sopenharmony_ci#include "qp.h" 2162306a36Sopenharmony_ci#include "sdma.h" 2262306a36Sopenharmony_ci#include "debugfs.h" 2362306a36Sopenharmony_ci#include "vnic.h" 2462306a36Sopenharmony_ci#include "fault.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "ipoib.h" 2762306a36Sopenharmony_ci#include "netdev.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#undef pr_fmt 3062306a36Sopenharmony_ci#define pr_fmt(fmt) DRIVER_NAME ": " fmt 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciDEFINE_MUTEX(hfi1_mutex); /* general driver use */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciunsigned int hfi1_max_mtu = HFI1_DEFAULT_MAX_MTU; 3562306a36Sopenharmony_cimodule_param_named(max_mtu, hfi1_max_mtu, uint, S_IRUGO); 3662306a36Sopenharmony_ciMODULE_PARM_DESC(max_mtu, "Set max MTU bytes, default is " __stringify( 3762306a36Sopenharmony_ci HFI1_DEFAULT_MAX_MTU)); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciunsigned int hfi1_cu = 1; 4062306a36Sopenharmony_cimodule_param_named(cu, hfi1_cu, uint, S_IRUGO); 4162306a36Sopenharmony_ciMODULE_PARM_DESC(cu, "Credit return units"); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ciunsigned long hfi1_cap_mask = HFI1_CAP_MASK_DEFAULT; 4462306a36Sopenharmony_cistatic int hfi1_caps_set(const char *val, const struct kernel_param *kp); 4562306a36Sopenharmony_cistatic int hfi1_caps_get(char *buffer, const struct kernel_param *kp); 4662306a36Sopenharmony_cistatic const struct kernel_param_ops cap_ops = { 4762306a36Sopenharmony_ci .set = hfi1_caps_set, 4862306a36Sopenharmony_ci .get = hfi1_caps_get 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_cimodule_param_cb(cap_mask, &cap_ops, &hfi1_cap_mask, S_IWUSR | S_IRUGO); 5162306a36Sopenharmony_ciMODULE_PARM_DESC(cap_mask, "Bit mask of enabled/disabled HW features"); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 5462306a36Sopenharmony_ciMODULE_DESCRIPTION("Cornelis Omni-Path Express driver"); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * MAX_PKT_RCV is the max # if packets processed per receive interrupt. 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci#define MAX_PKT_RECV 64 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * MAX_PKT_THREAD_RCV is the max # of packets processed before 6262306a36Sopenharmony_ci * the qp_wait_list queue is flushed. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci#define MAX_PKT_RECV_THREAD (MAX_PKT_RECV * 4) 6562306a36Sopenharmony_ci#define EGR_HEAD_UPDATE_THRESHOLD 16 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistruct hfi1_ib_stats hfi1_stats; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int hfi1_caps_set(const char *val, const struct kernel_param *kp) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci int ret = 0; 7262306a36Sopenharmony_ci unsigned long *cap_mask_ptr = (unsigned long *)kp->arg, 7362306a36Sopenharmony_ci cap_mask = *cap_mask_ptr, value, diff, 7462306a36Sopenharmony_ci write_mask = ((HFI1_CAP_WRITABLE_MASK << HFI1_CAP_USER_SHIFT) | 7562306a36Sopenharmony_ci HFI1_CAP_WRITABLE_MASK); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci ret = kstrtoul(val, 0, &value); 7862306a36Sopenharmony_ci if (ret) { 7962306a36Sopenharmony_ci pr_warn("Invalid module parameter value for 'cap_mask'\n"); 8062306a36Sopenharmony_ci goto done; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci /* Get the changed bits (except the locked bit) */ 8362306a36Sopenharmony_ci diff = value ^ (cap_mask & ~HFI1_CAP_LOCKED_SMASK); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Remove any bits that are not allowed to change after driver load */ 8662306a36Sopenharmony_ci if (HFI1_CAP_LOCKED() && (diff & ~write_mask)) { 8762306a36Sopenharmony_ci pr_warn("Ignoring non-writable capability bits %#lx\n", 8862306a36Sopenharmony_ci diff & ~write_mask); 8962306a36Sopenharmony_ci diff &= write_mask; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Mask off any reserved bits */ 9362306a36Sopenharmony_ci diff &= ~HFI1_CAP_RESERVED_MASK; 9462306a36Sopenharmony_ci /* Clear any previously set and changing bits */ 9562306a36Sopenharmony_ci cap_mask &= ~diff; 9662306a36Sopenharmony_ci /* Update the bits with the new capability */ 9762306a36Sopenharmony_ci cap_mask |= (value & diff); 9862306a36Sopenharmony_ci /* Check for any kernel/user restrictions */ 9962306a36Sopenharmony_ci diff = (cap_mask & (HFI1_CAP_MUST_HAVE_KERN << HFI1_CAP_USER_SHIFT)) ^ 10062306a36Sopenharmony_ci ((cap_mask & HFI1_CAP_MUST_HAVE_KERN) << HFI1_CAP_USER_SHIFT); 10162306a36Sopenharmony_ci cap_mask &= ~diff; 10262306a36Sopenharmony_ci /* Set the bitmask to the final set */ 10362306a36Sopenharmony_ci *cap_mask_ptr = cap_mask; 10462306a36Sopenharmony_cidone: 10562306a36Sopenharmony_ci return ret; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int hfi1_caps_get(char *buffer, const struct kernel_param *kp) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci unsigned long cap_mask = *(unsigned long *)kp->arg; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci cap_mask &= ~HFI1_CAP_LOCKED_SMASK; 11362306a36Sopenharmony_ci cap_mask |= ((cap_mask & HFI1_CAP_K2U) << HFI1_CAP_USER_SHIFT); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return sysfs_emit(buffer, "0x%lx\n", cap_mask); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistruct pci_dev *get_pci_dev(struct rvt_dev_info *rdi) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct hfi1_ibdev *ibdev = container_of(rdi, struct hfi1_ibdev, rdi); 12162306a36Sopenharmony_ci struct hfi1_devdata *dd = container_of(ibdev, 12262306a36Sopenharmony_ci struct hfi1_devdata, verbs_dev); 12362306a36Sopenharmony_ci return dd->pcidev; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * Return count of units with at least one port ACTIVE. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ciint hfi1_count_active_units(void) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct hfi1_devdata *dd; 13262306a36Sopenharmony_ci struct hfi1_pportdata *ppd; 13362306a36Sopenharmony_ci unsigned long index, flags; 13462306a36Sopenharmony_ci int pidx, nunits_active = 0; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci xa_lock_irqsave(&hfi1_dev_table, flags); 13762306a36Sopenharmony_ci xa_for_each(&hfi1_dev_table, index, dd) { 13862306a36Sopenharmony_ci if (!(dd->flags & HFI1_PRESENT) || !dd->kregbase1) 13962306a36Sopenharmony_ci continue; 14062306a36Sopenharmony_ci for (pidx = 0; pidx < dd->num_pports; ++pidx) { 14162306a36Sopenharmony_ci ppd = dd->pport + pidx; 14262306a36Sopenharmony_ci if (ppd->lid && ppd->linkup) { 14362306a36Sopenharmony_ci nunits_active++; 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci xa_unlock_irqrestore(&hfi1_dev_table, flags); 14962306a36Sopenharmony_ci return nunits_active; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* 15362306a36Sopenharmony_ci * Get address of eager buffer from it's index (allocated in chunks, not 15462306a36Sopenharmony_ci * contiguous). 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_cistatic inline void *get_egrbuf(const struct hfi1_ctxtdata *rcd, u64 rhf, 15762306a36Sopenharmony_ci u8 *update) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci u32 idx = rhf_egr_index(rhf), offset = rhf_egr_buf_offset(rhf); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci *update |= !(idx & (rcd->egrbufs.threshold - 1)) && !offset; 16262306a36Sopenharmony_ci return (void *)(((u64)(rcd->egrbufs.rcvtids[idx].addr)) + 16362306a36Sopenharmony_ci (offset * RCV_BUF_BLOCK_SIZE)); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic inline void *hfi1_get_header(struct hfi1_ctxtdata *rcd, 16762306a36Sopenharmony_ci __le32 *rhf_addr) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci u32 offset = rhf_hdrq_offset(rhf_to_cpu(rhf_addr)); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return (void *)(rhf_addr - rcd->rhf_offset + offset); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic inline struct ib_header *hfi1_get_msgheader(struct hfi1_ctxtdata *rcd, 17562306a36Sopenharmony_ci __le32 *rhf_addr) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci return (struct ib_header *)hfi1_get_header(rcd, rhf_addr); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic inline struct hfi1_16b_header 18162306a36Sopenharmony_ci *hfi1_get_16B_header(struct hfi1_ctxtdata *rcd, 18262306a36Sopenharmony_ci __le32 *rhf_addr) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci return (struct hfi1_16b_header *)hfi1_get_header(rcd, rhf_addr); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* 18862306a36Sopenharmony_ci * Validate and encode the a given RcvArray Buffer size. 18962306a36Sopenharmony_ci * The function will check whether the given size falls within 19062306a36Sopenharmony_ci * allowed size ranges for the respective type and, optionally, 19162306a36Sopenharmony_ci * return the proper encoding. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ciint hfi1_rcvbuf_validate(u32 size, u8 type, u16 *encoded) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci if (unlikely(!PAGE_ALIGNED(size))) 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci if (unlikely(size < MIN_EAGER_BUFFER)) 19862306a36Sopenharmony_ci return 0; 19962306a36Sopenharmony_ci if (size > 20062306a36Sopenharmony_ci (type == PT_EAGER ? MAX_EAGER_BUFFER : MAX_EXPECTED_BUFFER)) 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci if (encoded) 20362306a36Sopenharmony_ci *encoded = ilog2(size / PAGE_SIZE) + 1; 20462306a36Sopenharmony_ci return 1; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, 20862306a36Sopenharmony_ci struct hfi1_packet *packet) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct ib_header *rhdr = packet->hdr; 21162306a36Sopenharmony_ci u32 rte = rhf_rcv_type_err(packet->rhf); 21262306a36Sopenharmony_ci u32 mlid_base; 21362306a36Sopenharmony_ci struct hfi1_ibport *ibp = rcd_to_iport(rcd); 21462306a36Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 21562306a36Sopenharmony_ci struct hfi1_ibdev *verbs_dev = &dd->verbs_dev; 21662306a36Sopenharmony_ci struct rvt_dev_info *rdi = &verbs_dev->rdi; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if ((packet->rhf & RHF_DC_ERR) && 21962306a36Sopenharmony_ci hfi1_dbg_fault_suppress_err(verbs_dev)) 22062306a36Sopenharmony_ci return; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (packet->rhf & RHF_ICRC_ERR) 22362306a36Sopenharmony_ci return; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (packet->etype == RHF_RCV_TYPE_BYPASS) { 22662306a36Sopenharmony_ci goto drop; 22762306a36Sopenharmony_ci } else { 22862306a36Sopenharmony_ci u8 lnh = ib_get_lnh(rhdr); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci mlid_base = be16_to_cpu(IB_MULTICAST_LID_BASE); 23162306a36Sopenharmony_ci if (lnh == HFI1_LRH_BTH) { 23262306a36Sopenharmony_ci packet->ohdr = &rhdr->u.oth; 23362306a36Sopenharmony_ci } else if (lnh == HFI1_LRH_GRH) { 23462306a36Sopenharmony_ci packet->ohdr = &rhdr->u.l.oth; 23562306a36Sopenharmony_ci packet->grh = &rhdr->u.l.grh; 23662306a36Sopenharmony_ci } else { 23762306a36Sopenharmony_ci goto drop; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (packet->rhf & RHF_TID_ERR) { 24262306a36Sopenharmony_ci /* For TIDERR and RC QPs preemptively schedule a NAK */ 24362306a36Sopenharmony_ci u32 tlen = rhf_pkt_len(packet->rhf); /* in bytes */ 24462306a36Sopenharmony_ci u32 dlid = ib_get_dlid(rhdr); 24562306a36Sopenharmony_ci u32 qp_num; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Sanity check packet */ 24862306a36Sopenharmony_ci if (tlen < 24) 24962306a36Sopenharmony_ci goto drop; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Check for GRH */ 25262306a36Sopenharmony_ci if (packet->grh) { 25362306a36Sopenharmony_ci u32 vtf; 25462306a36Sopenharmony_ci struct ib_grh *grh = packet->grh; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (grh->next_hdr != IB_GRH_NEXT_HDR) 25762306a36Sopenharmony_ci goto drop; 25862306a36Sopenharmony_ci vtf = be32_to_cpu(grh->version_tclass_flow); 25962306a36Sopenharmony_ci if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) 26062306a36Sopenharmony_ci goto drop; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Get the destination QP number. */ 26462306a36Sopenharmony_ci qp_num = ib_bth_get_qpn(packet->ohdr); 26562306a36Sopenharmony_ci if (dlid < mlid_base) { 26662306a36Sopenharmony_ci struct rvt_qp *qp; 26762306a36Sopenharmony_ci unsigned long flags; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci rcu_read_lock(); 27062306a36Sopenharmony_ci qp = rvt_lookup_qpn(rdi, &ibp->rvp, qp_num); 27162306a36Sopenharmony_ci if (!qp) { 27262306a36Sopenharmony_ci rcu_read_unlock(); 27362306a36Sopenharmony_ci goto drop; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * Handle only RC QPs - for other QP types drop error 27862306a36Sopenharmony_ci * packet. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci spin_lock_irqsave(&qp->r_lock, flags); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* Check for valid receive state. */ 28362306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & 28462306a36Sopenharmony_ci RVT_PROCESS_RECV_OK)) { 28562306a36Sopenharmony_ci ibp->rvp.n_pkt_drops++; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci switch (qp->ibqp.qp_type) { 28962306a36Sopenharmony_ci case IB_QPT_RC: 29062306a36Sopenharmony_ci hfi1_rc_hdrerr(rcd, packet, qp); 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci default: 29362306a36Sopenharmony_ci /* For now don't handle any other QP types */ 29462306a36Sopenharmony_ci break; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 29862306a36Sopenharmony_ci rcu_read_unlock(); 29962306a36Sopenharmony_ci } /* Unicast QP */ 30062306a36Sopenharmony_ci } /* Valid packet with TIDErr */ 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* handle "RcvTypeErr" flags */ 30362306a36Sopenharmony_ci switch (rte) { 30462306a36Sopenharmony_ci case RHF_RTE_ERROR_OP_CODE_ERR: 30562306a36Sopenharmony_ci { 30662306a36Sopenharmony_ci void *ebuf = NULL; 30762306a36Sopenharmony_ci u8 opcode; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (rhf_use_egr_bfr(packet->rhf)) 31062306a36Sopenharmony_ci ebuf = packet->ebuf; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (!ebuf) 31362306a36Sopenharmony_ci goto drop; /* this should never happen */ 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci opcode = ib_bth_get_opcode(packet->ohdr); 31662306a36Sopenharmony_ci if (opcode == IB_OPCODE_CNP) { 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * Only in pre-B0 h/w is the CNP_OPCODE handled 31962306a36Sopenharmony_ci * via this code path. 32062306a36Sopenharmony_ci */ 32162306a36Sopenharmony_ci struct rvt_qp *qp = NULL; 32262306a36Sopenharmony_ci u32 lqpn, rqpn; 32362306a36Sopenharmony_ci u16 rlid; 32462306a36Sopenharmony_ci u8 svc_type, sl, sc5; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci sc5 = hfi1_9B_get_sc5(rhdr, packet->rhf); 32762306a36Sopenharmony_ci sl = ibp->sc_to_sl[sc5]; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci lqpn = ib_bth_get_qpn(packet->ohdr); 33062306a36Sopenharmony_ci rcu_read_lock(); 33162306a36Sopenharmony_ci qp = rvt_lookup_qpn(rdi, &ibp->rvp, lqpn); 33262306a36Sopenharmony_ci if (!qp) { 33362306a36Sopenharmony_ci rcu_read_unlock(); 33462306a36Sopenharmony_ci goto drop; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci switch (qp->ibqp.qp_type) { 33862306a36Sopenharmony_ci case IB_QPT_UD: 33962306a36Sopenharmony_ci rlid = 0; 34062306a36Sopenharmony_ci rqpn = 0; 34162306a36Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UD; 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci case IB_QPT_UC: 34462306a36Sopenharmony_ci rlid = ib_get_slid(rhdr); 34562306a36Sopenharmony_ci rqpn = qp->remote_qpn; 34662306a36Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UC; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci default: 34962306a36Sopenharmony_ci rcu_read_unlock(); 35062306a36Sopenharmony_ci goto drop; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type); 35462306a36Sopenharmony_ci rcu_read_unlock(); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci packet->rhf &= ~RHF_RCV_TYPE_ERR_SMASK; 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci default: 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cidrop: 36562306a36Sopenharmony_ci return; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic inline void init_packet(struct hfi1_ctxtdata *rcd, 36962306a36Sopenharmony_ci struct hfi1_packet *packet) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci packet->rsize = get_hdrqentsize(rcd); /* words */ 37262306a36Sopenharmony_ci packet->maxcnt = get_hdrq_cnt(rcd) * packet->rsize; /* words */ 37362306a36Sopenharmony_ci packet->rcd = rcd; 37462306a36Sopenharmony_ci packet->updegr = 0; 37562306a36Sopenharmony_ci packet->etail = -1; 37662306a36Sopenharmony_ci packet->rhf_addr = get_rhf_addr(rcd); 37762306a36Sopenharmony_ci packet->rhf = rhf_to_cpu(packet->rhf_addr); 37862306a36Sopenharmony_ci packet->rhqoff = hfi1_rcd_head(rcd); 37962306a36Sopenharmony_ci packet->numpkt = 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/* We support only two types - 9B and 16B for now */ 38362306a36Sopenharmony_cistatic const hfi1_handle_cnp hfi1_handle_cnp_tbl[2] = { 38462306a36Sopenharmony_ci [HFI1_PKT_TYPE_9B] = &return_cnp, 38562306a36Sopenharmony_ci [HFI1_PKT_TYPE_16B] = &return_cnp_16B 38662306a36Sopenharmony_ci}; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/** 38962306a36Sopenharmony_ci * hfi1_process_ecn_slowpath - Process FECN or BECN bits 39062306a36Sopenharmony_ci * @qp: The packet's destination QP 39162306a36Sopenharmony_ci * @pkt: The packet itself. 39262306a36Sopenharmony_ci * @prescan: Is the caller the RXQ prescan 39362306a36Sopenharmony_ci * 39462306a36Sopenharmony_ci * Process the packet's FECN or BECN bits. By now, the packet 39562306a36Sopenharmony_ci * has already been evaluated whether processing of those bit should 39662306a36Sopenharmony_ci * be done. 39762306a36Sopenharmony_ci * The significance of the @prescan argument is that if the caller 39862306a36Sopenharmony_ci * is the RXQ prescan, a CNP will be send out instead of waiting for the 39962306a36Sopenharmony_ci * normal packet processing to send an ACK with BECN set (or a CNP). 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_cibool hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt, 40262306a36Sopenharmony_ci bool prescan) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); 40562306a36Sopenharmony_ci struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); 40662306a36Sopenharmony_ci struct ib_other_headers *ohdr = pkt->ohdr; 40762306a36Sopenharmony_ci struct ib_grh *grh = pkt->grh; 40862306a36Sopenharmony_ci u32 rqpn = 0; 40962306a36Sopenharmony_ci u16 pkey; 41062306a36Sopenharmony_ci u32 rlid, slid, dlid = 0; 41162306a36Sopenharmony_ci u8 hdr_type, sc, svc_type, opcode; 41262306a36Sopenharmony_ci bool is_mcast = false, ignore_fecn = false, do_cnp = false, 41362306a36Sopenharmony_ci fecn, becn; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* can be called from prescan */ 41662306a36Sopenharmony_ci if (pkt->etype == RHF_RCV_TYPE_BYPASS) { 41762306a36Sopenharmony_ci pkey = hfi1_16B_get_pkey(pkt->hdr); 41862306a36Sopenharmony_ci sc = hfi1_16B_get_sc(pkt->hdr); 41962306a36Sopenharmony_ci dlid = hfi1_16B_get_dlid(pkt->hdr); 42062306a36Sopenharmony_ci slid = hfi1_16B_get_slid(pkt->hdr); 42162306a36Sopenharmony_ci is_mcast = hfi1_is_16B_mcast(dlid); 42262306a36Sopenharmony_ci opcode = ib_bth_get_opcode(ohdr); 42362306a36Sopenharmony_ci hdr_type = HFI1_PKT_TYPE_16B; 42462306a36Sopenharmony_ci fecn = hfi1_16B_get_fecn(pkt->hdr); 42562306a36Sopenharmony_ci becn = hfi1_16B_get_becn(pkt->hdr); 42662306a36Sopenharmony_ci } else { 42762306a36Sopenharmony_ci pkey = ib_bth_get_pkey(ohdr); 42862306a36Sopenharmony_ci sc = hfi1_9B_get_sc5(pkt->hdr, pkt->rhf); 42962306a36Sopenharmony_ci dlid = qp->ibqp.qp_type != IB_QPT_UD ? ib_get_dlid(pkt->hdr) : 43062306a36Sopenharmony_ci ppd->lid; 43162306a36Sopenharmony_ci slid = ib_get_slid(pkt->hdr); 43262306a36Sopenharmony_ci is_mcast = (dlid > be16_to_cpu(IB_MULTICAST_LID_BASE)) && 43362306a36Sopenharmony_ci (dlid != be16_to_cpu(IB_LID_PERMISSIVE)); 43462306a36Sopenharmony_ci opcode = ib_bth_get_opcode(ohdr); 43562306a36Sopenharmony_ci hdr_type = HFI1_PKT_TYPE_9B; 43662306a36Sopenharmony_ci fecn = ib_bth_get_fecn(ohdr); 43762306a36Sopenharmony_ci becn = ib_bth_get_becn(ohdr); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci switch (qp->ibqp.qp_type) { 44162306a36Sopenharmony_ci case IB_QPT_UD: 44262306a36Sopenharmony_ci rlid = slid; 44362306a36Sopenharmony_ci rqpn = ib_get_sqpn(pkt->ohdr); 44462306a36Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UD; 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci case IB_QPT_SMI: 44762306a36Sopenharmony_ci case IB_QPT_GSI: 44862306a36Sopenharmony_ci rlid = slid; 44962306a36Sopenharmony_ci rqpn = ib_get_sqpn(pkt->ohdr); 45062306a36Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UD; 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci case IB_QPT_UC: 45362306a36Sopenharmony_ci rlid = rdma_ah_get_dlid(&qp->remote_ah_attr); 45462306a36Sopenharmony_ci rqpn = qp->remote_qpn; 45562306a36Sopenharmony_ci svc_type = IB_CC_SVCTYPE_UC; 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci case IB_QPT_RC: 45862306a36Sopenharmony_ci rlid = rdma_ah_get_dlid(&qp->remote_ah_attr); 45962306a36Sopenharmony_ci rqpn = qp->remote_qpn; 46062306a36Sopenharmony_ci svc_type = IB_CC_SVCTYPE_RC; 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci default: 46362306a36Sopenharmony_ci return false; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci ignore_fecn = is_mcast || (opcode == IB_OPCODE_CNP) || 46762306a36Sopenharmony_ci (opcode == IB_OPCODE_RC_ACKNOWLEDGE); 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * ACKNOWLEDGE packets do not get a CNP but this will be 47062306a36Sopenharmony_ci * guarded by ignore_fecn above. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci do_cnp = prescan || 47362306a36Sopenharmony_ci (opcode >= IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST && 47462306a36Sopenharmony_ci opcode <= IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE) || 47562306a36Sopenharmony_ci opcode == TID_OP(READ_RESP) || 47662306a36Sopenharmony_ci opcode == TID_OP(ACK); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* Call appropriate CNP handler */ 47962306a36Sopenharmony_ci if (!ignore_fecn && do_cnp && fecn) 48062306a36Sopenharmony_ci hfi1_handle_cnp_tbl[hdr_type](ibp, qp, rqpn, pkey, 48162306a36Sopenharmony_ci dlid, rlid, sc, grh); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (becn) { 48462306a36Sopenharmony_ci u32 lqpn = be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK; 48562306a36Sopenharmony_ci u8 sl = ibp->sc_to_sl[sc]; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type); 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci return !ignore_fecn && fecn; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistruct ps_mdata { 49362306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd; 49462306a36Sopenharmony_ci u32 rsize; 49562306a36Sopenharmony_ci u32 maxcnt; 49662306a36Sopenharmony_ci u32 ps_head; 49762306a36Sopenharmony_ci u32 ps_tail; 49862306a36Sopenharmony_ci u32 ps_seq; 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic inline void init_ps_mdata(struct ps_mdata *mdata, 50262306a36Sopenharmony_ci struct hfi1_packet *packet) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci mdata->rcd = rcd; 50762306a36Sopenharmony_ci mdata->rsize = packet->rsize; 50862306a36Sopenharmony_ci mdata->maxcnt = packet->maxcnt; 50962306a36Sopenharmony_ci mdata->ps_head = packet->rhqoff; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (get_dma_rtail_setting(rcd)) { 51262306a36Sopenharmony_ci mdata->ps_tail = get_rcvhdrtail(rcd); 51362306a36Sopenharmony_ci if (rcd->ctxt == HFI1_CTRL_CTXT) 51462306a36Sopenharmony_ci mdata->ps_seq = hfi1_seq_cnt(rcd); 51562306a36Sopenharmony_ci else 51662306a36Sopenharmony_ci mdata->ps_seq = 0; /* not used with DMA_RTAIL */ 51762306a36Sopenharmony_ci } else { 51862306a36Sopenharmony_ci mdata->ps_tail = 0; /* used only with DMA_RTAIL*/ 51962306a36Sopenharmony_ci mdata->ps_seq = hfi1_seq_cnt(rcd); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic inline int ps_done(struct ps_mdata *mdata, u64 rhf, 52462306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci if (get_dma_rtail_setting(rcd)) 52762306a36Sopenharmony_ci return mdata->ps_head == mdata->ps_tail; 52862306a36Sopenharmony_ci return mdata->ps_seq != rhf_rcv_seq(rhf); 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic inline int ps_skip(struct ps_mdata *mdata, u64 rhf, 53262306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci /* 53562306a36Sopenharmony_ci * Control context can potentially receive an invalid rhf. 53662306a36Sopenharmony_ci * Drop such packets. 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ci if ((rcd->ctxt == HFI1_CTRL_CTXT) && (mdata->ps_head != mdata->ps_tail)) 53962306a36Sopenharmony_ci return mdata->ps_seq != rhf_rcv_seq(rhf); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return 0; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic inline void update_ps_mdata(struct ps_mdata *mdata, 54562306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci mdata->ps_head += mdata->rsize; 54862306a36Sopenharmony_ci if (mdata->ps_head >= mdata->maxcnt) 54962306a36Sopenharmony_ci mdata->ps_head = 0; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* Control context must do seq counting */ 55262306a36Sopenharmony_ci if (!get_dma_rtail_setting(rcd) || 55362306a36Sopenharmony_ci rcd->ctxt == HFI1_CTRL_CTXT) 55462306a36Sopenharmony_ci mdata->ps_seq = hfi1_seq_incr_wrap(mdata->ps_seq); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci/* 55862306a36Sopenharmony_ci * prescan_rxq - search through the receive queue looking for packets 55962306a36Sopenharmony_ci * containing Excplicit Congestion Notifications (FECNs, or BECNs). 56062306a36Sopenharmony_ci * When an ECN is found, process the Congestion Notification, and toggle 56162306a36Sopenharmony_ci * it off. 56262306a36Sopenharmony_ci * This is declared as a macro to allow quick checking of the port to avoid 56362306a36Sopenharmony_ci * the overhead of a function call if not enabled. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci#define prescan_rxq(rcd, packet) \ 56662306a36Sopenharmony_ci do { \ 56762306a36Sopenharmony_ci if (rcd->ppd->cc_prescan) \ 56862306a36Sopenharmony_ci __prescan_rxq(packet); \ 56962306a36Sopenharmony_ci } while (0) 57062306a36Sopenharmony_cistatic void __prescan_rxq(struct hfi1_packet *packet) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 57362306a36Sopenharmony_ci struct ps_mdata mdata; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci init_ps_mdata(&mdata, packet); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci while (1) { 57862306a36Sopenharmony_ci struct hfi1_ibport *ibp = rcd_to_iport(rcd); 57962306a36Sopenharmony_ci __le32 *rhf_addr = (__le32 *)rcd->rcvhdrq + mdata.ps_head + 58062306a36Sopenharmony_ci packet->rcd->rhf_offset; 58162306a36Sopenharmony_ci struct rvt_qp *qp; 58262306a36Sopenharmony_ci struct ib_header *hdr; 58362306a36Sopenharmony_ci struct rvt_dev_info *rdi = &rcd->dd->verbs_dev.rdi; 58462306a36Sopenharmony_ci u64 rhf = rhf_to_cpu(rhf_addr); 58562306a36Sopenharmony_ci u32 etype = rhf_rcv_type(rhf), qpn, bth1; 58662306a36Sopenharmony_ci u8 lnh; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (ps_done(&mdata, rhf, rcd)) 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (ps_skip(&mdata, rhf, rcd)) 59262306a36Sopenharmony_ci goto next; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (etype != RHF_RCV_TYPE_IB) 59562306a36Sopenharmony_ci goto next; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci packet->hdr = hfi1_get_msgheader(packet->rcd, rhf_addr); 59862306a36Sopenharmony_ci hdr = packet->hdr; 59962306a36Sopenharmony_ci lnh = ib_get_lnh(hdr); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (lnh == HFI1_LRH_BTH) { 60262306a36Sopenharmony_ci packet->ohdr = &hdr->u.oth; 60362306a36Sopenharmony_ci packet->grh = NULL; 60462306a36Sopenharmony_ci } else if (lnh == HFI1_LRH_GRH) { 60562306a36Sopenharmony_ci packet->ohdr = &hdr->u.l.oth; 60662306a36Sopenharmony_ci packet->grh = &hdr->u.l.grh; 60762306a36Sopenharmony_ci } else { 60862306a36Sopenharmony_ci goto next; /* just in case */ 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (!hfi1_may_ecn(packet)) 61262306a36Sopenharmony_ci goto next; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci bth1 = be32_to_cpu(packet->ohdr->bth[1]); 61562306a36Sopenharmony_ci qpn = bth1 & RVT_QPN_MASK; 61662306a36Sopenharmony_ci rcu_read_lock(); 61762306a36Sopenharmony_ci qp = rvt_lookup_qpn(rdi, &ibp->rvp, qpn); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (!qp) { 62062306a36Sopenharmony_ci rcu_read_unlock(); 62162306a36Sopenharmony_ci goto next; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci hfi1_process_ecn_slowpath(qp, packet, true); 62562306a36Sopenharmony_ci rcu_read_unlock(); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* turn off BECN, FECN */ 62862306a36Sopenharmony_ci bth1 &= ~(IB_FECN_SMASK | IB_BECN_SMASK); 62962306a36Sopenharmony_ci packet->ohdr->bth[1] = cpu_to_be32(bth1); 63062306a36Sopenharmony_cinext: 63162306a36Sopenharmony_ci update_ps_mdata(&mdata, rcd); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void process_rcv_qp_work(struct hfi1_packet *packet) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct rvt_qp *qp, *nqp; 63862306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* 64162306a36Sopenharmony_ci * Iterate over all QPs waiting to respond. 64262306a36Sopenharmony_ci * The list won't change since the IRQ is only run on one CPU. 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_ci list_for_each_entry_safe(qp, nqp, &rcd->qp_wait_list, rspwait) { 64562306a36Sopenharmony_ci list_del_init(&qp->rspwait); 64662306a36Sopenharmony_ci if (qp->r_flags & RVT_R_RSP_NAK) { 64762306a36Sopenharmony_ci qp->r_flags &= ~RVT_R_RSP_NAK; 64862306a36Sopenharmony_ci packet->qp = qp; 64962306a36Sopenharmony_ci hfi1_send_rc_ack(packet, 0); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci if (qp->r_flags & RVT_R_RSP_SEND) { 65262306a36Sopenharmony_ci unsigned long flags; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci qp->r_flags &= ~RVT_R_RSP_SEND; 65562306a36Sopenharmony_ci spin_lock_irqsave(&qp->s_lock, flags); 65662306a36Sopenharmony_ci if (ib_rvt_state_ops[qp->state] & 65762306a36Sopenharmony_ci RVT_PROCESS_OR_FLUSH_SEND) 65862306a36Sopenharmony_ci hfi1_schedule_send(qp); 65962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->s_lock, flags); 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci rvt_put_qp(qp); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic noinline int max_packet_exceeded(struct hfi1_packet *packet, int thread) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci if (thread) { 66862306a36Sopenharmony_ci if ((packet->numpkt & (MAX_PKT_RECV_THREAD - 1)) == 0) 66962306a36Sopenharmony_ci /* allow defered processing */ 67062306a36Sopenharmony_ci process_rcv_qp_work(packet); 67162306a36Sopenharmony_ci cond_resched(); 67262306a36Sopenharmony_ci return RCV_PKT_OK; 67362306a36Sopenharmony_ci } else { 67462306a36Sopenharmony_ci this_cpu_inc(*packet->rcd->dd->rcv_limit); 67562306a36Sopenharmony_ci return RCV_PKT_LIMIT; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic inline int check_max_packet(struct hfi1_packet *packet, int thread) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci int ret = RCV_PKT_OK; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (unlikely((packet->numpkt & (MAX_PKT_RECV - 1)) == 0)) 68462306a36Sopenharmony_ci ret = max_packet_exceeded(packet, thread); 68562306a36Sopenharmony_ci return ret; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic noinline int skip_rcv_packet(struct hfi1_packet *packet, int thread) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci int ret; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci packet->rcd->dd->ctx0_seq_drop++; 69362306a36Sopenharmony_ci /* Set up for the next packet */ 69462306a36Sopenharmony_ci packet->rhqoff += packet->rsize; 69562306a36Sopenharmony_ci if (packet->rhqoff >= packet->maxcnt) 69662306a36Sopenharmony_ci packet->rhqoff = 0; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci packet->numpkt++; 69962306a36Sopenharmony_ci ret = check_max_packet(packet, thread); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci packet->rhf_addr = (__le32 *)packet->rcd->rcvhdrq + packet->rhqoff + 70262306a36Sopenharmony_ci packet->rcd->rhf_offset; 70362306a36Sopenharmony_ci packet->rhf = rhf_to_cpu(packet->rhf_addr); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci return ret; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic void process_rcv_packet_napi(struct hfi1_packet *packet) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci packet->etype = rhf_rcv_type(packet->rhf); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* total length */ 71362306a36Sopenharmony_ci packet->tlen = rhf_pkt_len(packet->rhf); /* in bytes */ 71462306a36Sopenharmony_ci /* retrieve eager buffer details */ 71562306a36Sopenharmony_ci packet->etail = rhf_egr_index(packet->rhf); 71662306a36Sopenharmony_ci packet->ebuf = get_egrbuf(packet->rcd, packet->rhf, 71762306a36Sopenharmony_ci &packet->updegr); 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * Prefetch the contents of the eager buffer. It is 72062306a36Sopenharmony_ci * OK to send a negative length to prefetch_range(). 72162306a36Sopenharmony_ci * The +2 is the size of the RHF. 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_ci prefetch_range(packet->ebuf, 72462306a36Sopenharmony_ci packet->tlen - ((packet->rcd->rcvhdrqentsize - 72562306a36Sopenharmony_ci (rhf_hdrq_offset(packet->rhf) 72662306a36Sopenharmony_ci + 2)) * 4)); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci packet->rcd->rhf_rcv_function_map[packet->etype](packet); 72962306a36Sopenharmony_ci packet->numpkt++; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* Set up for the next packet */ 73262306a36Sopenharmony_ci packet->rhqoff += packet->rsize; 73362306a36Sopenharmony_ci if (packet->rhqoff >= packet->maxcnt) 73462306a36Sopenharmony_ci packet->rhqoff = 0; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci packet->rhf_addr = (__le32 *)packet->rcd->rcvhdrq + packet->rhqoff + 73762306a36Sopenharmony_ci packet->rcd->rhf_offset; 73862306a36Sopenharmony_ci packet->rhf = rhf_to_cpu(packet->rhf_addr); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic inline int process_rcv_packet(struct hfi1_packet *packet, int thread) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci int ret; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci packet->etype = rhf_rcv_type(packet->rhf); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci /* total length */ 74862306a36Sopenharmony_ci packet->tlen = rhf_pkt_len(packet->rhf); /* in bytes */ 74962306a36Sopenharmony_ci /* retrieve eager buffer details */ 75062306a36Sopenharmony_ci packet->ebuf = NULL; 75162306a36Sopenharmony_ci if (rhf_use_egr_bfr(packet->rhf)) { 75262306a36Sopenharmony_ci packet->etail = rhf_egr_index(packet->rhf); 75362306a36Sopenharmony_ci packet->ebuf = get_egrbuf(packet->rcd, packet->rhf, 75462306a36Sopenharmony_ci &packet->updegr); 75562306a36Sopenharmony_ci /* 75662306a36Sopenharmony_ci * Prefetch the contents of the eager buffer. It is 75762306a36Sopenharmony_ci * OK to send a negative length to prefetch_range(). 75862306a36Sopenharmony_ci * The +2 is the size of the RHF. 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci prefetch_range(packet->ebuf, 76162306a36Sopenharmony_ci packet->tlen - ((get_hdrqentsize(packet->rcd) - 76262306a36Sopenharmony_ci (rhf_hdrq_offset(packet->rhf) 76362306a36Sopenharmony_ci + 2)) * 4)); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* 76762306a36Sopenharmony_ci * Call a type specific handler for the packet. We 76862306a36Sopenharmony_ci * should be able to trust that etype won't be beyond 76962306a36Sopenharmony_ci * the range of valid indexes. If so something is really 77062306a36Sopenharmony_ci * wrong and we can probably just let things come 77162306a36Sopenharmony_ci * crashing down. There is no need to eat another 77262306a36Sopenharmony_ci * comparison in this performance critical code. 77362306a36Sopenharmony_ci */ 77462306a36Sopenharmony_ci packet->rcd->rhf_rcv_function_map[packet->etype](packet); 77562306a36Sopenharmony_ci packet->numpkt++; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* Set up for the next packet */ 77862306a36Sopenharmony_ci packet->rhqoff += packet->rsize; 77962306a36Sopenharmony_ci if (packet->rhqoff >= packet->maxcnt) 78062306a36Sopenharmony_ci packet->rhqoff = 0; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci ret = check_max_packet(packet, thread); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci packet->rhf_addr = (__le32 *)packet->rcd->rcvhdrq + packet->rhqoff + 78562306a36Sopenharmony_ci packet->rcd->rhf_offset; 78662306a36Sopenharmony_ci packet->rhf = rhf_to_cpu(packet->rhf_addr); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci return ret; 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic inline void process_rcv_update(int last, struct hfi1_packet *packet) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci /* 79462306a36Sopenharmony_ci * Update head regs etc., every 16 packets, if not last pkt, 79562306a36Sopenharmony_ci * to help prevent rcvhdrq overflows, when many packets 79662306a36Sopenharmony_ci * are processed and queue is nearly full. 79762306a36Sopenharmony_ci * Don't request an interrupt for intermediate updates. 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_ci if (!last && !(packet->numpkt & 0xf)) { 80062306a36Sopenharmony_ci update_usrhead(packet->rcd, packet->rhqoff, packet->updegr, 80162306a36Sopenharmony_ci packet->etail, 0, 0); 80262306a36Sopenharmony_ci packet->updegr = 0; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci packet->grh = NULL; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic inline void finish_packet(struct hfi1_packet *packet) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci /* 81062306a36Sopenharmony_ci * Nothing we need to free for the packet. 81162306a36Sopenharmony_ci * 81262306a36Sopenharmony_ci * The only thing we need to do is a final update and call for an 81362306a36Sopenharmony_ci * interrupt 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_ci update_usrhead(packet->rcd, hfi1_rcd_head(packet->rcd), packet->updegr, 81662306a36Sopenharmony_ci packet->etail, rcv_intr_dynamic, packet->numpkt); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci/* 82062306a36Sopenharmony_ci * handle_receive_interrupt_napi_fp - receive a packet 82162306a36Sopenharmony_ci * @rcd: the context 82262306a36Sopenharmony_ci * @budget: polling budget 82362306a36Sopenharmony_ci * 82462306a36Sopenharmony_ci * Called from interrupt handler for receive interrupt. 82562306a36Sopenharmony_ci * This is the fast path interrupt handler 82662306a36Sopenharmony_ci * when executing napi soft irq environment. 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_ciint handle_receive_interrupt_napi_fp(struct hfi1_ctxtdata *rcd, int budget) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct hfi1_packet packet; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci init_packet(rcd, &packet); 83362306a36Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) 83462306a36Sopenharmony_ci goto bail; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci while (packet.numpkt < budget) { 83762306a36Sopenharmony_ci process_rcv_packet_napi(&packet); 83862306a36Sopenharmony_ci if (hfi1_seq_incr(rcd, rhf_rcv_seq(packet.rhf))) 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci process_rcv_update(0, &packet); 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 84462306a36Sopenharmony_cibail: 84562306a36Sopenharmony_ci finish_packet(&packet); 84662306a36Sopenharmony_ci return packet.numpkt; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci/* 85062306a36Sopenharmony_ci * Handle receive interrupts when using the no dma rtail option. 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_ciint handle_receive_interrupt_nodma_rtail(struct hfi1_ctxtdata *rcd, int thread) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci int last = RCV_PKT_OK; 85562306a36Sopenharmony_ci struct hfi1_packet packet; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci init_packet(rcd, &packet); 85862306a36Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) { 85962306a36Sopenharmony_ci last = RCV_PKT_DONE; 86062306a36Sopenharmony_ci goto bail; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci prescan_rxq(rcd, &packet); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci while (last == RCV_PKT_OK) { 86662306a36Sopenharmony_ci last = process_rcv_packet(&packet, thread); 86762306a36Sopenharmony_ci if (hfi1_seq_incr(rcd, rhf_rcv_seq(packet.rhf))) 86862306a36Sopenharmony_ci last = RCV_PKT_DONE; 86962306a36Sopenharmony_ci process_rcv_update(last, &packet); 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci process_rcv_qp_work(&packet); 87262306a36Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 87362306a36Sopenharmony_cibail: 87462306a36Sopenharmony_ci finish_packet(&packet); 87562306a36Sopenharmony_ci return last; 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ciint handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *rcd, int thread) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci u32 hdrqtail; 88162306a36Sopenharmony_ci int last = RCV_PKT_OK; 88262306a36Sopenharmony_ci struct hfi1_packet packet; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci init_packet(rcd, &packet); 88562306a36Sopenharmony_ci hdrqtail = get_rcvhdrtail(rcd); 88662306a36Sopenharmony_ci if (packet.rhqoff == hdrqtail) { 88762306a36Sopenharmony_ci last = RCV_PKT_DONE; 88862306a36Sopenharmony_ci goto bail; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci smp_rmb(); /* prevent speculative reads of dma'ed hdrq */ 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci prescan_rxq(rcd, &packet); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci while (last == RCV_PKT_OK) { 89562306a36Sopenharmony_ci last = process_rcv_packet(&packet, thread); 89662306a36Sopenharmony_ci if (packet.rhqoff == hdrqtail) 89762306a36Sopenharmony_ci last = RCV_PKT_DONE; 89862306a36Sopenharmony_ci process_rcv_update(last, &packet); 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci process_rcv_qp_work(&packet); 90162306a36Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 90262306a36Sopenharmony_cibail: 90362306a36Sopenharmony_ci finish_packet(&packet); 90462306a36Sopenharmony_ci return last; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic void set_all_fastpath(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci u16 i; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci /* 91262306a36Sopenharmony_ci * For dynamically allocated kernel contexts (like vnic) switch 91362306a36Sopenharmony_ci * interrupt handler only for that context. Otherwise, switch 91462306a36Sopenharmony_ci * interrupt handler for all statically allocated kernel contexts. 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_ci if (rcd->ctxt >= dd->first_dyn_alloc_ctxt && !rcd->is_vnic) { 91762306a36Sopenharmony_ci hfi1_rcd_get(rcd); 91862306a36Sopenharmony_ci hfi1_set_fast(rcd); 91962306a36Sopenharmony_ci hfi1_rcd_put(rcd); 92062306a36Sopenharmony_ci return; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci for (i = HFI1_CTRL_CTXT + 1; i < dd->num_rcv_contexts; i++) { 92462306a36Sopenharmony_ci rcd = hfi1_rcd_get_by_index(dd, i); 92562306a36Sopenharmony_ci if (rcd && (i < dd->first_dyn_alloc_ctxt || rcd->is_vnic)) 92662306a36Sopenharmony_ci hfi1_set_fast(rcd); 92762306a36Sopenharmony_ci hfi1_rcd_put(rcd); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_civoid set_all_slowpath(struct hfi1_devdata *dd) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd; 93462306a36Sopenharmony_ci u16 i; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* HFI1_CTRL_CTXT must always use the slow path interrupt handler */ 93762306a36Sopenharmony_ci for (i = HFI1_CTRL_CTXT + 1; i < dd->num_rcv_contexts; i++) { 93862306a36Sopenharmony_ci rcd = hfi1_rcd_get_by_index(dd, i); 93962306a36Sopenharmony_ci if (!rcd) 94062306a36Sopenharmony_ci continue; 94162306a36Sopenharmony_ci if (i < dd->first_dyn_alloc_ctxt || rcd->is_vnic) 94262306a36Sopenharmony_ci rcd->do_interrupt = rcd->slow_handler; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci hfi1_rcd_put(rcd); 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic bool __set_armed_to_active(struct hfi1_packet *packet) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci u8 etype = rhf_rcv_type(packet->rhf); 95162306a36Sopenharmony_ci u8 sc = SC15_PACKET; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (etype == RHF_RCV_TYPE_IB) { 95462306a36Sopenharmony_ci struct ib_header *hdr = hfi1_get_msgheader(packet->rcd, 95562306a36Sopenharmony_ci packet->rhf_addr); 95662306a36Sopenharmony_ci sc = hfi1_9B_get_sc5(hdr, packet->rhf); 95762306a36Sopenharmony_ci } else if (etype == RHF_RCV_TYPE_BYPASS) { 95862306a36Sopenharmony_ci struct hfi1_16b_header *hdr = hfi1_get_16B_header( 95962306a36Sopenharmony_ci packet->rcd, 96062306a36Sopenharmony_ci packet->rhf_addr); 96162306a36Sopenharmony_ci sc = hfi1_16B_get_sc(hdr); 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci if (sc != SC15_PACKET) { 96462306a36Sopenharmony_ci int hwstate = driver_lstate(packet->rcd->ppd); 96562306a36Sopenharmony_ci struct work_struct *lsaw = 96662306a36Sopenharmony_ci &packet->rcd->ppd->linkstate_active_work; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (hwstate != IB_PORT_ACTIVE) { 96962306a36Sopenharmony_ci dd_dev_info(packet->rcd->dd, 97062306a36Sopenharmony_ci "Unexpected link state %s\n", 97162306a36Sopenharmony_ci opa_lstate_name(hwstate)); 97262306a36Sopenharmony_ci return false; 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci queue_work(packet->rcd->ppd->link_wq, lsaw); 97662306a36Sopenharmony_ci return true; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci return false; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci/** 98262306a36Sopenharmony_ci * set_armed_to_active - the fast path for armed to active 98362306a36Sopenharmony_ci * @packet: the packet structure 98462306a36Sopenharmony_ci * 98562306a36Sopenharmony_ci * Return true if packet processing needs to bail. 98662306a36Sopenharmony_ci */ 98762306a36Sopenharmony_cistatic bool set_armed_to_active(struct hfi1_packet *packet) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci if (likely(packet->rcd->ppd->host_link_state != HLS_UP_ARMED)) 99062306a36Sopenharmony_ci return false; 99162306a36Sopenharmony_ci return __set_armed_to_active(packet); 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci/* 99562306a36Sopenharmony_ci * handle_receive_interrupt - receive a packet 99662306a36Sopenharmony_ci * @rcd: the context 99762306a36Sopenharmony_ci * 99862306a36Sopenharmony_ci * Called from interrupt handler for errors or receive interrupt. 99962306a36Sopenharmony_ci * This is the slow path interrupt handler. 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ciint handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread) 100262306a36Sopenharmony_ci{ 100362306a36Sopenharmony_ci struct hfi1_devdata *dd = rcd->dd; 100462306a36Sopenharmony_ci u32 hdrqtail; 100562306a36Sopenharmony_ci int needset, last = RCV_PKT_OK; 100662306a36Sopenharmony_ci struct hfi1_packet packet; 100762306a36Sopenharmony_ci int skip_pkt = 0; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (!rcd->rcvhdrq) 101062306a36Sopenharmony_ci return RCV_PKT_OK; 101162306a36Sopenharmony_ci /* Control context will always use the slow path interrupt handler */ 101262306a36Sopenharmony_ci needset = (rcd->ctxt == HFI1_CTRL_CTXT) ? 0 : 1; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci init_packet(rcd, &packet); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (!get_dma_rtail_setting(rcd)) { 101762306a36Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) { 101862306a36Sopenharmony_ci last = RCV_PKT_DONE; 101962306a36Sopenharmony_ci goto bail; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci hdrqtail = 0; 102262306a36Sopenharmony_ci } else { 102362306a36Sopenharmony_ci hdrqtail = get_rcvhdrtail(rcd); 102462306a36Sopenharmony_ci if (packet.rhqoff == hdrqtail) { 102562306a36Sopenharmony_ci last = RCV_PKT_DONE; 102662306a36Sopenharmony_ci goto bail; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci smp_rmb(); /* prevent speculative reads of dma'ed hdrq */ 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci /* 103162306a36Sopenharmony_ci * Control context can potentially receive an invalid 103262306a36Sopenharmony_ci * rhf. Drop such packets. 103362306a36Sopenharmony_ci */ 103462306a36Sopenharmony_ci if (rcd->ctxt == HFI1_CTRL_CTXT) 103562306a36Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) 103662306a36Sopenharmony_ci skip_pkt = 1; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci prescan_rxq(rcd, &packet); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci while (last == RCV_PKT_OK) { 104262306a36Sopenharmony_ci if (hfi1_need_drop(dd)) { 104362306a36Sopenharmony_ci /* On to the next packet */ 104462306a36Sopenharmony_ci packet.rhqoff += packet.rsize; 104562306a36Sopenharmony_ci packet.rhf_addr = (__le32 *)rcd->rcvhdrq + 104662306a36Sopenharmony_ci packet.rhqoff + 104762306a36Sopenharmony_ci rcd->rhf_offset; 104862306a36Sopenharmony_ci packet.rhf = rhf_to_cpu(packet.rhf_addr); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci } else if (skip_pkt) { 105162306a36Sopenharmony_ci last = skip_rcv_packet(&packet, thread); 105262306a36Sopenharmony_ci skip_pkt = 0; 105362306a36Sopenharmony_ci } else { 105462306a36Sopenharmony_ci if (set_armed_to_active(&packet)) 105562306a36Sopenharmony_ci goto bail; 105662306a36Sopenharmony_ci last = process_rcv_packet(&packet, thread); 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (!get_dma_rtail_setting(rcd)) { 106062306a36Sopenharmony_ci if (hfi1_seq_incr(rcd, rhf_rcv_seq(packet.rhf))) 106162306a36Sopenharmony_ci last = RCV_PKT_DONE; 106262306a36Sopenharmony_ci } else { 106362306a36Sopenharmony_ci if (packet.rhqoff == hdrqtail) 106462306a36Sopenharmony_ci last = RCV_PKT_DONE; 106562306a36Sopenharmony_ci /* 106662306a36Sopenharmony_ci * Control context can potentially receive an invalid 106762306a36Sopenharmony_ci * rhf. Drop such packets. 106862306a36Sopenharmony_ci */ 106962306a36Sopenharmony_ci if (rcd->ctxt == HFI1_CTRL_CTXT) { 107062306a36Sopenharmony_ci bool lseq; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci lseq = hfi1_seq_incr(rcd, 107362306a36Sopenharmony_ci rhf_rcv_seq(packet.rhf)); 107462306a36Sopenharmony_ci if (!last && lseq) 107562306a36Sopenharmony_ci skip_pkt = 1; 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci if (needset) { 108062306a36Sopenharmony_ci needset = false; 108162306a36Sopenharmony_ci set_all_fastpath(dd, rcd); 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci process_rcv_update(last, &packet); 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci process_rcv_qp_work(&packet); 108762306a36Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cibail: 109062306a36Sopenharmony_ci /* 109162306a36Sopenharmony_ci * Always write head at end, and setup rcv interrupt, even 109262306a36Sopenharmony_ci * if no packets were processed. 109362306a36Sopenharmony_ci */ 109462306a36Sopenharmony_ci finish_packet(&packet); 109562306a36Sopenharmony_ci return last; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci/* 109962306a36Sopenharmony_ci * handle_receive_interrupt_napi_sp - receive a packet 110062306a36Sopenharmony_ci * @rcd: the context 110162306a36Sopenharmony_ci * @budget: polling budget 110262306a36Sopenharmony_ci * 110362306a36Sopenharmony_ci * Called from interrupt handler for errors or receive interrupt. 110462306a36Sopenharmony_ci * This is the slow path interrupt handler 110562306a36Sopenharmony_ci * when executing napi soft irq environment. 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_ciint handle_receive_interrupt_napi_sp(struct hfi1_ctxtdata *rcd, int budget) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci struct hfi1_devdata *dd = rcd->dd; 111062306a36Sopenharmony_ci int last = RCV_PKT_OK; 111162306a36Sopenharmony_ci bool needset = true; 111262306a36Sopenharmony_ci struct hfi1_packet packet; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci init_packet(rcd, &packet); 111562306a36Sopenharmony_ci if (last_rcv_seq(rcd, rhf_rcv_seq(packet.rhf))) 111662306a36Sopenharmony_ci goto bail; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci while (last != RCV_PKT_DONE && packet.numpkt < budget) { 111962306a36Sopenharmony_ci if (hfi1_need_drop(dd)) { 112062306a36Sopenharmony_ci /* On to the next packet */ 112162306a36Sopenharmony_ci packet.rhqoff += packet.rsize; 112262306a36Sopenharmony_ci packet.rhf_addr = (__le32 *)rcd->rcvhdrq + 112362306a36Sopenharmony_ci packet.rhqoff + 112462306a36Sopenharmony_ci rcd->rhf_offset; 112562306a36Sopenharmony_ci packet.rhf = rhf_to_cpu(packet.rhf_addr); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci } else { 112862306a36Sopenharmony_ci if (set_armed_to_active(&packet)) 112962306a36Sopenharmony_ci goto bail; 113062306a36Sopenharmony_ci process_rcv_packet_napi(&packet); 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci if (hfi1_seq_incr(rcd, rhf_rcv_seq(packet.rhf))) 113462306a36Sopenharmony_ci last = RCV_PKT_DONE; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if (needset) { 113762306a36Sopenharmony_ci needset = false; 113862306a36Sopenharmony_ci set_all_fastpath(dd, rcd); 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci process_rcv_update(last, &packet); 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci hfi1_set_rcd_head(rcd, packet.rhqoff); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cibail: 114762306a36Sopenharmony_ci /* 114862306a36Sopenharmony_ci * Always write head at end, and setup rcv interrupt, even 114962306a36Sopenharmony_ci * if no packets were processed. 115062306a36Sopenharmony_ci */ 115162306a36Sopenharmony_ci finish_packet(&packet); 115262306a36Sopenharmony_ci return packet.numpkt; 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci/* 115662306a36Sopenharmony_ci * We may discover in the interrupt that the hardware link state has 115762306a36Sopenharmony_ci * changed from ARMED to ACTIVE (due to the arrival of a non-SC15 packet), 115862306a36Sopenharmony_ci * and we need to update the driver's notion of the link state. We cannot 115962306a36Sopenharmony_ci * run set_link_state from interrupt context, so we queue this function on 116062306a36Sopenharmony_ci * a workqueue. 116162306a36Sopenharmony_ci * 116262306a36Sopenharmony_ci * We delay the regular interrupt processing until after the state changes 116362306a36Sopenharmony_ci * so that the link will be in the correct state by the time any application 116462306a36Sopenharmony_ci * we wake up attempts to send a reply to any message it received. 116562306a36Sopenharmony_ci * (Subsequent receive interrupts may possibly force the wakeup before we 116662306a36Sopenharmony_ci * update the link state.) 116762306a36Sopenharmony_ci * 116862306a36Sopenharmony_ci * The rcd is freed in hfi1_free_ctxtdata after hfi1_postinit_cleanup invokes 116962306a36Sopenharmony_ci * dd->f_cleanup(dd) to disable the interrupt handler and flush workqueues, 117062306a36Sopenharmony_ci * so we're safe from use-after-free of the rcd. 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_civoid receive_interrupt_work(struct work_struct *work) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, 117562306a36Sopenharmony_ci linkstate_active_work); 117662306a36Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 117762306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd; 117862306a36Sopenharmony_ci u16 i; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* Received non-SC15 packet implies neighbor_normal */ 118162306a36Sopenharmony_ci ppd->neighbor_normal = 1; 118262306a36Sopenharmony_ci set_link_state(ppd, HLS_UP_ACTIVE); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci /* 118562306a36Sopenharmony_ci * Interrupt all statically allocated kernel contexts that could 118662306a36Sopenharmony_ci * have had an interrupt during auto activation. 118762306a36Sopenharmony_ci */ 118862306a36Sopenharmony_ci for (i = HFI1_CTRL_CTXT; i < dd->first_dyn_alloc_ctxt; i++) { 118962306a36Sopenharmony_ci rcd = hfi1_rcd_get_by_index(dd, i); 119062306a36Sopenharmony_ci if (rcd) 119162306a36Sopenharmony_ci force_recv_intr(rcd); 119262306a36Sopenharmony_ci hfi1_rcd_put(rcd); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci/* 119762306a36Sopenharmony_ci * Convert a given MTU size to the on-wire MAD packet enumeration. 119862306a36Sopenharmony_ci * Return -1 if the size is invalid. 119962306a36Sopenharmony_ci */ 120062306a36Sopenharmony_ciint mtu_to_enum(u32 mtu, int default_if_bad) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci switch (mtu) { 120362306a36Sopenharmony_ci case 0: return OPA_MTU_0; 120462306a36Sopenharmony_ci case 256: return OPA_MTU_256; 120562306a36Sopenharmony_ci case 512: return OPA_MTU_512; 120662306a36Sopenharmony_ci case 1024: return OPA_MTU_1024; 120762306a36Sopenharmony_ci case 2048: return OPA_MTU_2048; 120862306a36Sopenharmony_ci case 4096: return OPA_MTU_4096; 120962306a36Sopenharmony_ci case 8192: return OPA_MTU_8192; 121062306a36Sopenharmony_ci case 10240: return OPA_MTU_10240; 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci return default_if_bad; 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ciu16 enum_to_mtu(int mtu) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci switch (mtu) { 121862306a36Sopenharmony_ci case OPA_MTU_0: return 0; 121962306a36Sopenharmony_ci case OPA_MTU_256: return 256; 122062306a36Sopenharmony_ci case OPA_MTU_512: return 512; 122162306a36Sopenharmony_ci case OPA_MTU_1024: return 1024; 122262306a36Sopenharmony_ci case OPA_MTU_2048: return 2048; 122362306a36Sopenharmony_ci case OPA_MTU_4096: return 4096; 122462306a36Sopenharmony_ci case OPA_MTU_8192: return 8192; 122562306a36Sopenharmony_ci case OPA_MTU_10240: return 10240; 122662306a36Sopenharmony_ci default: return 0xffff; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci/* 123162306a36Sopenharmony_ci * set_mtu - set the MTU 123262306a36Sopenharmony_ci * @ppd: the per port data 123362306a36Sopenharmony_ci * 123462306a36Sopenharmony_ci * We can handle "any" incoming size, the issue here is whether we 123562306a36Sopenharmony_ci * need to restrict our outgoing size. We do not deal with what happens 123662306a36Sopenharmony_ci * to programs that are already running when the size changes. 123762306a36Sopenharmony_ci */ 123862306a36Sopenharmony_ciint set_mtu(struct hfi1_pportdata *ppd) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 124162306a36Sopenharmony_ci int i, drain, ret = 0, is_up = 0; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci ppd->ibmtu = 0; 124462306a36Sopenharmony_ci for (i = 0; i < ppd->vls_supported; i++) 124562306a36Sopenharmony_ci if (ppd->ibmtu < dd->vld[i].mtu) 124662306a36Sopenharmony_ci ppd->ibmtu = dd->vld[i].mtu; 124762306a36Sopenharmony_ci ppd->ibmaxlen = ppd->ibmtu + lrh_max_header_bytes(ppd->dd); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci mutex_lock(&ppd->hls_lock); 125062306a36Sopenharmony_ci if (ppd->host_link_state == HLS_UP_INIT || 125162306a36Sopenharmony_ci ppd->host_link_state == HLS_UP_ARMED || 125262306a36Sopenharmony_ci ppd->host_link_state == HLS_UP_ACTIVE) 125362306a36Sopenharmony_ci is_up = 1; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci drain = !is_ax(dd) && is_up; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (drain) 125862306a36Sopenharmony_ci /* 125962306a36Sopenharmony_ci * MTU is specified per-VL. To ensure that no packet gets 126062306a36Sopenharmony_ci * stuck (due, e.g., to the MTU for the packet's VL being 126162306a36Sopenharmony_ci * reduced), empty the per-VL FIFOs before adjusting MTU. 126262306a36Sopenharmony_ci */ 126362306a36Sopenharmony_ci ret = stop_drain_data_vls(dd); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci if (ret) { 126662306a36Sopenharmony_ci dd_dev_err(dd, "%s: cannot stop/drain VLs - refusing to change per-VL MTUs\n", 126762306a36Sopenharmony_ci __func__); 126862306a36Sopenharmony_ci goto err; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_MTU, 0); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (drain) 127462306a36Sopenharmony_ci open_fill_data_vls(dd); /* reopen all VLs */ 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_cierr: 127762306a36Sopenharmony_ci mutex_unlock(&ppd->hls_lock); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci return ret; 128062306a36Sopenharmony_ci} 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ciint hfi1_set_lid(struct hfi1_pportdata *ppd, u32 lid, u8 lmc) 128362306a36Sopenharmony_ci{ 128462306a36Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci ppd->lid = lid; 128762306a36Sopenharmony_ci ppd->lmc = lmc; 128862306a36Sopenharmony_ci hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_LIDLMC, 0); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci dd_dev_info(dd, "port %u: got a lid: 0x%x\n", ppd->port, lid); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci return 0; 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_civoid shutdown_led_override(struct hfi1_pportdata *ppd) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci /* 130062306a36Sopenharmony_ci * This pairs with the memory barrier in hfi1_start_led_override to 130162306a36Sopenharmony_ci * ensure that we read the correct state of LED beaconing represented 130262306a36Sopenharmony_ci * by led_override_timer_active 130362306a36Sopenharmony_ci */ 130462306a36Sopenharmony_ci smp_rmb(); 130562306a36Sopenharmony_ci if (atomic_read(&ppd->led_override_timer_active)) { 130662306a36Sopenharmony_ci del_timer_sync(&ppd->led_override_timer); 130762306a36Sopenharmony_ci atomic_set(&ppd->led_override_timer_active, 0); 130862306a36Sopenharmony_ci /* Ensure the atomic_set is visible to all CPUs */ 130962306a36Sopenharmony_ci smp_wmb(); 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* Hand control of the LED to the DC for normal operation */ 131362306a36Sopenharmony_ci write_csr(dd, DCC_CFG_LED_CNTRL, 0); 131462306a36Sopenharmony_ci} 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cistatic void run_led_override(struct timer_list *t) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci struct hfi1_pportdata *ppd = from_timer(ppd, t, led_override_timer); 131962306a36Sopenharmony_ci struct hfi1_devdata *dd = ppd->dd; 132062306a36Sopenharmony_ci unsigned long timeout; 132162306a36Sopenharmony_ci int phase_idx; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (!(dd->flags & HFI1_INITTED)) 132462306a36Sopenharmony_ci return; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci phase_idx = ppd->led_override_phase & 1; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci setextled(dd, phase_idx); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci timeout = ppd->led_override_vals[phase_idx]; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* Set up for next phase */ 133362306a36Sopenharmony_ci ppd->led_override_phase = !ppd->led_override_phase; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci mod_timer(&ppd->led_override_timer, jiffies + timeout); 133662306a36Sopenharmony_ci} 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci/* 133962306a36Sopenharmony_ci * To have the LED blink in a particular pattern, provide timeon and timeoff 134062306a36Sopenharmony_ci * in milliseconds. 134162306a36Sopenharmony_ci * To turn off custom blinking and return to normal operation, use 134262306a36Sopenharmony_ci * shutdown_led_override() 134362306a36Sopenharmony_ci */ 134462306a36Sopenharmony_civoid hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon, 134562306a36Sopenharmony_ci unsigned int timeoff) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci if (!(ppd->dd->flags & HFI1_INITTED)) 134862306a36Sopenharmony_ci return; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci /* Convert to jiffies for direct use in timer */ 135162306a36Sopenharmony_ci ppd->led_override_vals[0] = msecs_to_jiffies(timeoff); 135262306a36Sopenharmony_ci ppd->led_override_vals[1] = msecs_to_jiffies(timeon); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci /* Arbitrarily start from LED on phase */ 135562306a36Sopenharmony_ci ppd->led_override_phase = 1; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* 135862306a36Sopenharmony_ci * If the timer has not already been started, do so. Use a "quick" 135962306a36Sopenharmony_ci * timeout so the handler will be called soon to look at our request. 136062306a36Sopenharmony_ci */ 136162306a36Sopenharmony_ci if (!timer_pending(&ppd->led_override_timer)) { 136262306a36Sopenharmony_ci timer_setup(&ppd->led_override_timer, run_led_override, 0); 136362306a36Sopenharmony_ci ppd->led_override_timer.expires = jiffies + 1; 136462306a36Sopenharmony_ci add_timer(&ppd->led_override_timer); 136562306a36Sopenharmony_ci atomic_set(&ppd->led_override_timer_active, 1); 136662306a36Sopenharmony_ci /* Ensure the atomic_set is visible to all CPUs */ 136762306a36Sopenharmony_ci smp_wmb(); 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci/** 137262306a36Sopenharmony_ci * hfi1_reset_device - reset the chip if possible 137362306a36Sopenharmony_ci * @unit: the device to reset 137462306a36Sopenharmony_ci * 137562306a36Sopenharmony_ci * Whether or not reset is successful, we attempt to re-initialize the chip 137662306a36Sopenharmony_ci * (that is, much like a driver unload/reload). We clear the INITTED flag 137762306a36Sopenharmony_ci * so that the various entry points will fail until we reinitialize. For 137862306a36Sopenharmony_ci * now, we only allow this if no user contexts are open that use chip resources 137962306a36Sopenharmony_ci */ 138062306a36Sopenharmony_ciint hfi1_reset_device(int unit) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci int ret; 138362306a36Sopenharmony_ci struct hfi1_devdata *dd = hfi1_lookup(unit); 138462306a36Sopenharmony_ci struct hfi1_pportdata *ppd; 138562306a36Sopenharmony_ci int pidx; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci if (!dd) { 138862306a36Sopenharmony_ci ret = -ENODEV; 138962306a36Sopenharmony_ci goto bail; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci dd_dev_info(dd, "Reset on unit %u requested\n", unit); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci if (!dd->kregbase1 || !(dd->flags & HFI1_PRESENT)) { 139562306a36Sopenharmony_ci dd_dev_info(dd, 139662306a36Sopenharmony_ci "Invalid unit number %u or not initialized or not present\n", 139762306a36Sopenharmony_ci unit); 139862306a36Sopenharmony_ci ret = -ENXIO; 139962306a36Sopenharmony_ci goto bail; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci /* If there are any user/vnic contexts, we cannot reset */ 140362306a36Sopenharmony_ci mutex_lock(&hfi1_mutex); 140462306a36Sopenharmony_ci if (dd->rcd) 140562306a36Sopenharmony_ci if (hfi1_stats.sps_ctxts) { 140662306a36Sopenharmony_ci mutex_unlock(&hfi1_mutex); 140762306a36Sopenharmony_ci ret = -EBUSY; 140862306a36Sopenharmony_ci goto bail; 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci mutex_unlock(&hfi1_mutex); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci for (pidx = 0; pidx < dd->num_pports; ++pidx) { 141362306a36Sopenharmony_ci ppd = dd->pport + pidx; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci shutdown_led_override(ppd); 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci if (dd->flags & HFI1_HAS_SEND_DMA) 141862306a36Sopenharmony_ci sdma_exit(dd); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci hfi1_reset_cpu_counters(dd); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci ret = hfi1_init(dd, 1); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci if (ret) 142562306a36Sopenharmony_ci dd_dev_err(dd, 142662306a36Sopenharmony_ci "Reinitialize unit %u after reset failed with %d\n", 142762306a36Sopenharmony_ci unit, ret); 142862306a36Sopenharmony_ci else 142962306a36Sopenharmony_ci dd_dev_info(dd, "Reinitialized unit %u after resetting\n", 143062306a36Sopenharmony_ci unit); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_cibail: 143362306a36Sopenharmony_ci return ret; 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_cistatic inline void hfi1_setup_ib_header(struct hfi1_packet *packet) 143762306a36Sopenharmony_ci{ 143862306a36Sopenharmony_ci packet->hdr = (struct hfi1_ib_message_header *) 143962306a36Sopenharmony_ci hfi1_get_msgheader(packet->rcd, 144062306a36Sopenharmony_ci packet->rhf_addr); 144162306a36Sopenharmony_ci packet->hlen = (u8 *)packet->rhf_addr - (u8 *)packet->hdr; 144262306a36Sopenharmony_ci} 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cistatic int hfi1_bypass_ingress_pkt_check(struct hfi1_packet *packet) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci struct hfi1_pportdata *ppd = packet->rcd->ppd; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci /* slid and dlid cannot be 0 */ 144962306a36Sopenharmony_ci if ((!packet->slid) || (!packet->dlid)) 145062306a36Sopenharmony_ci return -EINVAL; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci /* Compare port lid with incoming packet dlid */ 145362306a36Sopenharmony_ci if ((!(hfi1_is_16B_mcast(packet->dlid))) && 145462306a36Sopenharmony_ci (packet->dlid != 145562306a36Sopenharmony_ci opa_get_lid(be32_to_cpu(OPA_LID_PERMISSIVE), 16B))) { 145662306a36Sopenharmony_ci if ((packet->dlid & ~((1 << ppd->lmc) - 1)) != ppd->lid) 145762306a36Sopenharmony_ci return -EINVAL; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci /* No multicast packets with SC15 */ 146162306a36Sopenharmony_ci if ((hfi1_is_16B_mcast(packet->dlid)) && (packet->sc == 0xF)) 146262306a36Sopenharmony_ci return -EINVAL; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci /* Packets with permissive DLID always on SC15 */ 146562306a36Sopenharmony_ci if ((packet->dlid == opa_get_lid(be32_to_cpu(OPA_LID_PERMISSIVE), 146662306a36Sopenharmony_ci 16B)) && 146762306a36Sopenharmony_ci (packet->sc != 0xF)) 146862306a36Sopenharmony_ci return -EINVAL; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci return 0; 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_cistatic int hfi1_setup_9B_packet(struct hfi1_packet *packet) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci struct hfi1_ibport *ibp = rcd_to_iport(packet->rcd); 147662306a36Sopenharmony_ci struct ib_header *hdr; 147762306a36Sopenharmony_ci u8 lnh; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci hfi1_setup_ib_header(packet); 148062306a36Sopenharmony_ci hdr = packet->hdr; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci lnh = ib_get_lnh(hdr); 148362306a36Sopenharmony_ci if (lnh == HFI1_LRH_BTH) { 148462306a36Sopenharmony_ci packet->ohdr = &hdr->u.oth; 148562306a36Sopenharmony_ci packet->grh = NULL; 148662306a36Sopenharmony_ci } else if (lnh == HFI1_LRH_GRH) { 148762306a36Sopenharmony_ci u32 vtf; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci packet->ohdr = &hdr->u.l.oth; 149062306a36Sopenharmony_ci packet->grh = &hdr->u.l.grh; 149162306a36Sopenharmony_ci if (packet->grh->next_hdr != IB_GRH_NEXT_HDR) 149262306a36Sopenharmony_ci goto drop; 149362306a36Sopenharmony_ci vtf = be32_to_cpu(packet->grh->version_tclass_flow); 149462306a36Sopenharmony_ci if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) 149562306a36Sopenharmony_ci goto drop; 149662306a36Sopenharmony_ci } else { 149762306a36Sopenharmony_ci goto drop; 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci /* Query commonly used fields from packet header */ 150162306a36Sopenharmony_ci packet->payload = packet->ebuf; 150262306a36Sopenharmony_ci packet->opcode = ib_bth_get_opcode(packet->ohdr); 150362306a36Sopenharmony_ci packet->slid = ib_get_slid(hdr); 150462306a36Sopenharmony_ci packet->dlid = ib_get_dlid(hdr); 150562306a36Sopenharmony_ci if (unlikely((packet->dlid >= be16_to_cpu(IB_MULTICAST_LID_BASE)) && 150662306a36Sopenharmony_ci (packet->dlid != be16_to_cpu(IB_LID_PERMISSIVE)))) 150762306a36Sopenharmony_ci packet->dlid += opa_get_mcast_base(OPA_MCAST_NR) - 150862306a36Sopenharmony_ci be16_to_cpu(IB_MULTICAST_LID_BASE); 150962306a36Sopenharmony_ci packet->sl = ib_get_sl(hdr); 151062306a36Sopenharmony_ci packet->sc = hfi1_9B_get_sc5(hdr, packet->rhf); 151162306a36Sopenharmony_ci packet->pad = ib_bth_get_pad(packet->ohdr); 151262306a36Sopenharmony_ci packet->extra_byte = 0; 151362306a36Sopenharmony_ci packet->pkey = ib_bth_get_pkey(packet->ohdr); 151462306a36Sopenharmony_ci packet->migrated = ib_bth_is_migration(packet->ohdr); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci return 0; 151762306a36Sopenharmony_cidrop: 151862306a36Sopenharmony_ci ibp->rvp.n_pkt_drops++; 151962306a36Sopenharmony_ci return -EINVAL; 152062306a36Sopenharmony_ci} 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_cistatic int hfi1_setup_bypass_packet(struct hfi1_packet *packet) 152362306a36Sopenharmony_ci{ 152462306a36Sopenharmony_ci /* 152562306a36Sopenharmony_ci * Bypass packets have a different header/payload split 152662306a36Sopenharmony_ci * compared to an IB packet. 152762306a36Sopenharmony_ci * Current split is set such that 16 bytes of the actual 152862306a36Sopenharmony_ci * header is in the header buffer and the remining is in 152962306a36Sopenharmony_ci * the eager buffer. We chose 16 since hfi1 driver only 153062306a36Sopenharmony_ci * supports 16B bypass packets and we will be able to 153162306a36Sopenharmony_ci * receive the entire LRH with such a split. 153262306a36Sopenharmony_ci */ 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 153562306a36Sopenharmony_ci struct hfi1_pportdata *ppd = rcd->ppd; 153662306a36Sopenharmony_ci struct hfi1_ibport *ibp = &ppd->ibport_data; 153762306a36Sopenharmony_ci u8 l4; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci packet->hdr = (struct hfi1_16b_header *) 154062306a36Sopenharmony_ci hfi1_get_16B_header(packet->rcd, 154162306a36Sopenharmony_ci packet->rhf_addr); 154262306a36Sopenharmony_ci l4 = hfi1_16B_get_l4(packet->hdr); 154362306a36Sopenharmony_ci if (l4 == OPA_16B_L4_IB_LOCAL) { 154462306a36Sopenharmony_ci packet->ohdr = packet->ebuf; 154562306a36Sopenharmony_ci packet->grh = NULL; 154662306a36Sopenharmony_ci packet->opcode = ib_bth_get_opcode(packet->ohdr); 154762306a36Sopenharmony_ci packet->pad = hfi1_16B_bth_get_pad(packet->ohdr); 154862306a36Sopenharmony_ci /* hdr_len_by_opcode already has an IB LRH factored in */ 154962306a36Sopenharmony_ci packet->hlen = hdr_len_by_opcode[packet->opcode] + 155062306a36Sopenharmony_ci (LRH_16B_BYTES - LRH_9B_BYTES); 155162306a36Sopenharmony_ci packet->migrated = opa_bth_is_migration(packet->ohdr); 155262306a36Sopenharmony_ci } else if (l4 == OPA_16B_L4_IB_GLOBAL) { 155362306a36Sopenharmony_ci u32 vtf; 155462306a36Sopenharmony_ci u8 grh_len = sizeof(struct ib_grh); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci packet->ohdr = packet->ebuf + grh_len; 155762306a36Sopenharmony_ci packet->grh = packet->ebuf; 155862306a36Sopenharmony_ci packet->opcode = ib_bth_get_opcode(packet->ohdr); 155962306a36Sopenharmony_ci packet->pad = hfi1_16B_bth_get_pad(packet->ohdr); 156062306a36Sopenharmony_ci /* hdr_len_by_opcode already has an IB LRH factored in */ 156162306a36Sopenharmony_ci packet->hlen = hdr_len_by_opcode[packet->opcode] + 156262306a36Sopenharmony_ci (LRH_16B_BYTES - LRH_9B_BYTES) + grh_len; 156362306a36Sopenharmony_ci packet->migrated = opa_bth_is_migration(packet->ohdr); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (packet->grh->next_hdr != IB_GRH_NEXT_HDR) 156662306a36Sopenharmony_ci goto drop; 156762306a36Sopenharmony_ci vtf = be32_to_cpu(packet->grh->version_tclass_flow); 156862306a36Sopenharmony_ci if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) 156962306a36Sopenharmony_ci goto drop; 157062306a36Sopenharmony_ci } else if (l4 == OPA_16B_L4_FM) { 157162306a36Sopenharmony_ci packet->mgmt = packet->ebuf; 157262306a36Sopenharmony_ci packet->ohdr = NULL; 157362306a36Sopenharmony_ci packet->grh = NULL; 157462306a36Sopenharmony_ci packet->opcode = IB_OPCODE_UD_SEND_ONLY; 157562306a36Sopenharmony_ci packet->pad = OPA_16B_L4_FM_PAD; 157662306a36Sopenharmony_ci packet->hlen = OPA_16B_L4_FM_HLEN; 157762306a36Sopenharmony_ci packet->migrated = false; 157862306a36Sopenharmony_ci } else { 157962306a36Sopenharmony_ci goto drop; 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci /* Query commonly used fields from packet header */ 158362306a36Sopenharmony_ci packet->payload = packet->ebuf + packet->hlen - LRH_16B_BYTES; 158462306a36Sopenharmony_ci packet->slid = hfi1_16B_get_slid(packet->hdr); 158562306a36Sopenharmony_ci packet->dlid = hfi1_16B_get_dlid(packet->hdr); 158662306a36Sopenharmony_ci if (unlikely(hfi1_is_16B_mcast(packet->dlid))) 158762306a36Sopenharmony_ci packet->dlid += opa_get_mcast_base(OPA_MCAST_NR) - 158862306a36Sopenharmony_ci opa_get_lid(opa_get_mcast_base(OPA_MCAST_NR), 158962306a36Sopenharmony_ci 16B); 159062306a36Sopenharmony_ci packet->sc = hfi1_16B_get_sc(packet->hdr); 159162306a36Sopenharmony_ci packet->sl = ibp->sc_to_sl[packet->sc]; 159262306a36Sopenharmony_ci packet->extra_byte = SIZE_OF_LT; 159362306a36Sopenharmony_ci packet->pkey = hfi1_16B_get_pkey(packet->hdr); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (hfi1_bypass_ingress_pkt_check(packet)) 159662306a36Sopenharmony_ci goto drop; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci return 0; 159962306a36Sopenharmony_cidrop: 160062306a36Sopenharmony_ci hfi1_cdbg(PKT, "%s: packet dropped", __func__); 160162306a36Sopenharmony_ci ibp->rvp.n_pkt_drops++; 160262306a36Sopenharmony_ci return -EINVAL; 160362306a36Sopenharmony_ci} 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistatic void show_eflags_errs(struct hfi1_packet *packet) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 160862306a36Sopenharmony_ci u32 rte = rhf_rcv_type_err(packet->rhf); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci dd_dev_err(rcd->dd, 161162306a36Sopenharmony_ci "receive context %d: rhf 0x%016llx, errs [ %s%s%s%s%s%s%s] rte 0x%x\n", 161262306a36Sopenharmony_ci rcd->ctxt, packet->rhf, 161362306a36Sopenharmony_ci packet->rhf & RHF_K_HDR_LEN_ERR ? "k_hdr_len " : "", 161462306a36Sopenharmony_ci packet->rhf & RHF_DC_UNC_ERR ? "dc_unc " : "", 161562306a36Sopenharmony_ci packet->rhf & RHF_DC_ERR ? "dc " : "", 161662306a36Sopenharmony_ci packet->rhf & RHF_TID_ERR ? "tid " : "", 161762306a36Sopenharmony_ci packet->rhf & RHF_LEN_ERR ? "len " : "", 161862306a36Sopenharmony_ci packet->rhf & RHF_ECC_ERR ? "ecc " : "", 161962306a36Sopenharmony_ci packet->rhf & RHF_ICRC_ERR ? "icrc " : "", 162062306a36Sopenharmony_ci rte); 162162306a36Sopenharmony_ci} 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_civoid handle_eflags(struct hfi1_packet *packet) 162462306a36Sopenharmony_ci{ 162562306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci rcv_hdrerr(rcd, rcd->ppd, packet); 162862306a36Sopenharmony_ci if (rhf_err_flags(packet->rhf)) 162962306a36Sopenharmony_ci show_eflags_errs(packet); 163062306a36Sopenharmony_ci} 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_cistatic void hfi1_ipoib_ib_rcv(struct hfi1_packet *packet) 163362306a36Sopenharmony_ci{ 163462306a36Sopenharmony_ci struct hfi1_ibport *ibp; 163562306a36Sopenharmony_ci struct net_device *netdev; 163662306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 163762306a36Sopenharmony_ci struct napi_struct *napi = rcd->napi; 163862306a36Sopenharmony_ci struct sk_buff *skb; 163962306a36Sopenharmony_ci struct hfi1_netdev_rxq *rxq = container_of(napi, 164062306a36Sopenharmony_ci struct hfi1_netdev_rxq, napi); 164162306a36Sopenharmony_ci u32 extra_bytes; 164262306a36Sopenharmony_ci u32 tlen, qpnum; 164362306a36Sopenharmony_ci bool do_work, do_cnp; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci trace_hfi1_rcvhdr(packet); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci hfi1_setup_ib_header(packet); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci packet->ohdr = &((struct ib_header *)packet->hdr)->u.oth; 165062306a36Sopenharmony_ci packet->grh = NULL; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 165362306a36Sopenharmony_ci handle_eflags(packet); 165462306a36Sopenharmony_ci return; 165562306a36Sopenharmony_ci } 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci qpnum = ib_bth_get_qpn(packet->ohdr); 165862306a36Sopenharmony_ci netdev = hfi1_netdev_get_data(rcd->dd, qpnum); 165962306a36Sopenharmony_ci if (!netdev) 166062306a36Sopenharmony_ci goto drop_no_nd; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci trace_input_ibhdr(rcd->dd, packet, !!(rhf_dc_info(packet->rhf))); 166362306a36Sopenharmony_ci trace_ctxt_rsm_hist(rcd->ctxt); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci /* handle congestion notifications */ 166662306a36Sopenharmony_ci do_work = hfi1_may_ecn(packet); 166762306a36Sopenharmony_ci if (unlikely(do_work)) { 166862306a36Sopenharmony_ci do_cnp = (packet->opcode != IB_OPCODE_CNP); 166962306a36Sopenharmony_ci (void)hfi1_process_ecn_slowpath(hfi1_ipoib_priv(netdev)->qp, 167062306a36Sopenharmony_ci packet, do_cnp); 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci /* 167462306a36Sopenharmony_ci * We have split point after last byte of DETH 167562306a36Sopenharmony_ci * lets strip padding and CRC and ICRC. 167662306a36Sopenharmony_ci * tlen is whole packet len so we need to 167762306a36Sopenharmony_ci * subtract header size as well. 167862306a36Sopenharmony_ci */ 167962306a36Sopenharmony_ci tlen = packet->tlen; 168062306a36Sopenharmony_ci extra_bytes = ib_bth_get_pad(packet->ohdr) + (SIZE_OF_CRC << 2) + 168162306a36Sopenharmony_ci packet->hlen; 168262306a36Sopenharmony_ci if (unlikely(tlen < extra_bytes)) 168362306a36Sopenharmony_ci goto drop; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci tlen -= extra_bytes; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci skb = hfi1_ipoib_prepare_skb(rxq, tlen, packet->ebuf); 168862306a36Sopenharmony_ci if (unlikely(!skb)) 168962306a36Sopenharmony_ci goto drop; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci dev_sw_netstats_rx_add(netdev, skb->len); 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci skb->dev = netdev; 169462306a36Sopenharmony_ci skb->pkt_type = PACKET_HOST; 169562306a36Sopenharmony_ci netif_receive_skb(skb); 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci return; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_cidrop: 170062306a36Sopenharmony_ci ++netdev->stats.rx_dropped; 170162306a36Sopenharmony_cidrop_no_nd: 170262306a36Sopenharmony_ci ibp = rcd_to_iport(packet->rcd); 170362306a36Sopenharmony_ci ++ibp->rvp.n_pkt_drops; 170462306a36Sopenharmony_ci} 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci/* 170762306a36Sopenharmony_ci * The following functions are called by the interrupt handler. They are type 170862306a36Sopenharmony_ci * specific handlers for each packet type. 170962306a36Sopenharmony_ci */ 171062306a36Sopenharmony_cistatic void process_receive_ib(struct hfi1_packet *packet) 171162306a36Sopenharmony_ci{ 171262306a36Sopenharmony_ci if (hfi1_setup_9B_packet(packet)) 171362306a36Sopenharmony_ci return; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci if (unlikely(hfi1_dbg_should_fault_rx(packet))) 171662306a36Sopenharmony_ci return; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci trace_hfi1_rcvhdr(packet); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 172162306a36Sopenharmony_ci handle_eflags(packet); 172262306a36Sopenharmony_ci return; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci hfi1_ib_rcv(packet); 172662306a36Sopenharmony_ci} 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_cistatic void process_receive_bypass(struct hfi1_packet *packet) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci struct hfi1_devdata *dd = packet->rcd->dd; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci if (hfi1_setup_bypass_packet(packet)) 173362306a36Sopenharmony_ci return; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci trace_hfi1_rcvhdr(packet); 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 173862306a36Sopenharmony_ci handle_eflags(packet); 173962306a36Sopenharmony_ci return; 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci if (hfi1_16B_get_l2(packet->hdr) == 0x2) { 174362306a36Sopenharmony_ci hfi1_16B_rcv(packet); 174462306a36Sopenharmony_ci } else { 174562306a36Sopenharmony_ci dd_dev_err(dd, 174662306a36Sopenharmony_ci "Bypass packets other than 16B are not supported in normal operation. Dropping\n"); 174762306a36Sopenharmony_ci incr_cntr64(&dd->sw_rcv_bypass_packet_errors); 174862306a36Sopenharmony_ci if (!(dd->err_info_rcvport.status_and_code & 174962306a36Sopenharmony_ci OPA_EI_STATUS_SMASK)) { 175062306a36Sopenharmony_ci u64 *flits = packet->ebuf; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (flits && !(packet->rhf & RHF_LEN_ERR)) { 175362306a36Sopenharmony_ci dd->err_info_rcvport.packet_flit1 = flits[0]; 175462306a36Sopenharmony_ci dd->err_info_rcvport.packet_flit2 = 175562306a36Sopenharmony_ci packet->tlen > sizeof(flits[0]) ? 175662306a36Sopenharmony_ci flits[1] : 0; 175762306a36Sopenharmony_ci } 175862306a36Sopenharmony_ci dd->err_info_rcvport.status_and_code |= 175962306a36Sopenharmony_ci (OPA_EI_STATUS_SMASK | BAD_L2_ERR); 176062306a36Sopenharmony_ci } 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_cistatic void process_receive_error(struct hfi1_packet *packet) 176562306a36Sopenharmony_ci{ 176662306a36Sopenharmony_ci /* KHdrHCRCErr -- KDETH packet with a bad HCRC */ 176762306a36Sopenharmony_ci if (unlikely( 176862306a36Sopenharmony_ci hfi1_dbg_fault_suppress_err(&packet->rcd->dd->verbs_dev) && 176962306a36Sopenharmony_ci (rhf_rcv_type_err(packet->rhf) == RHF_RCV_TYPE_ERROR || 177062306a36Sopenharmony_ci packet->rhf & RHF_DC_ERR))) 177162306a36Sopenharmony_ci return; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci hfi1_setup_ib_header(packet); 177462306a36Sopenharmony_ci handle_eflags(packet); 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) 177762306a36Sopenharmony_ci dd_dev_err(packet->rcd->dd, 177862306a36Sopenharmony_ci "Unhandled error packet received. Dropping.\n"); 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic void kdeth_process_expected(struct hfi1_packet *packet) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci hfi1_setup_9B_packet(packet); 178462306a36Sopenharmony_ci if (unlikely(hfi1_dbg_should_fault_rx(packet))) 178562306a36Sopenharmony_ci return; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 178862306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci if (hfi1_handle_kdeth_eflags(rcd, rcd->ppd, packet)) 179162306a36Sopenharmony_ci return; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci hfi1_kdeth_expected_rcv(packet); 179562306a36Sopenharmony_ci} 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cistatic void kdeth_process_eager(struct hfi1_packet *packet) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci hfi1_setup_9B_packet(packet); 180062306a36Sopenharmony_ci if (unlikely(hfi1_dbg_should_fault_rx(packet))) 180162306a36Sopenharmony_ci return; 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci trace_hfi1_rcvhdr(packet); 180462306a36Sopenharmony_ci if (unlikely(rhf_err_flags(packet->rhf))) { 180562306a36Sopenharmony_ci struct hfi1_ctxtdata *rcd = packet->rcd; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci show_eflags_errs(packet); 180862306a36Sopenharmony_ci if (hfi1_handle_kdeth_eflags(rcd, rcd->ppd, packet)) 180962306a36Sopenharmony_ci return; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci hfi1_kdeth_eager_rcv(packet); 181362306a36Sopenharmony_ci} 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_cistatic void process_receive_invalid(struct hfi1_packet *packet) 181662306a36Sopenharmony_ci{ 181762306a36Sopenharmony_ci dd_dev_err(packet->rcd->dd, "Invalid packet type %d. Dropping\n", 181862306a36Sopenharmony_ci rhf_rcv_type(packet->rhf)); 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci#define HFI1_RCVHDR_DUMP_MAX 5 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_civoid seqfile_dump_rcd(struct seq_file *s, struct hfi1_ctxtdata *rcd) 182462306a36Sopenharmony_ci{ 182562306a36Sopenharmony_ci struct hfi1_packet packet; 182662306a36Sopenharmony_ci struct ps_mdata mdata; 182762306a36Sopenharmony_ci int i; 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_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", 183062306a36Sopenharmony_ci rcd->ctxt, get_hdrq_cnt(rcd), get_hdrqentsize(rcd), 183162306a36Sopenharmony_ci get_dma_rtail_setting(rcd) ? 183262306a36Sopenharmony_ci "dma_rtail" : "nodma_rtail", 183362306a36Sopenharmony_ci read_kctxt_csr(rcd->dd, rcd->ctxt, RCV_CTXT_CTRL), 183462306a36Sopenharmony_ci read_kctxt_csr(rcd->dd, rcd->ctxt, RCV_CTXT_STATUS), 183562306a36Sopenharmony_ci read_uctxt_csr(rcd->dd, rcd->ctxt, RCV_HDR_HEAD) & 183662306a36Sopenharmony_ci RCV_HDR_HEAD_HEAD_MASK, 183762306a36Sopenharmony_ci read_uctxt_csr(rcd->dd, rcd->ctxt, RCV_HDR_TAIL), 183862306a36Sopenharmony_ci rcd->head); 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci init_packet(rcd, &packet); 184162306a36Sopenharmony_ci init_ps_mdata(&mdata, &packet); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci for (i = 0; i < HFI1_RCVHDR_DUMP_MAX; i++) { 184462306a36Sopenharmony_ci __le32 *rhf_addr = (__le32 *)rcd->rcvhdrq + mdata.ps_head + 184562306a36Sopenharmony_ci rcd->rhf_offset; 184662306a36Sopenharmony_ci struct ib_header *hdr; 184762306a36Sopenharmony_ci u64 rhf = rhf_to_cpu(rhf_addr); 184862306a36Sopenharmony_ci u32 etype = rhf_rcv_type(rhf), qpn; 184962306a36Sopenharmony_ci u8 opcode; 185062306a36Sopenharmony_ci u32 psn; 185162306a36Sopenharmony_ci u8 lnh; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (ps_done(&mdata, rhf, rcd)) 185462306a36Sopenharmony_ci break; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci if (ps_skip(&mdata, rhf, rcd)) 185762306a36Sopenharmony_ci goto next; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci if (etype > RHF_RCV_TYPE_IB) 186062306a36Sopenharmony_ci goto next; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci packet.hdr = hfi1_get_msgheader(rcd, rhf_addr); 186362306a36Sopenharmony_ci hdr = packet.hdr; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci lnh = be16_to_cpu(hdr->lrh[0]) & 3; 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci if (lnh == HFI1_LRH_BTH) 186862306a36Sopenharmony_ci packet.ohdr = &hdr->u.oth; 186962306a36Sopenharmony_ci else if (lnh == HFI1_LRH_GRH) 187062306a36Sopenharmony_ci packet.ohdr = &hdr->u.l.oth; 187162306a36Sopenharmony_ci else 187262306a36Sopenharmony_ci goto next; /* just in case */ 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci opcode = (be32_to_cpu(packet.ohdr->bth[0]) >> 24); 187562306a36Sopenharmony_ci qpn = be32_to_cpu(packet.ohdr->bth[1]) & RVT_QPN_MASK; 187662306a36Sopenharmony_ci psn = mask_psn(be32_to_cpu(packet.ohdr->bth[2])); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci seq_printf(s, "\tEnt %u: opcode 0x%x, qpn 0x%x, psn 0x%x\n", 187962306a36Sopenharmony_ci mdata.ps_head, opcode, qpn, psn); 188062306a36Sopenharmony_cinext: 188162306a36Sopenharmony_ci update_ps_mdata(&mdata, rcd); 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci} 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ciconst rhf_rcv_function_ptr normal_rhf_rcv_functions[] = { 188662306a36Sopenharmony_ci [RHF_RCV_TYPE_EXPECTED] = kdeth_process_expected, 188762306a36Sopenharmony_ci [RHF_RCV_TYPE_EAGER] = kdeth_process_eager, 188862306a36Sopenharmony_ci [RHF_RCV_TYPE_IB] = process_receive_ib, 188962306a36Sopenharmony_ci [RHF_RCV_TYPE_ERROR] = process_receive_error, 189062306a36Sopenharmony_ci [RHF_RCV_TYPE_BYPASS] = process_receive_bypass, 189162306a36Sopenharmony_ci [RHF_RCV_TYPE_INVALID5] = process_receive_invalid, 189262306a36Sopenharmony_ci [RHF_RCV_TYPE_INVALID6] = process_receive_invalid, 189362306a36Sopenharmony_ci [RHF_RCV_TYPE_INVALID7] = process_receive_invalid, 189462306a36Sopenharmony_ci}; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ciconst rhf_rcv_function_ptr netdev_rhf_rcv_functions[] = { 189762306a36Sopenharmony_ci [RHF_RCV_TYPE_EXPECTED] = process_receive_invalid, 189862306a36Sopenharmony_ci [RHF_RCV_TYPE_EAGER] = process_receive_invalid, 189962306a36Sopenharmony_ci [RHF_RCV_TYPE_IB] = hfi1_ipoib_ib_rcv, 190062306a36Sopenharmony_ci [RHF_RCV_TYPE_ERROR] = process_receive_error, 190162306a36Sopenharmony_ci [RHF_RCV_TYPE_BYPASS] = hfi1_vnic_bypass_rcv, 190262306a36Sopenharmony_ci [RHF_RCV_TYPE_INVALID5] = process_receive_invalid, 190362306a36Sopenharmony_ci [RHF_RCV_TYPE_INVALID6] = process_receive_invalid, 190462306a36Sopenharmony_ci [RHF_RCV_TYPE_INVALID7] = process_receive_invalid, 190562306a36Sopenharmony_ci}; 1906