blob: 5fefaccaf0d4cfb366c05f29593d1aa0735a1554 [file] [log] [blame]
Sudeep Dutt40cb5942015-04-29 05:32:34 -07001/*
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
23void 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
36static 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
53void 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 */
80void 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 */
111void 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
125static 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, &notif_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 */
145void 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}