// SPDX-License-Identifier: GPL-2.0 /* Shared Memory Communications Direct over ISM devices (SMC-D) * * Functions for ISM device. * * Copyright IBM Corp. 2018
*/
/* Test if an ISM communication is possible - same CPC */ int smc_ism_cantalk(struct smcd_gid *peer_gid, unsignedshort vlan_id, struct smcd_dev *smcd)
{ return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0,
vlan_id);
}
/* Register a VLAN identifier with the ISM device. Use a reference count * and add a VLAN identifier only when the first DMB using this VLAN is * registered.
*/ int smc_ism_get_vlan(struct smcd_dev *smcd, unsignedshort vlanid)
{ struct smc_ism_vlanid *new_vlan, *vlan; unsignedlong flags; int rc = 0;
if (!vlanid) /* No valid vlan id */ return -EINVAL; if (!smcd->ops->add_vlan_id) return -EOPNOTSUPP;
/* create new vlan entry, in case we need it */
new_vlan = kzalloc(sizeof(*new_vlan), GFP_KERNEL); if (!new_vlan) return -ENOMEM;
new_vlan->vlanid = vlanid;
refcount_set(&new_vlan->refcnt, 1);
/* if there is an existing entry, increase count and return */
spin_lock_irqsave(&smcd->lock, flags);
list_for_each_entry(vlan, &smcd->vlan, list) { if (vlan->vlanid == vlanid) {
refcount_inc(&vlan->refcnt);
kfree(new_vlan); goto out;
}
}
/* no existing entry found. * add new entry to device; might fail, e.g., if HW limit reached
*/ if (smcd->ops->add_vlan_id(smcd, vlanid)) {
kfree(new_vlan);
rc = -EIO; goto out;
}
list_add_tail(&new_vlan->list, &smcd->vlan);
out:
spin_unlock_irqrestore(&smcd->lock, flags); return rc;
}
/* Unregister a VLAN identifier with the ISM device. Use a reference count * and remove a VLAN identifier only when the last DMB using this VLAN is * unregistered.
*/ int smc_ism_put_vlan(struct smcd_dev *smcd, unsignedshort vlanid)
{ struct smc_ism_vlanid *vlan; unsignedlong flags; bool found = false; int rc = 0;
if (!vlanid) /* No valid vlan id */ return -EINVAL; if (!smcd->ops->del_vlan_id) return -EOPNOTSUPP;
spin_lock_irqsave(&smcd->lock, flags);
list_for_each_entry(vlan, &smcd->vlan, list) { if (vlan->vlanid == vlanid) { if (!refcount_dec_and_test(&vlan->refcnt)) goto out;
found = true; break;
}
} if (!found) {
rc = -ENOENT; goto out; /* VLAN id not in table */
}
/* Found and the last reference just gone */ if (smcd->ops->del_vlan_id(smcd, vlanid))
rc = -EIO;
list_del(&vlan->list);
kfree(vlan);
out:
spin_unlock_irqrestore(&smcd->lock, flags); return rc;
}
int smc_ism_unregister_dmb(struct smcd_dev *smcd, struct smc_buf_desc *dmb_desc)
{ struct smcd_dmb dmb; int rc = 0;
bool smc_ism_support_dmb_nocopy(struct smcd_dev *smcd)
{ /* for now only loopback-ism supports * merging sndbuf with peer DMB to avoid * data copies between them.
*/ return (smcd->ops->support_dmb_nocopy &&
smcd->ops->support_dmb_nocopy(smcd));
}
int smc_ism_attach_dmb(struct smcd_dev *dev, u64 token, struct smc_buf_desc *dmb_desc)
{ struct smcd_dmb dmb; int rc = 0;
/* SMCD Device event handler. Called from ISM device interrupt handler. * Parameters are ism device pointer, * - event->type (0 --> DMB, 1 --> GID), * - event->code (event code), * - event->tok (either DMB token when event type 0, or GID when event type 1) * - event->time (time of day) * - event->info (debug info). * * Context: * - Function called in IRQ context from ISM device driver event handler.
*/ staticvoid smcd_handle_event(struct ism_dev *ism, struct ism_event *event)
{ struct smcd_dev *smcd = ism_get_priv(ism, &smc_ism_client); struct smc_ism_event_work *wrk;
if (smcd->going_away) return; /* copy event to event work queue, and let it be handled there */
wrk = kmalloc(sizeof(*wrk), GFP_ATOMIC); if (!wrk) return;
INIT_WORK(&wrk->work, smc_ism_event_work);
wrk->smcd = smcd;
wrk->event = *event;
queue_work(smcd->event_wq, &wrk->work);
}
/* SMCD Device interrupt handler. Called from ISM device interrupt handler. * Parameters are the ism device pointer, DMB number, and the DMBE bitmask. * Find the connection and schedule the tasklet for this connection. * * Context: * - Function called in IRQ context from ISM device driver IRQ handler.
*/ staticvoid smcd_handle_irq(struct ism_dev *ism, unsignedint dmbno,
u16 dmbemask)
{ struct smcd_dev *smcd = ism_get_priv(ism, &smc_ism_client); struct smc_connection *conn = NULL; unsignedlong flags;
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.