in rio_cm.c [2175:2238]
static void riocm_remove_mport(struct device *dev,
struct class_interface *class_intf)
{
struct rio_mport *mport = to_rio_mport(dev);
struct cm_dev *cm;
struct cm_peer *peer, *temp;
struct rio_channel *ch, *_c;
unsigned int i;
bool found = false;
LIST_HEAD(list);
riocm_debug(MPORT, "%s", mport->name);
/* Find a matching cm_dev object */
down_write(&rdev_sem);
list_for_each_entry(cm, &cm_dev_list, list) {
if (cm->mport == mport) {
list_del(&cm->list);
found = true;
break;
}
}
up_write(&rdev_sem);
if (!found)
return;
flush_workqueue(cm->rx_wq);
destroy_workqueue(cm->rx_wq);
/* Release channels bound to this mport */
spin_lock_bh(&idr_lock);
idr_for_each_entry(&ch_idr, ch, i) {
if (ch->cmdev == cm) {
riocm_debug(RDEV, "%s drop ch_%d",
mport->name, ch->id);
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);
}
}
rio_release_inb_mbox(mport, cmbox);
rio_release_outb_mbox(mport, cmbox);
/* Remove and free peer entries */
if (!list_empty(&cm->peers))
riocm_debug(RDEV, "ATTN: peer list not empty");
list_for_each_entry_safe(peer, temp, &cm->peers, node) {
riocm_debug(RDEV, "removing peer %s", rio_name(peer->rdev));
list_del(&peer->node);
kfree(peer);
}
riocm_rx_free(cm);
kfree(cm);
riocm_debug(MPORT, "%s done", mport->name);
}