in rio_cm.c [1988:2057]
static void riocm_remove_dev(struct device *dev, struct subsys_interface *sif)
{
struct rio_dev *rdev = to_rio_dev(dev);
struct cm_dev *cm;
struct cm_peer *peer;
struct rio_channel *ch, *_c;
unsigned int i;
bool found = false;
LIST_HEAD(list);
/* Check if the remote device has capabilities required to support CM */
if (!dev_cm_capable(rdev))
return;
riocm_debug(RDEV, "(%s)", rio_name(rdev));
/* Find matching cm_dev object */
down_write(&rdev_sem);
list_for_each_entry(cm, &cm_dev_list, list) {
if (cm->mport == rdev->net->hport) {
found = true;
break;
}
}
if (!found) {
up_write(&rdev_sem);
return;
}
/* Remove remote device from the list of peers */
found = false;
list_for_each_entry(peer, &cm->peers, node) {
if (peer->rdev == rdev) {
riocm_debug(RDEV, "removing peer %s", rio_name(rdev));
found = true;
list_del(&peer->node);
cm->npeers--;
kfree(peer);
break;
}
}
up_write(&rdev_sem);
if (!found)
return;
/*
* Release channels associated with this peer
*/
spin_lock_bh(&idr_lock);
idr_for_each_entry(&ch_idr, ch, i) {
if (ch && ch->rdev == rdev) {
if (atomic_read(&rdev->state) != RIO_DEVICE_SHUTDOWN)
riocm_exch(ch, RIO_CM_DISCONNECT);
idr_remove(&ch_idr, ch->id);
list_add(&ch->ch_node, &list);
}
}
spin_unlock_bh(&idr_lock);
if (!list_empty(&list)) {
list_for_each_entry_safe(ch, _c, &list, ch_node) {
list_del(&ch->ch_node);
riocm_ch_close(ch);
}
}
}