1 /*
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2017 Cavium, Inc.. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Cavium, Inc. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <rte_ethdev.h>
35 #include <rte_cycles.h>
36 
37 #include "lio_logs.h"
38 #include "lio_struct.h"
39 #include "lio_mbox.h"
40 
41 /**
42  * lio_mbox_read:
43  * @mbox: Pointer mailbox
44  *
45  * Reads the 8-bytes of data from the mbox register
46  * Writes back the acknowledgment indicating completion of read
47  */
48 int
49 lio_mbox_read(struct lio_mbox *mbox)
50 {
51 	union lio_mbox_message msg;
52 	int ret = 0;
53 
54 	msg.mbox_msg64 = rte_read64(mbox->mbox_read_reg);
55 
56 	if ((msg.mbox_msg64 == LIO_PFVFACK) || (msg.mbox_msg64 == LIO_PFVFSIG))
57 		return 0;
58 
59 	if (mbox->state & LIO_MBOX_STATE_REQ_RECEIVING) {
60 		mbox->mbox_req.data[mbox->mbox_req.recv_len - 1] =
61 					msg.mbox_msg64;
62 		mbox->mbox_req.recv_len++;
63 	} else {
64 		if (mbox->state & LIO_MBOX_STATE_RES_RECEIVING) {
65 			mbox->mbox_resp.data[mbox->mbox_resp.recv_len - 1] =
66 					msg.mbox_msg64;
67 			mbox->mbox_resp.recv_len++;
68 		} else {
69 			if ((mbox->state & LIO_MBOX_STATE_IDLE) &&
70 					(msg.s.type == LIO_MBOX_REQUEST)) {
71 				mbox->state &= ~LIO_MBOX_STATE_IDLE;
72 				mbox->state |= LIO_MBOX_STATE_REQ_RECEIVING;
73 				mbox->mbox_req.msg.mbox_msg64 = msg.mbox_msg64;
74 				mbox->mbox_req.q_no = mbox->q_no;
75 				mbox->mbox_req.recv_len = 1;
76 			} else {
77 				if ((mbox->state &
78 				     LIO_MBOX_STATE_RES_PENDING) &&
79 				    (msg.s.type == LIO_MBOX_RESPONSE)) {
80 					mbox->state &=
81 						~LIO_MBOX_STATE_RES_PENDING;
82 					mbox->state |=
83 						LIO_MBOX_STATE_RES_RECEIVING;
84 					mbox->mbox_resp.msg.mbox_msg64 =
85 								msg.mbox_msg64;
86 					mbox->mbox_resp.q_no = mbox->q_no;
87 					mbox->mbox_resp.recv_len = 1;
88 				} else {
89 					rte_write64(LIO_PFVFERR,
90 						    mbox->mbox_read_reg);
91 					mbox->state |= LIO_MBOX_STATE_ERROR;
92 					return -1;
93 				}
94 			}
95 		}
96 	}
97 
98 	if (mbox->state & LIO_MBOX_STATE_REQ_RECEIVING) {
99 		if (mbox->mbox_req.recv_len < msg.s.len) {
100 			ret = 0;
101 		} else {
102 			mbox->state &= ~LIO_MBOX_STATE_REQ_RECEIVING;
103 			mbox->state |= LIO_MBOX_STATE_REQ_RECEIVED;
104 			ret = 1;
105 		}
106 	} else {
107 		if (mbox->state & LIO_MBOX_STATE_RES_RECEIVING) {
108 			if (mbox->mbox_resp.recv_len < msg.s.len) {
109 				ret = 0;
110 			} else {
111 				mbox->state &= ~LIO_MBOX_STATE_RES_RECEIVING;
112 				mbox->state |= LIO_MBOX_STATE_RES_RECEIVED;
113 				ret = 1;
114 			}
115 		} else {
116 			RTE_ASSERT(0);
117 		}
118 	}
119 
120 	rte_write64(LIO_PFVFACK, mbox->mbox_read_reg);
121 
122 	return ret;
123 }
124 
125 /**
126  * lio_mbox_write:
127  * @lio_dev: Pointer lio device
128  * @mbox_cmd: Cmd to send to mailbox.
129  *
130  * Populates the queue specific mbox structure
131  * with cmd information.
132  * Write the cmd to mbox register
133  */
134 int
135 lio_mbox_write(struct lio_device *lio_dev,
136 	       struct lio_mbox_cmd *mbox_cmd)
137 {
138 	struct lio_mbox *mbox = lio_dev->mbox[mbox_cmd->q_no];
139 	uint32_t count, i, ret = LIO_MBOX_STATUS_SUCCESS;
140 
141 	if ((mbox_cmd->msg.s.type == LIO_MBOX_RESPONSE) &&
142 			!(mbox->state & LIO_MBOX_STATE_REQ_RECEIVED))
143 		return LIO_MBOX_STATUS_FAILED;
144 
145 	if ((mbox_cmd->msg.s.type == LIO_MBOX_REQUEST) &&
146 			!(mbox->state & LIO_MBOX_STATE_IDLE))
147 		return LIO_MBOX_STATUS_BUSY;
148 
149 	if (mbox_cmd->msg.s.type == LIO_MBOX_REQUEST) {
150 		rte_memcpy(&mbox->mbox_resp, mbox_cmd,
151 			   sizeof(struct lio_mbox_cmd));
152 		mbox->state = LIO_MBOX_STATE_RES_PENDING;
153 	}
154 
155 	count = 0;
156 
157 	while (rte_read64(mbox->mbox_write_reg) != LIO_PFVFSIG) {
158 		rte_delay_ms(1);
159 		if (count++ == 1000) {
160 			ret = LIO_MBOX_STATUS_FAILED;
161 			break;
162 		}
163 	}
164 
165 	if (ret == LIO_MBOX_STATUS_SUCCESS) {
166 		rte_write64(mbox_cmd->msg.mbox_msg64, mbox->mbox_write_reg);
167 		for (i = 0; i < (uint32_t)(mbox_cmd->msg.s.len - 1); i++) {
168 			count = 0;
169 			while (rte_read64(mbox->mbox_write_reg) !=
170 					LIO_PFVFACK) {
171 				rte_delay_ms(1);
172 				if (count++ == 1000) {
173 					ret = LIO_MBOX_STATUS_FAILED;
174 					break;
175 				}
176 			}
177 			rte_write64(mbox_cmd->data[i], mbox->mbox_write_reg);
178 		}
179 	}
180 
181 	if (mbox_cmd->msg.s.type == LIO_MBOX_RESPONSE) {
182 		mbox->state = LIO_MBOX_STATE_IDLE;
183 		rte_write64(LIO_PFVFSIG, mbox->mbox_read_reg);
184 	} else {
185 		if ((!mbox_cmd->msg.s.resp_needed) ||
186 				(ret == LIO_MBOX_STATUS_FAILED)) {
187 			mbox->state &= ~LIO_MBOX_STATE_RES_PENDING;
188 			if (!(mbox->state & (LIO_MBOX_STATE_REQ_RECEIVING |
189 					     LIO_MBOX_STATE_REQ_RECEIVED)))
190 				mbox->state = LIO_MBOX_STATE_IDLE;
191 		}
192 	}
193 
194 	return ret;
195 }
196 
197 /**
198  * lio_mbox_process_cmd:
199  * @mbox: Pointer mailbox
200  * @mbox_cmd: Pointer to command received
201  *
202  * Process the cmd received in mbox
203  */
204 static int
205 lio_mbox_process_cmd(struct lio_mbox *mbox,
206 		     struct lio_mbox_cmd *mbox_cmd)
207 {
208 	struct lio_device *lio_dev = mbox->lio_dev;
209 
210 	if (mbox_cmd->msg.s.cmd == LIO_CORES_CRASHED)
211 		lio_dev_err(lio_dev, "Octeon core(s) crashed or got stuck!\n");
212 
213 	return 0;
214 }
215 
216 /**
217  * Process the received mbox message.
218  */
219 int
220 lio_mbox_process_message(struct lio_mbox *mbox)
221 {
222 	struct lio_mbox_cmd mbox_cmd;
223 
224 	if (mbox->state & LIO_MBOX_STATE_ERROR) {
225 		if (mbox->state & (LIO_MBOX_STATE_RES_PENDING |
226 				   LIO_MBOX_STATE_RES_RECEIVING)) {
227 			rte_memcpy(&mbox_cmd, &mbox->mbox_resp,
228 				   sizeof(struct lio_mbox_cmd));
229 			mbox->state = LIO_MBOX_STATE_IDLE;
230 			rte_write64(LIO_PFVFSIG, mbox->mbox_read_reg);
231 			mbox_cmd.recv_status = 1;
232 			if (mbox_cmd.fn)
233 				mbox_cmd.fn(mbox->lio_dev, &mbox_cmd,
234 					    mbox_cmd.fn_arg);
235 
236 			return 0;
237 		}
238 
239 		mbox->state = LIO_MBOX_STATE_IDLE;
240 		rte_write64(LIO_PFVFSIG, mbox->mbox_read_reg);
241 
242 		return 0;
243 	}
244 
245 	if (mbox->state & LIO_MBOX_STATE_RES_RECEIVED) {
246 		rte_memcpy(&mbox_cmd, &mbox->mbox_resp,
247 			   sizeof(struct lio_mbox_cmd));
248 		mbox->state = LIO_MBOX_STATE_IDLE;
249 		rte_write64(LIO_PFVFSIG, mbox->mbox_read_reg);
250 		mbox_cmd.recv_status = 0;
251 		if (mbox_cmd.fn)
252 			mbox_cmd.fn(mbox->lio_dev, &mbox_cmd, mbox_cmd.fn_arg);
253 
254 		return 0;
255 	}
256 
257 	if (mbox->state & LIO_MBOX_STATE_REQ_RECEIVED) {
258 		rte_memcpy(&mbox_cmd, &mbox->mbox_req,
259 			   sizeof(struct lio_mbox_cmd));
260 		if (!mbox_cmd.msg.s.resp_needed) {
261 			mbox->state &= ~LIO_MBOX_STATE_REQ_RECEIVED;
262 			if (!(mbox->state & LIO_MBOX_STATE_RES_PENDING))
263 				mbox->state = LIO_MBOX_STATE_IDLE;
264 			rte_write64(LIO_PFVFSIG, mbox->mbox_read_reg);
265 		}
266 
267 		lio_mbox_process_cmd(mbox, &mbox_cmd);
268 
269 		return 0;
270 	}
271 
272 	RTE_ASSERT(0);
273 
274 	return 0;
275 }
276