Sudeep Dutt | 40cb594 | 2015-04-29 05:32:34 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Intel MIC Platform Software Stack (MPSS) |
| 3 | * |
| 4 | * Copyright(c) 2014 Intel Corporation. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License, version 2, as |
| 8 | * published by the Free Software Foundation. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, but |
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | * General Public License for more details. |
| 14 | * |
| 15 | * Intel SCIF driver. |
| 16 | * |
| 17 | */ |
| 18 | #include "scif_peer_bus.h" |
| 19 | |
| 20 | #include "scif_main.h" |
| 21 | #include "scif_map.h" |
| 22 | |
| 23 | void scif_free_qp(struct scif_dev *scifdev) |
| 24 | { |
| 25 | struct scif_qp *qp = scifdev->qpairs; |
| 26 | |
| 27 | if (!qp) |
| 28 | return; |
| 29 | scif_free_coherent((void *)qp->inbound_q.rb_base, |
| 30 | qp->local_buf, scifdev, qp->inbound_q.size); |
| 31 | scif_unmap_single(qp->local_qp, scifdev, sizeof(struct scif_qp)); |
| 32 | kfree(scifdev->qpairs); |
| 33 | scifdev->qpairs = NULL; |
| 34 | } |
| 35 | |
| 36 | static void scif_cleanup_qp(struct scif_dev *dev) |
| 37 | { |
| 38 | struct scif_qp *qp = &dev->qpairs[0]; |
| 39 | |
| 40 | if (!qp) |
| 41 | return; |
| 42 | scif_iounmap((void *)qp->remote_qp, sizeof(struct scif_qp), dev); |
| 43 | scif_iounmap((void *)qp->outbound_q.rb_base, |
| 44 | sizeof(struct scif_qp), dev); |
| 45 | qp->remote_qp = NULL; |
| 46 | qp->local_write = 0; |
| 47 | qp->inbound_q.current_write_offset = 0; |
| 48 | qp->inbound_q.current_read_offset = 0; |
| 49 | if (scifdev_is_p2p(dev)) |
| 50 | scif_free_qp(dev); |
| 51 | } |
| 52 | |
| 53 | void scif_send_acks(struct scif_dev *dev) |
| 54 | { |
| 55 | struct scifmsg msg; |
| 56 | |
| 57 | if (dev->node_remove_ack_pending) { |
| 58 | msg.uop = SCIF_NODE_REMOVE_ACK; |
| 59 | msg.src.node = scif_info.nodeid; |
| 60 | msg.dst.node = SCIF_MGMT_NODE; |
| 61 | msg.payload[0] = dev->node; |
| 62 | scif_nodeqp_send(&scif_dev[SCIF_MGMT_NODE], &msg); |
| 63 | dev->node_remove_ack_pending = false; |
| 64 | } |
| 65 | if (dev->exit_ack_pending) { |
| 66 | msg.uop = SCIF_EXIT_ACK; |
| 67 | msg.src.node = scif_info.nodeid; |
| 68 | msg.dst.node = dev->node; |
| 69 | scif_nodeqp_send(dev, &msg); |
| 70 | dev->exit_ack_pending = false; |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | /* |
| 75 | * scif_cleanup_scifdev |
| 76 | * |
| 77 | * @dev: Remote SCIF device. |
| 78 | * Uninitialize SCIF data structures for remote SCIF device. |
| 79 | */ |
| 80 | void scif_cleanup_scifdev(struct scif_dev *dev) |
| 81 | { |
| 82 | struct scif_hw_dev *sdev = dev->sdev; |
| 83 | |
| 84 | if (!dev->sdev) |
| 85 | return; |
| 86 | if (scifdev_is_p2p(dev)) { |
| 87 | if (dev->cookie) { |
| 88 | sdev->hw_ops->free_irq(sdev, dev->cookie, dev); |
| 89 | dev->cookie = NULL; |
| 90 | } |
| 91 | scif_destroy_intr_wq(dev); |
| 92 | } |
| 93 | scif_destroy_p2p(dev); |
| 94 | scif_send_acks(dev); |
| 95 | if (!dev->node && scif_info.card_initiated_exit) { |
| 96 | /* |
| 97 | * Send an SCIF_EXIT message which is the last message from MIC |
| 98 | * to the Host and wait for a SCIF_EXIT_ACK |
| 99 | */ |
| 100 | scif_send_exit(dev); |
| 101 | scif_info.card_initiated_exit = false; |
| 102 | } |
| 103 | scif_cleanup_qp(dev); |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | * scif_remove_node: |
| 108 | * |
| 109 | * @node: Node to remove |
| 110 | */ |
| 111 | void scif_handle_remove_node(int node) |
| 112 | { |
| 113 | struct scif_dev *scifdev = &scif_dev[node]; |
| 114 | struct scif_peer_dev *spdev; |
| 115 | |
| 116 | rcu_read_lock(); |
| 117 | spdev = rcu_dereference(scifdev->spdev); |
| 118 | rcu_read_unlock(); |
| 119 | if (spdev) |
| 120 | scif_peer_unregister_device(spdev); |
| 121 | else |
| 122 | scif_send_acks(scifdev); |
| 123 | } |
| 124 | |
| 125 | static int scif_send_rmnode_msg(int node, int remove_node) |
| 126 | { |
| 127 | struct scifmsg notif_msg; |
| 128 | struct scif_dev *dev = &scif_dev[node]; |
| 129 | |
| 130 | notif_msg.uop = SCIF_NODE_REMOVE; |
| 131 | notif_msg.src.node = scif_info.nodeid; |
| 132 | notif_msg.dst.node = node; |
| 133 | notif_msg.payload[0] = remove_node; |
| 134 | return scif_nodeqp_send(dev, ¬if_msg); |
| 135 | } |
| 136 | |
| 137 | /** |
| 138 | * scif_node_disconnect: |
| 139 | * |
| 140 | * @node_id[in]: source node id. |
| 141 | * @mgmt_initiated: Disconnection initiated from the mgmt node |
| 142 | * |
| 143 | * Disconnect a node from the scif network. |
| 144 | */ |
| 145 | void scif_disconnect_node(u32 node_id, bool mgmt_initiated) |
| 146 | { |
| 147 | int ret; |
| 148 | int msg_cnt = 0; |
| 149 | u32 i = 0; |
| 150 | struct scif_dev *scifdev = &scif_dev[node_id]; |
| 151 | |
| 152 | if (!node_id) |
| 153 | return; |
| 154 | |
| 155 | atomic_set(&scifdev->disconn_rescnt, 0); |
| 156 | |
| 157 | /* Destroy p2p network */ |
| 158 | for (i = 1; i <= scif_info.maxid; i++) { |
| 159 | if (i == node_id) |
| 160 | continue; |
| 161 | ret = scif_send_rmnode_msg(i, node_id); |
| 162 | if (!ret) |
| 163 | msg_cnt++; |
| 164 | } |
| 165 | /* Wait for the remote nodes to respond with SCIF_NODE_REMOVE_ACK */ |
| 166 | ret = wait_event_timeout(scifdev->disconn_wq, |
| 167 | (atomic_read(&scifdev->disconn_rescnt) |
| 168 | == msg_cnt), SCIF_NODE_ALIVE_TIMEOUT); |
| 169 | /* Tell the card to clean up */ |
| 170 | if (mgmt_initiated && _scifdev_alive(scifdev)) |
| 171 | /* |
| 172 | * Send an SCIF_EXIT message which is the last message from Host |
| 173 | * to the MIC and wait for a SCIF_EXIT_ACK |
| 174 | */ |
| 175 | scif_send_exit(scifdev); |
| 176 | atomic_set(&scifdev->disconn_rescnt, 0); |
| 177 | /* Tell the mgmt node to clean up */ |
| 178 | ret = scif_send_rmnode_msg(SCIF_MGMT_NODE, node_id); |
| 179 | if (!ret) |
| 180 | /* Wait for mgmt node to respond with SCIF_NODE_REMOVE_ACK */ |
| 181 | wait_event_timeout(scifdev->disconn_wq, |
| 182 | (atomic_read(&scifdev->disconn_rescnt) == 1), |
| 183 | SCIF_NODE_ALIVE_TIMEOUT); |
| 184 | } |