/* * If the port is down, clean up all pending traps. We need to be careful * with the given trap, because it may be queued.
*/ staticvoid cleanup_traps(struct hfi1_ibport *ibp, struct trap_node *trap)
{ struct trap_node *node, *q; unsignedlong flags; struct list_head trap_list; int i;
for (i = 0; i < RVT_MAX_TRAP_LISTS; i++) {
spin_lock_irqsave(&ibp->rvp.lock, flags);
list_replace_init(&ibp->rvp.trap_lists[i].list, &trap_list);
ibp->rvp.trap_lists[i].list_len = 0;
spin_unlock_irqrestore(&ibp->rvp.lock, flags);
/* * Remove all items from the list, freeing all the non-given * traps.
*/
list_for_each_entry_safe(node, q, &trap_list, list) {
list_del(&node->list); if (node != trap)
kfree(node);
}
}
/* * If this wasn't on one of the lists it would not be freed. If it * was on the list, it is now safe to free.
*/
kfree(trap);
}
/* * Since the retry (handle timeout) does not remove a trap request * from the list, all we have to do is compare the node.
*/
spin_lock_irqsave(&ibp->rvp.lock, flags);
trap_list = &ibp->rvp.trap_lists[queue_id];
list_for_each_entry(node, &trap_list->list, list) { if (node == trap) {
node->retry++;
found = 1; break;
}
}
/* If it is not on the list, add it, limited to RVT-MAX_TRAP_LEN. */ if (!found) { if (trap_list->list_len < RVT_MAX_TRAP_LEN) {
trap_list->list_len++;
list_add_tail(&trap->list, &trap_list->list);
} else {
pr_warn_ratelimited("hfi1: Maximum trap limit reached for 0x%0x traps\n",
trap->data.generic_type);
kfree(trap);
}
}
/* * Next check to see if there is a timer pending. If not, set it up * and get the first trap from the list.
*/
node = NULL; if (!timer_pending(&ibp->rvp.trap_timer)) { /* * o14-2 * If the time out is set we have to wait until it expires * before the trap can be sent. * This should be > RVT_TRAP_TIMEOUT
*/
timeout = (RVT_TRAP_TIMEOUT *
(1UL << ibp->rvp.subnet_timeout)) / 1000;
mod_timer(&ibp->rvp.trap_timer,
jiffies + usecs_to_jiffies(timeout));
node = list_first_entry(&trap_list->list, struct trap_node,
list);
node->in_use = 1;
}
spin_unlock_irqrestore(&ibp->rvp.lock, flags);
/* Only update the transaction ID for new traps (o13-5). */ if (trap->tid == 0) {
ibp->rvp.tid++; /* make sure that tid != 0 */ if (ibp->rvp.tid == 0)
ibp->rvp.tid++;
trap->tid = cpu_to_be64(ibp->rvp.tid);
}
smp->tid = trap->tid;
/* * If the trap was repressed while things were getting set up, don't * bother sending it. This could happen for a retry.
*/ if (trap->repress) {
list_del(&trap->list);
spin_unlock_irqrestore(&ibp->rvp.lock, flags);
kfree(trap);
ib_free_send_mad(send_buf); return;
}
staticint check_mkey(struct hfi1_ibport *ibp, struct ib_mad_hdr *mad, int mad_flags, __be64 mkey, __be32 dr_slid,
u8 return_path[], u8 hop_cnt)
{ int valid_mkey = 0; int ret = 0;
/* Is the mkey in the process of expiring? */ if (ibp->rvp.mkey_lease_timeout &&
time_after_eq(jiffies, ibp->rvp.mkey_lease_timeout)) { /* Clear timeout and mkey protection field. */
ibp->rvp.mkey_lease_timeout = 0;
ibp->rvp.mkeyprot = 0;
}
/* Unset lease timeout on any valid Get/Set/TrapRepress */ if (valid_mkey && ibp->rvp.mkey_lease_timeout &&
(mad->method == IB_MGMT_METHOD_GET ||
mad->method == IB_MGMT_METHOD_SET ||
mad->method == IB_MGMT_METHOD_TRAP_REPRESS))
ibp->rvp.mkey_lease_timeout = 0;
if (!valid_mkey) { switch (mad->method) { case IB_MGMT_METHOD_GET: /* Bad mkey not a violation below level 2 */ if (ibp->rvp.mkeyprot < 2) break;
fallthrough; case IB_MGMT_METHOD_SET: case IB_MGMT_METHOD_TRAP_REPRESS: if (ibp->rvp.mkey_violations != 0xFFFF)
++ibp->rvp.mkey_violations; if (!ibp->rvp.mkey_lease_timeout &&
ibp->rvp.mkey_lease_period)
ibp->rvp.mkey_lease_timeout = jiffies +
ibp->rvp.mkey_lease_period * HZ; /* Generate a trap notice. */
bad_mkey(ibp, mad, mkey, dr_slid, return_path,
hop_cnt);
ret = 1;
}
}
return ret;
}
/* * The SMA caches reads from LCB registers in case the LCB is unavailable. * (The LCB is unavailable in certain link states, for example.)
*/ struct lcb_datum {
u32 off;
u64 val;
};
/* Only return the mkey if the protection field allows it. */ if (!(smp->method == IB_MGMT_METHOD_GET &&
ibp->rvp.mkey != smp->mkey &&
ibp->rvp.mkeyprot == 1))
pi->mkey = ibp->rvp.mkey;
if (start_of_sm_config && (state == IB_PORT_INIT))
ppd->is_sm_config_started = 1;
pi->port_phys_conf = (ppd->port_type & 0xf);
pi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4;
pi->port_states.ledenable_offlinereason |=
ppd->is_sm_config_started << 5; /* * This pairs with the memory barrier in hfi1_start_led_override to * ensure that we read the correct state of LED beaconing represented * by led_override_timer_active
*/
smp_rmb();
is_beaconing_active = !!atomic_read(&ppd->led_override_timer_active);
pi->port_states.ledenable_offlinereason |= is_beaconing_active << 6;
pi->port_states.ledenable_offlinereason |=
ppd->offline_disabled_reason;
/* HFI supports a replay buffer 128 LTPs in size */
pi->replay_depth.buffer = 0x80; /* read the cached value of DC_LCB_STS_ROUND_TRIP_LTP_CNT */
read_lcb_cache(DC_LCB_STS_ROUND_TRIP_LTP_CNT, &tmp);
/* * this counter is 16 bits wide, but the replay_depth.wire * variable is only 8 bits
*/ if (tmp > 0xff)
tmp = 0xff;
pi->replay_depth.wire = tmp;
if (resp_len)
*resp_len += sizeof(struct opa_port_info);
return reply((struct ib_mad_hdr *)smp);
}
/** * get_pkeys - return the PKEY table * @dd: the hfi1_ib device * @port: the IB port number * @pkeys: the pkey table is placed here
*/ staticint get_pkeys(struct hfi1_devdata *dd, u32 port, u16 *pkeys)
{ struct hfi1_pportdata *ppd = dd->pport + port - 1;
if (start_block + n_blocks_req > n_blocks_avail ||
n_blocks_req > OPA_NUM_PKEY_BLOCKS_PER_SMP) {
pr_warn("OPA Get PKey AM Invalid : s 0x%x; req 0x%x; " "avail 0x%x; blk/smp 0x%lx\n",
start_block, n_blocks_req, n_blocks_avail,
OPA_NUM_PKEY_BLOCKS_PER_SMP);
smp->status |= IB_SMP_INVALID_FIELD; return reply((struct ib_mad_hdr *)smp);
}
p = (__be16 *)data;
q = (u16 *)data; /* get the real pkeys if we are requesting the first block */ if (start_block == 0) {
get_pkeys(dd, port, q); for (i = 0; i < npkeys; i++)
p[i] = cpu_to_be16(q[i]); if (resp_len)
*resp_len += size;
} else {
smp->status |= IB_SMP_INVALID_FIELD;
} return reply((struct ib_mad_hdr *)smp);
}
ret = logical_transition_allowed(logical_old, logical_new);
logical_allowed = ret;
if (ret == HFI_TRANSITION_DISALLOWED ||
ret == HFI_TRANSITION_UNDEFINED) {
pr_warn("invalid logical state transition %s -> %s\n",
ib_port_state_to_str(logical_old),
ib_port_state_to_str(logical_new)); return ret;
}
ret = physical_transition_allowed(physical_old, physical_new);
physical_allowed = ret;
if (ret == HFI_TRANSITION_DISALLOWED ||
ret == HFI_TRANSITION_UNDEFINED) {
pr_warn("invalid physical state transition %s -> %s\n",
opa_pstate_name(physical_old),
opa_pstate_name(physical_new)); return ret;
}
if (logical_allowed == HFI_TRANSITION_IGNORED &&
physical_allowed == HFI_TRANSITION_IGNORED) return HFI_TRANSITION_IGNORED;
/* * A change request of Physical Port State from * 'Offline' to 'Polling' should be ignored.
*/ if ((physical_old == OPA_PORTPHYSSTATE_OFFLINE) &&
(physical_new == IB_PORTPHYSSTATE_POLLING)) return HFI_TRANSITION_IGNORED;
/* * Either physical_allowed or logical_allowed is * HFI_TRANSITION_ALLOWED.
*/ return HFI_TRANSITION_ALLOWED;
}
ret = port_states_transition_allowed(ppd, logical_state, phys_state); if (ret == HFI_TRANSITION_DISALLOWED ||
ret == HFI_TRANSITION_UNDEFINED) { /* error message emitted above */
smp->status |= IB_SMP_INVALID_FIELD; return 0;
}
if (ret == HFI_TRANSITION_IGNORED) return 0;
if ((phys_state != IB_PORTPHYSSTATE_NOP) &&
!(logical_state == IB_PORT_DOWN ||
logical_state == IB_PORT_NOP)){
pr_warn("SubnSet(OPA_PortInfo) port state invalid: logical_state 0x%x physical_state 0x%x\n",
logical_state, phys_state);
smp->status |= IB_SMP_INVALID_FIELD;
}
/* * Logical state changes are summarized in OPAv1g1 spec., * Table 9-12; physical state changes are summarized in * OPAv1g1 spec., Table 6.4.
*/ switch (logical_state) { case IB_PORT_NOP: if (phys_state == IB_PORTPHYSSTATE_NOP) break;
fallthrough; case IB_PORT_DOWN: if (phys_state == IB_PORTPHYSSTATE_NOP) {
link_state = HLS_DN_DOWNDEF;
} elseif (phys_state == IB_PORTPHYSSTATE_POLLING) {
link_state = HLS_DN_POLL;
set_link_down_reason(ppd, OPA_LINKDOWN_REASON_FM_BOUNCE,
0, OPA_LINKDOWN_REASON_FM_BOUNCE);
} elseif (phys_state == IB_PORTPHYSSTATE_DISABLED) {
link_state = HLS_DN_DISABLE;
} else {
pr_warn("SubnSet(OPA_PortInfo) invalid physical state 0x%x\n",
phys_state);
smp->status |= IB_SMP_INVALID_FIELD; break;
}
if ((link_state == HLS_DN_POLL ||
link_state == HLS_DN_DOWNDEF)) { /* * Going to poll. No matter what the current state, * always move offline first, then tune and start the * link. This correctly handles a FM link bounce and * a link enable. Going offline is a no-op if already * offline.
*/
set_link_state(ppd, HLS_DN_OFFLINE);
start_link(ppd);
} else {
set_link_state(ppd, link_state);
} if (link_state == HLS_DN_DISABLE &&
(ppd->offline_disabled_reason >
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_SMA_DISABLED) ||
ppd->offline_disabled_reason ==
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE)))
ppd->offline_disabled_reason =
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_SMA_DISABLED); /* * Don't send a reply if the response would be sent * through the disabled port.
*/ if (link_state == HLS_DN_DISABLE && !local_mad) return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; break; case IB_PORT_ARMED:
ret = set_link_state(ppd, HLS_UP_ARMED); if (!ret)
send_idle_sma(dd, SMA_IDLE_ARM); break; case IB_PORT_ACTIVE: if (ppd->neighbor_normal) {
ret = set_link_state(ppd, HLS_UP_ACTIVE); if (ret == 0)
send_idle_sma(dd, SMA_IDLE_ACTIVE);
} else {
pr_warn("SubnSet(OPA_PortInfo) Cannot move to Active with NeighborNormal 0\n");
smp->status |= IB_SMP_INVALID_FIELD;
} break; default:
pr_warn("SubnSet(OPA_PortInfo) invalid logical state 0x%x\n",
logical_state);
smp->status |= IB_SMP_INVALID_FIELD;
}
return 0;
}
/* * subn_set_opa_portinfo - set port information * @smp: the incoming SM packet * @ibdev: the infiniband device * @port: the port on the device *
*/ staticint __subn_set_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, struct ib_device *ibdev, u32 port,
u32 *resp_len, u32 max_len, int local_mad)
{ struct opa_port_info *pi = (struct opa_port_info *)data; struct ib_event event; struct hfi1_devdata *dd; struct hfi1_pportdata *ppd; struct hfi1_ibport *ibp;
u8 clientrereg; unsignedlong flags;
u32 smlid;
u32 lid;
u8 ls_old, ls_new, ps_new;
u8 vls;
u8 msl;
u8 crc_enabled;
u16 lse, lwe, mtu;
u32 num_ports = OPA_AM_NPORT(am);
u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); int ret, i, invalid = 0, call_set_mtu = 0; int call_link_downgrade_policy = 0;
lid = be32_to_cpu(pi->lid); if (lid & 0xFF000000) {
pr_warn("OPA_PortInfo lid out of range: %X\n", lid);
smp->status |= IB_SMP_INVALID_FIELD; goto get_only;
}
smlid = be32_to_cpu(pi->sm_lid); if (smlid & 0xFF000000) {
pr_warn("OPA_PortInfo SM lid out of range: %X\n", smlid);
smp->status |= IB_SMP_INVALID_FIELD; goto get_only;
}
if (ppd->vls_supported / 2 > ARRAY_SIZE(pi->neigh_mtu.pvlx_to_mtu) ||
ppd->vls_supported > ARRAY_SIZE(dd->vld)) {
smp->status |= IB_SMP_INVALID_FIELD; return reply((struct ib_mad_hdr *)smp);
} for (i = 0; i < ppd->vls_supported; i++) { if ((i % 2) == 0)
mtu = enum_to_mtu((pi->neigh_mtu.pvlx_to_mtu[i / 2] >>
4) & 0xF); else
mtu = enum_to_mtu(pi->neigh_mtu.pvlx_to_mtu[i / 2] &
0xF); if (mtu == 0xffff) {
pr_warn("SubnSet(OPA_PortInfo) mtu invalid %d (0x%x)\n",
mtu,
(pi->neigh_mtu.pvlx_to_mtu[0] >> 4) & 0xF);
smp->status |= IB_SMP_INVALID_FIELD;
mtu = hfi1_max_mtu; /* use a valid MTU */
} if (dd->vld[i].mtu != mtu) {
dd_dev_info(dd, "MTU change on vl %d from %d to %d\n",
i, dd->vld[i].mtu, mtu);
dd->vld[i].mtu = mtu;
call_set_mtu++;
}
} /* As per OPAV1 spec: VL15 must support and be configured * for operation with a 2048 or larger MTU.
*/
mtu = enum_to_mtu(pi->neigh_mtu.pvlx_to_mtu[15 / 2] & 0xF); if (mtu < 2048 || mtu == 0xffff)
mtu = 2048; if (dd->vld[15].mtu != mtu) {
dd_dev_info(dd, "MTU change on vl 15 from %d to %d\n",
dd->vld[15].mtu, mtu);
dd->vld[15].mtu = mtu;
call_set_mtu++;
} if (call_set_mtu)
set_mtu(ppd);
if (ls_old == IB_PORT_INIT) { if (start_of_sm_config) { if (ls_new == ls_old || (ls_new == IB_PORT_ARMED))
ppd->is_sm_config_started = 1;
} elseif (ls_new == IB_PORT_ARMED) { if (ppd->is_sm_config_started == 0) {
invalid = 1;
smp->status |= IB_SMP_INVALID_FIELD;
}
}
}
/* Handle CLIENT_REREGISTER event b/c SM asked us for it */ if (clientrereg) {
event.event = IB_EVENT_CLIENT_REREGISTER;
ib_dispatch_event(&event);
}
/* * Do the port state change now that the other link parameters * have been set. * Changing the port physical state only makes sense if the link * is down or is being set to down.
*/
if (!invalid) {
ret = set_port_states(ppd, smp, ls_new, ps_new, local_mad); if (ret) return ret;
}
ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len,
max_len);
/* restore re-reg bit per o14-12.2.1 */
pi->clientrereg_subnettimeout |= clientrereg;
/* * Apply the new link downgrade policy. This may result in a link * bounce. Do this after everything else so things are settled. * Possible problem: if setting the port state above fails, then * the policy change is not applied.
*/ if (call_link_downgrade_policy)
apply_link_downgrade_policy(ppd, 0);
/** * set_pkeys - set the PKEY table for ctxt 0 * @dd: the hfi1_ib device * @port: the IB port number * @pkeys: the PKEY table
*/ staticint set_pkeys(struct hfi1_devdata *dd, u32 port, u16 *pkeys)
{ struct hfi1_pportdata *ppd; int i; int changed = 0; int update_includes_mgmt_partition = 0;
/* * IB port one/two always maps to context zero/one, * always a kernel context, no locking needed * If we get here with ppd setup, no need to check * that rcd is valid.
*/
ppd = dd->pport + (port - 1); /* * If the update does not include the management pkey, don't do it.
*/ for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) { if (pkeys[i] == LIM_MGMT_P_KEY) {
update_includes_mgmt_partition = 1; break;
}
}
if (!update_includes_mgmt_partition) return 1;
for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) {
u16 key = pkeys[i];
u16 okey = ppd->pkeys[i];
if (key == okey) continue; /* * The SM gives us the complete PKey table. We have * to ensure that we put the PKeys in the matching * slots.
*/
ppd->pkeys[i] = key;
changed = 1;
}
if (changed) {
(void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_PKEYS, 0);
hfi1_event_pkey_change(dd, port);
}
#define ILLEGAL_VL 12 /* * filter_sc2vlt changes mappings to VL15 to ILLEGAL_VL (except * for SC15, which must map to VL15). If we don't remap things this * way it is possible for VL15 counters to increment when we try to * send on a SC which is mapped to an invalid VL. * When getting the table convert ILLEGAL_VL back to VL15.
*/ staticvoid filter_sc2vlt(void *data, bool set)
{ int i;
u8 *pd = data;
for (i = 0; i < OPA_MAX_SCS; i++) { if (i == 15) continue;
if (set) { if ((pd[i] & 0x1f) == 0xf)
pd[i] = ILLEGAL_VL;
} else { if ((pd[i] & 0x1f) == ILLEGAL_VL)
pd[i] = 0xf;
}
}
}
staticint __subn_set_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data, struct ib_device *ibdev, u32 port,
u32 *resp_len, u32 max_len)
{
u32 n_blocks = OPA_AM_NBLK(am); int async_update = OPA_AM_ASYNC(am); struct hfi1_devdata *dd = dd_from_ibdev(ibdev); void *vp = (void *)data; struct hfi1_pportdata *ppd; int lstate; /* * set_sc2vlt_tables writes the information contained in *data * to four 64-bit registers SendSC2VLt[0-3]. We need to make * sure *max_len is not greater than the total size of the four * SendSC2VLt[0-3] registers.
*/
size_t size = 4 * sizeof(u64);
/* IB numbers ports from 1, hw from 0 */
ppd = dd->pport + (port - 1);
lstate = driver_lstate(ppd); /* * it's known that async_update is 0 by this point, but include * the explicit check for clarity
*/ if (!async_update &&
(lstate == IB_PORT_ARMED || lstate == IB_PORT_ACTIVE)) {
smp->status |= IB_SMP_INVALID_FIELD; return reply((struct ib_mad_hdr *)smp);
}
/* * check that addr is within spec, and * addr and (addr + len - 1) are on the same "page"
*/ if (addr >= 4096 ||
(__CI_PAGE_NUM(addr) != __CI_PAGE_NUM(addr + len - 1))) {
smp->status |= IB_SMP_INVALID_FIELD; return reply((struct ib_mad_hdr *)smp);
}
/* The address range for the CableInfo SMA query is wider than the * memory available on the QSFP cable. We want to return a valid * response, albeit zeroed out, for address ranges beyond available * memory but that are within the CableInfo query spec
*/ if (ret < 0 && ret != -ERANGE) {
smp->status |= IB_SMP_INVALID_FIELD; return reply((struct ib_mad_hdr *)smp);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.