1/* Intel Ethernet Switch Host Interface Driver
2 * Copyright(c) 2013 - 2015 Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11 * more details.
12 *
13 * The full GNU General Public License is included in this distribution in
14 * the file called "COPYING".
15 *
16 * Contact Information:
17 * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
18 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
19 */
20
21#include "fm10k_common.h"
22
23/**
24 *  fm10k_fifo_init - Initialize a message FIFO
25 *  @fifo: pointer to FIFO
26 *  @buffer: pointer to memory to be used to store FIFO
27 *  @size: maximum message size to store in FIFO, must be 2^n - 1
28 **/
29static void fm10k_fifo_init(struct fm10k_mbx_fifo *fifo, u32 *buffer, u16 size)
30{
31	fifo->buffer = buffer;
32	fifo->size = size;
33	fifo->head = 0;
34	fifo->tail = 0;
35}
36
37/**
38 *  fm10k_fifo_used - Retrieve used space in FIFO
39 *  @fifo: pointer to FIFO
40 *
41 *  This function returns the number of DWORDs used in the FIFO
42 **/
43static u16 fm10k_fifo_used(struct fm10k_mbx_fifo *fifo)
44{
45	return fifo->tail - fifo->head;
46}
47
48/**
49 *  fm10k_fifo_unused - Retrieve unused space in FIFO
50 *  @fifo: pointer to FIFO
51 *
52 *  This function returns the number of unused DWORDs in the FIFO
53 **/
54static u16 fm10k_fifo_unused(struct fm10k_mbx_fifo *fifo)
55{
56	return fifo->size + fifo->head - fifo->tail;
57}
58
59/**
60 *  fm10k_fifo_empty - Test to verify if fifo is empty
61 *  @fifo: pointer to FIFO
62 *
63 *  This function returns true if the FIFO is empty, else false
64 **/
65static bool fm10k_fifo_empty(struct fm10k_mbx_fifo *fifo)
66{
67	return fifo->head == fifo->tail;
68}
69
70/**
71 *  fm10k_fifo_head_offset - returns indices of head with given offset
72 *  @fifo: pointer to FIFO
73 *  @offset: offset to add to head
74 *
75 *  This function returns the indices into the fifo based on head + offset
76 **/
77static u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
78{
79	return (fifo->head + offset) & (fifo->size - 1);
80}
81
82/**
83 *  fm10k_fifo_tail_offset - returns indices of tail with given offset
84 *  @fifo: pointer to FIFO
85 *  @offset: offset to add to tail
86 *
87 *  This function returns the indices into the fifo based on tail + offset
88 **/
89static u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
90{
91	return (fifo->tail + offset) & (fifo->size - 1);
92}
93
94/**
95 *  fm10k_fifo_head_len - Retrieve length of first message in FIFO
96 *  @fifo: pointer to FIFO
97 *
98 *  This function returns the size of the first message in the FIFO
99 **/
100static u16 fm10k_fifo_head_len(struct fm10k_mbx_fifo *fifo)
101{
102	u32 *head = fifo->buffer + fm10k_fifo_head_offset(fifo, 0);
103
104	/* verify there is at least 1 DWORD in the fifo so *head is valid */
105	if (fm10k_fifo_empty(fifo))
106		return 0;
107
108	/* retieve the message length */
109	return FM10K_TLV_DWORD_LEN(*head);
110}
111
112/**
113 *  fm10k_fifo_head_drop - Drop the first message in FIFO
114 *  @fifo: pointer to FIFO
115 *
116 *  This function returns the size of the message dropped from the FIFO
117 **/
118static u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo)
119{
120	u16 len = fm10k_fifo_head_len(fifo);
121
122	/* update head so it is at the start of next frame */
123	fifo->head += len;
124
125	return len;
126}
127
128/**
129 *  fm10k_fifo_drop_all - Drop all messages in FIFO
130 *  @fifo: pointer to FIFO
131 *
132 *  This function resets the head pointer to drop all messages in the FIFO and
133 *  ensure the FIFO is empty.
134 **/
135static void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo)
136{
137	fifo->head = fifo->tail;
138}
139
140/**
141 *  fm10k_mbx_index_len - Convert a head/tail index into a length value
142 *  @mbx: pointer to mailbox
143 *  @head: head index
144 *  @tail: head index
145 *
146 *  This function takes the head and tail index and determines the length
147 *  of the data indicated by this pair.
148 **/
149static u16 fm10k_mbx_index_len(struct fm10k_mbx_info *mbx, u16 head, u16 tail)
150{
151	u16 len = tail - head;
152
153	/* we wrapped so subtract 2, one for index 0, one for all 1s index */
154	if (len > tail)
155		len -= 2;
156
157	return len & ((mbx->mbmem_len << 1) - 1);
158}
159
160/**
161 *  fm10k_mbx_tail_add - Determine new tail value with added offset
162 *  @mbx: pointer to mailbox
163 *  @offset: length to add to head offset
164 *
165 *  This function takes the local tail index and recomputes it for
166 *  a given length added as an offset.
167 **/
168static u16 fm10k_mbx_tail_add(struct fm10k_mbx_info *mbx, u16 offset)
169{
170	u16 tail = (mbx->tail + offset + 1) & ((mbx->mbmem_len << 1) - 1);
171
172	/* add/sub 1 because we cannot have offset 0 or all 1s */
173	return (tail > mbx->tail) ? --tail : ++tail;
174}
175
176/**
177 *  fm10k_mbx_tail_sub - Determine new tail value with subtracted offset
178 *  @mbx: pointer to mailbox
179 *  @offset: length to add to head offset
180 *
181 *  This function takes the local tail index and recomputes it for
182 *  a given length added as an offset.
183 **/
184static u16 fm10k_mbx_tail_sub(struct fm10k_mbx_info *mbx, u16 offset)
185{
186	u16 tail = (mbx->tail - offset - 1) & ((mbx->mbmem_len << 1) - 1);
187
188	/* sub/add 1 because we cannot have offset 0 or all 1s */
189	return (tail < mbx->tail) ? ++tail : --tail;
190}
191
192/**
193 *  fm10k_mbx_head_add - Determine new head value with added offset
194 *  @mbx: pointer to mailbox
195 *  @offset: length to add to head offset
196 *
197 *  This function takes the local head index and recomputes it for
198 *  a given length added as an offset.
199 **/
200static u16 fm10k_mbx_head_add(struct fm10k_mbx_info *mbx, u16 offset)
201{
202	u16 head = (mbx->head + offset + 1) & ((mbx->mbmem_len << 1) - 1);
203
204	/* add/sub 1 because we cannot have offset 0 or all 1s */
205	return (head > mbx->head) ? --head : ++head;
206}
207
208/**
209 *  fm10k_mbx_head_sub - Determine new head value with subtracted offset
210 *  @mbx: pointer to mailbox
211 *  @offset: length to add to head offset
212 *
213 *  This function takes the local head index and recomputes it for
214 *  a given length added as an offset.
215 **/
216static u16 fm10k_mbx_head_sub(struct fm10k_mbx_info *mbx, u16 offset)
217{
218	u16 head = (mbx->head - offset - 1) & ((mbx->mbmem_len << 1) - 1);
219
220	/* sub/add 1 because we cannot have offset 0 or all 1s */
221	return (head < mbx->head) ? ++head : --head;
222}
223
224/**
225 *  fm10k_mbx_pushed_tail_len - Retrieve the length of message being pushed
226 *  @mbx: pointer to mailbox
227 *
228 *  This function will return the length of the message currently being
229 *  pushed onto the tail of the Rx queue.
230 **/
231static u16 fm10k_mbx_pushed_tail_len(struct fm10k_mbx_info *mbx)
232{
233	u32 *tail = mbx->rx.buffer + fm10k_fifo_tail_offset(&mbx->rx, 0);
234
235	/* pushed tail is only valid if pushed is set */
236	if (!mbx->pushed)
237		return 0;
238
239	return FM10K_TLV_DWORD_LEN(*tail);
240}
241
242/**
243 *  fm10k_fifo_write_copy - pulls data off of msg and places it in fifo
244 *  @fifo: pointer to FIFO
245 *  @msg: message array to populate
246 *  @tail_offset: additional offset to add to tail pointer
247 *  @len: length of FIFO to copy into message header
248 *
249 *  This function will take a message and copy it into a section of the
250 *  FIFO.  In order to get something into a location other than just
251 *  the tail you can use tail_offset to adjust the pointer.
252 **/
253static void fm10k_fifo_write_copy(struct fm10k_mbx_fifo *fifo,
254				  const u32 *msg, u16 tail_offset, u16 len)
255{
256	u16 end = fm10k_fifo_tail_offset(fifo, tail_offset);
257	u32 *tail = fifo->buffer + end;
258
259	/* track when we should cross the end of the FIFO */
260	end = fifo->size - end;
261
262	/* copy end of message before start of message */
263	if (end < len)
264		memcpy(fifo->buffer, msg + end, (len - end) << 2);
265	else
266		end = len;
267
268	/* Copy remaining message into Tx FIFO */
269	memcpy(tail, msg, end << 2);
270}
271
272/**
273 *  fm10k_fifo_enqueue - Enqueues the message to the tail of the FIFO
274 *  @fifo: pointer to FIFO
275 *  @msg: message array to read
276 *
277 *  This function enqueues a message up to the size specified by the length
278 *  contained in the first DWORD of the message and will place at the tail
279 *  of the FIFO.  It will return 0 on success, or a negative value on error.
280 **/
281static s32 fm10k_fifo_enqueue(struct fm10k_mbx_fifo *fifo, const u32 *msg)
282{
283	u16 len = FM10K_TLV_DWORD_LEN(*msg);
284
285	/* verify parameters */
286	if (len > fifo->size)
287		return FM10K_MBX_ERR_SIZE;
288
289	/* verify there is room for the message */
290	if (len > fm10k_fifo_unused(fifo))
291		return FM10K_MBX_ERR_NO_SPACE;
292
293	/* Copy message into FIFO */
294	fm10k_fifo_write_copy(fifo, msg, 0, len);
295
296	/* memory barrier to guarantee FIFO is written before tail update */
297	wmb();
298
299	/* Update Tx FIFO tail */
300	fifo->tail += len;
301
302	return 0;
303}
304
305/**
306 *  fm10k_mbx_validate_msg_size - Validate incoming message based on size
307 *  @mbx: pointer to mailbox
308 *  @len: length of data pushed onto buffer
309 *
310 *  This function analyzes the frame and will return a non-zero value when
311 *  the start of a message larger than the mailbox is detected.
312 **/
313static u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len)
314{
315	struct fm10k_mbx_fifo *fifo = &mbx->rx;
316	u16 total_len = 0, msg_len;
317	u32 *msg;
318
319	/* length should include previous amounts pushed */
320	len += mbx->pushed;
321
322	/* offset in message is based off of current message size */
323	do {
324		msg = fifo->buffer + fm10k_fifo_tail_offset(fifo, total_len);
325		msg_len = FM10K_TLV_DWORD_LEN(*msg);
326		total_len += msg_len;
327	} while (total_len < len);
328
329	/* message extends out of pushed section, but fits in FIFO */
330	if ((len < total_len) && (msg_len <= mbx->max_size))
331		return 0;
332
333	/* return length of invalid section */
334	return (len < total_len) ? len : (len - total_len);
335}
336
337/**
338 *  fm10k_mbx_write_copy - pulls data off of Tx FIFO and places it in mbmem
339 *  @mbx: pointer to mailbox
340 *
341 *  This function will take a section of the Tx FIFO and copy it into the
342 *  mailbox memory.  The offset in mbmem is based on the lower bits of the
343 *  tail and len determines the length to copy.
344 **/
345static void fm10k_mbx_write_copy(struct fm10k_hw *hw,
346				 struct fm10k_mbx_info *mbx)
347{
348	struct fm10k_mbx_fifo *fifo = &mbx->tx;
349	u32 mbmem = mbx->mbmem_reg;
350	u32 *head = fifo->buffer;
351	u16 end, len, tail, mask;
352
353	if (!mbx->tail_len)
354		return;
355
356	/* determine data length and mbmem tail index */
357	mask = mbx->mbmem_len - 1;
358	len = mbx->tail_len;
359	tail = fm10k_mbx_tail_sub(mbx, len);
360	if (tail > mask)
361		tail++;
362
363	/* determine offset in the ring */
364	end = fm10k_fifo_head_offset(fifo, mbx->pulled);
365	head += end;
366
367	/* memory barrier to guarantee data is ready to be read */
368	rmb();
369
370	/* Copy message from Tx FIFO */
371	for (end = fifo->size - end; len; head = fifo->buffer) {
372		do {
373			/* adjust tail to match offset for FIFO */
374			tail &= mask;
375			if (!tail)
376				tail++;
377
378			/* write message to hardware FIFO */
379			fm10k_write_reg(hw, mbmem + tail++, *(head++));
380		} while (--len && --end);
381	}
382}
383
384/**
385 *  fm10k_mbx_pull_head - Pulls data off of head of Tx FIFO
386 *  @hw: pointer to hardware structure
387 *  @mbx: pointer to mailbox
388 *  @head: acknowledgement number last received
389 *
390 *  This function will push the tail index forward based on the remote
391 *  head index.  It will then pull up to mbmem_len DWORDs off of the
392 *  head of the FIFO and will place it in the MBMEM registers
393 *  associated with the mailbox.
394 **/
395static void fm10k_mbx_pull_head(struct fm10k_hw *hw,
396				struct fm10k_mbx_info *mbx, u16 head)
397{
398	u16 mbmem_len, len, ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
399	struct fm10k_mbx_fifo *fifo = &mbx->tx;
400
401	/* update number of bytes pulled and update bytes in transit */
402	mbx->pulled += mbx->tail_len - ack;
403
404	/* determine length of data to pull, reserve space for mbmem header */
405	mbmem_len = mbx->mbmem_len - 1;
406	len = fm10k_fifo_used(fifo) - mbx->pulled;
407	if (len > mbmem_len)
408		len = mbmem_len;
409
410	/* update tail and record number of bytes in transit */
411	mbx->tail = fm10k_mbx_tail_add(mbx, len - ack);
412	mbx->tail_len = len;
413
414	/* drop pulled messages from the FIFO */
415	for (len = fm10k_fifo_head_len(fifo);
416	     len && (mbx->pulled >= len);
417	     len = fm10k_fifo_head_len(fifo)) {
418		mbx->pulled -= fm10k_fifo_head_drop(fifo);
419		mbx->tx_messages++;
420		mbx->tx_dwords += len;
421	}
422
423	/* Copy message out from the Tx FIFO */
424	fm10k_mbx_write_copy(hw, mbx);
425}
426
427/**
428 *  fm10k_mbx_read_copy - pulls data off of mbmem and places it in Rx FIFO
429 *  @hw: pointer to hardware structure
430 *  @mbx: pointer to mailbox
431 *
432 *  This function will take a section of the mailbox memory and copy it
433 *  into the Rx FIFO.  The offset is based on the lower bits of the
434 *  head and len determines the length to copy.
435 **/
436static void fm10k_mbx_read_copy(struct fm10k_hw *hw,
437				struct fm10k_mbx_info *mbx)
438{
439	struct fm10k_mbx_fifo *fifo = &mbx->rx;
440	u32 mbmem = mbx->mbmem_reg ^ mbx->mbmem_len;
441	u32 *tail = fifo->buffer;
442	u16 end, len, head;
443
444	/* determine data length and mbmem head index */
445	len = mbx->head_len;
446	head = fm10k_mbx_head_sub(mbx, len);
447	if (head >= mbx->mbmem_len)
448		head++;
449
450	/* determine offset in the ring */
451	end = fm10k_fifo_tail_offset(fifo, mbx->pushed);
452	tail += end;
453
454	/* Copy message into Rx FIFO */
455	for (end = fifo->size - end; len; tail = fifo->buffer) {
456		do {
457			/* adjust head to match offset for FIFO */
458			head &= mbx->mbmem_len - 1;
459			if (!head)
460				head++;
461
462			/* read message from hardware FIFO */
463			*(tail++) = fm10k_read_reg(hw, mbmem + head++);
464		} while (--len && --end);
465	}
466
467	/* memory barrier to guarantee FIFO is written before tail update */
468	wmb();
469}
470
471/**
472 *  fm10k_mbx_push_tail - Pushes up to 15 DWORDs on to tail of FIFO
473 *  @hw: pointer to hardware structure
474 *  @mbx: pointer to mailbox
475 *  @tail: tail index of message
476 *
477 *  This function will first validate the tail index and size for the
478 *  incoming message.  It then updates the acknowledgment number and
479 *  copies the data into the FIFO.  It will return the number of messages
480 *  dequeued on success and a negative value on error.
481 **/
482static s32 fm10k_mbx_push_tail(struct fm10k_hw *hw,
483			       struct fm10k_mbx_info *mbx,
484			       u16 tail)
485{
486	struct fm10k_mbx_fifo *fifo = &mbx->rx;
487	u16 len, seq = fm10k_mbx_index_len(mbx, mbx->head, tail);
488
489	/* determine length of data to push */
490	len = fm10k_fifo_unused(fifo) - mbx->pushed;
491	if (len > seq)
492		len = seq;
493
494	/* update head and record bytes received */
495	mbx->head = fm10k_mbx_head_add(mbx, len);
496	mbx->head_len = len;
497
498	/* nothing to do if there is no data */
499	if (!len)
500		return 0;
501
502	/* Copy msg into Rx FIFO */
503	fm10k_mbx_read_copy(hw, mbx);
504
505	/* determine if there are any invalid lengths in message */
506	if (fm10k_mbx_validate_msg_size(mbx, len))
507		return FM10K_MBX_ERR_SIZE;
508
509	/* Update pushed */
510	mbx->pushed += len;
511
512	/* flush any completed messages */
513	for (len = fm10k_mbx_pushed_tail_len(mbx);
514	     len && (mbx->pushed >= len);
515	     len = fm10k_mbx_pushed_tail_len(mbx)) {
516		fifo->tail += len;
517		mbx->pushed -= len;
518		mbx->rx_messages++;
519		mbx->rx_dwords += len;
520	}
521
522	return 0;
523}
524
525/* pre-generated data for generating the CRC based on the poly 0xAC9A. */
526static const u16 fm10k_crc_16b_table[256] = {
527	0x0000, 0x7956, 0xF2AC, 0x8BFA, 0xBC6D, 0xC53B, 0x4EC1, 0x3797,
528	0x21EF, 0x58B9, 0xD343, 0xAA15, 0x9D82, 0xE4D4, 0x6F2E, 0x1678,
529	0x43DE, 0x3A88, 0xB172, 0xC824, 0xFFB3, 0x86E5, 0x0D1F, 0x7449,
530	0x6231, 0x1B67, 0x909D, 0xE9CB, 0xDE5C, 0xA70A, 0x2CF0, 0x55A6,
531	0x87BC, 0xFEEA, 0x7510, 0x0C46, 0x3BD1, 0x4287, 0xC97D, 0xB02B,
532	0xA653, 0xDF05, 0x54FF, 0x2DA9, 0x1A3E, 0x6368, 0xE892, 0x91C4,
533	0xC462, 0xBD34, 0x36CE, 0x4F98, 0x780F, 0x0159, 0x8AA3, 0xF3F5,
534	0xE58D, 0x9CDB, 0x1721, 0x6E77, 0x59E0, 0x20B6, 0xAB4C, 0xD21A,
535	0x564D, 0x2F1B, 0xA4E1, 0xDDB7, 0xEA20, 0x9376, 0x188C, 0x61DA,
536	0x77A2, 0x0EF4, 0x850E, 0xFC58, 0xCBCF, 0xB299, 0x3963, 0x4035,
537	0x1593, 0x6CC5, 0xE73F, 0x9E69, 0xA9FE, 0xD0A8, 0x5B52, 0x2204,
538	0x347C, 0x4D2A, 0xC6D0, 0xBF86, 0x8811, 0xF147, 0x7ABD, 0x03EB,
539	0xD1F1, 0xA8A7, 0x235D, 0x5A0B, 0x6D9C, 0x14CA, 0x9F30, 0xE666,
540	0xF01E, 0x8948, 0x02B2, 0x7BE4, 0x4C73, 0x3525, 0xBEDF, 0xC789,
541	0x922F, 0xEB79, 0x6083, 0x19D5, 0x2E42, 0x5714, 0xDCEE, 0xA5B8,
542	0xB3C0, 0xCA96, 0x416C, 0x383A, 0x0FAD, 0x76FB, 0xFD01, 0x8457,
543	0xAC9A, 0xD5CC, 0x5E36, 0x2760, 0x10F7, 0x69A1, 0xE25B, 0x9B0D,
544	0x8D75, 0xF423, 0x7FD9, 0x068F, 0x3118, 0x484E, 0xC3B4, 0xBAE2,
545	0xEF44, 0x9612, 0x1DE8, 0x64BE, 0x5329, 0x2A7F, 0xA185, 0xD8D3,
546	0xCEAB, 0xB7FD, 0x3C07, 0x4551, 0x72C6, 0x0B90, 0x806A, 0xF93C,
547	0x2B26, 0x5270, 0xD98A, 0xA0DC, 0x974B, 0xEE1D, 0x65E7, 0x1CB1,
548	0x0AC9, 0x739F, 0xF865, 0x8133, 0xB6A4, 0xCFF2, 0x4408, 0x3D5E,
549	0x68F8, 0x11AE, 0x9A54, 0xE302, 0xD495, 0xADC3, 0x2639, 0x5F6F,
550	0x4917, 0x3041, 0xBBBB, 0xC2ED, 0xF57A, 0x8C2C, 0x07D6, 0x7E80,
551	0xFAD7, 0x8381, 0x087B, 0x712D, 0x46BA, 0x3FEC, 0xB416, 0xCD40,
552	0xDB38, 0xA26E, 0x2994, 0x50C2, 0x6755, 0x1E03, 0x95F9, 0xECAF,
553	0xB909, 0xC05F, 0x4BA5, 0x32F3, 0x0564, 0x7C32, 0xF7C8, 0x8E9E,
554	0x98E6, 0xE1B0, 0x6A4A, 0x131C, 0x248B, 0x5DDD, 0xD627, 0xAF71,
555	0x7D6B, 0x043D, 0x8FC7, 0xF691, 0xC106, 0xB850, 0x33AA, 0x4AFC,
556	0x5C84, 0x25D2, 0xAE28, 0xD77E, 0xE0E9, 0x99BF, 0x1245, 0x6B13,
557	0x3EB5, 0x47E3, 0xCC19, 0xB54F, 0x82D8, 0xFB8E, 0x7074, 0x0922,
558	0x1F5A, 0x660C, 0xEDF6, 0x94A0, 0xA337, 0xDA61, 0x519B, 0x28CD };
559
560/**
561 *  fm10k_crc_16b - Generate a 16 bit CRC for a region of 16 bit data
562 *  @data: pointer to data to process
563 *  @seed: seed value for CRC
564 *  @len: length measured in 16 bits words
565 *
566 *  This function will generate a CRC based on the polynomial 0xAC9A and
567 *  whatever value is stored in the seed variable.  Note that this
568 *  value inverts the local seed and the result in order to capture all
569 *  leading and trailing zeros.
570 */
571static u16 fm10k_crc_16b(const u32 *data, u16 seed, u16 len)
572{
573	u32 result = seed;
574
575	while (len--) {
576		result ^= *(data++);
577		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
578		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
579
580		if (!(len--))
581			break;
582
583		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
584		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
585	}
586
587	return (u16)result;
588}
589
590/**
591 *  fm10k_fifo_crc - generate a CRC based off of FIFO data
592 *  @fifo: pointer to FIFO
593 *  @offset: offset point for start of FIFO
594 *  @len: number of DWORDS words to process
595 *  @seed: seed value for CRC
596 *
597 *  This function generates a CRC for some region of the FIFO
598 **/
599static u16 fm10k_fifo_crc(struct fm10k_mbx_fifo *fifo, u16 offset,
600			  u16 len, u16 seed)
601{
602	u32 *data = fifo->buffer + offset;
603
604	/* track when we should cross the end of the FIFO */
605	offset = fifo->size - offset;
606
607	/* if we are in 2 blocks process the end of the FIFO first */
608	if (offset < len) {
609		seed = fm10k_crc_16b(data, seed, offset * 2);
610		data = fifo->buffer;
611		len -= offset;
612	}
613
614	/* process any remaining bits */
615	return fm10k_crc_16b(data, seed, len * 2);
616}
617
618/**
619 *  fm10k_mbx_update_local_crc - Update the local CRC for outgoing data
620 *  @mbx: pointer to mailbox
621 *  @head: head index provided by remote mailbox
622 *
623 *  This function will generate the CRC for all data from the end of the
624 *  last head update to the current one.  It uses the result of the
625 *  previous CRC as the seed for this update.  The result is stored in
626 *  mbx->local.
627 **/
628static void fm10k_mbx_update_local_crc(struct fm10k_mbx_info *mbx, u16 head)
629{
630	u16 len = mbx->tail_len - fm10k_mbx_index_len(mbx, head, mbx->tail);
631
632	/* determine the offset for the start of the region to be pulled */
633	head = fm10k_fifo_head_offset(&mbx->tx, mbx->pulled);
634
635	/* update local CRC to include all of the pulled data */
636	mbx->local = fm10k_fifo_crc(&mbx->tx, head, len, mbx->local);
637}
638
639/**
640 *  fm10k_mbx_verify_remote_crc - Verify the CRC is correct for current data
641 *  @mbx: pointer to mailbox
642 *
643 *  This function will take all data that has been provided from the remote
644 *  end and generate a CRC for it.  This is stored in mbx->remote.  The
645 *  CRC for the header is then computed and if the result is non-zero this
646 *  is an error and we signal an error dropping all data and resetting the
647 *  connection.
648 */
649static s32 fm10k_mbx_verify_remote_crc(struct fm10k_mbx_info *mbx)
650{
651	struct fm10k_mbx_fifo *fifo = &mbx->rx;
652	u16 len = mbx->head_len;
653	u16 offset = fm10k_fifo_tail_offset(fifo, mbx->pushed) - len;
654	u16 crc;
655
656	/* update the remote CRC if new data has been received */
657	if (len)
658		mbx->remote = fm10k_fifo_crc(fifo, offset, len, mbx->remote);
659
660	/* process the full header as we have to validate the CRC */
661	crc = fm10k_crc_16b(&mbx->mbx_hdr, mbx->remote, 1);
662
663	/* notify other end if we have a problem */
664	return crc ? FM10K_MBX_ERR_CRC : 0;
665}
666
667/**
668 *  fm10k_mbx_rx_ready - Indicates that a message is ready in the Rx FIFO
669 *  @mbx: pointer to mailbox
670 *
671 *  This function returns true if there is a message in the Rx FIFO to dequeue.
672 **/
673static bool fm10k_mbx_rx_ready(struct fm10k_mbx_info *mbx)
674{
675	u16 msg_size = fm10k_fifo_head_len(&mbx->rx);
676
677	return msg_size && (fm10k_fifo_used(&mbx->rx) >= msg_size);
678}
679
680/**
681 *  fm10k_mbx_tx_ready - Indicates that the mailbox is in state ready for Tx
682 *  @mbx: pointer to mailbox
683 *  @len: verify free space is >= this value
684 *
685 *  This function returns true if the mailbox is in a state ready to transmit.
686 **/
687static bool fm10k_mbx_tx_ready(struct fm10k_mbx_info *mbx, u16 len)
688{
689	u16 fifo_unused = fm10k_fifo_unused(&mbx->tx);
690
691	return (mbx->state == FM10K_STATE_OPEN) && (fifo_unused >= len);
692}
693
694/**
695 *  fm10k_mbx_tx_complete - Indicates that the Tx FIFO has been emptied
696 *  @mbx: pointer to mailbox
697 *
698 *  This function returns true if the Tx FIFO is empty.
699 **/
700static bool fm10k_mbx_tx_complete(struct fm10k_mbx_info *mbx)
701{
702	return fm10k_fifo_empty(&mbx->tx);
703}
704
705/**
706 *  fm10k_mbx_deqeueue_rx - Dequeues the message from the head in the Rx FIFO
707 *  @hw: pointer to hardware structure
708 *  @mbx: pointer to mailbox
709 *
710 *  This function dequeues messages and hands them off to the tlv parser.
711 *  It will return the number of messages processed when called.
712 **/
713static u16 fm10k_mbx_dequeue_rx(struct fm10k_hw *hw,
714				struct fm10k_mbx_info *mbx)
715{
716	struct fm10k_mbx_fifo *fifo = &mbx->rx;
717	s32 err;
718	u16 cnt;
719
720	/* parse Rx messages out of the Rx FIFO to empty it */
721	for (cnt = 0; !fm10k_fifo_empty(fifo); cnt++) {
722		err = fm10k_tlv_msg_parse(hw, fifo->buffer + fifo->head,
723					  mbx, mbx->msg_data);
724		if (err < 0)
725			mbx->rx_parse_err++;
726
727		fm10k_fifo_head_drop(fifo);
728	}
729
730	/* shift remaining bytes back to start of FIFO */
731	memmove(fifo->buffer, fifo->buffer + fifo->tail, mbx->pushed << 2);
732
733	/* shift head and tail based on the memory we moved */
734	fifo->tail -= fifo->head;
735	fifo->head = 0;
736
737	return cnt;
738}
739
740/**
741 *  fm10k_mbx_enqueue_tx - Enqueues the message to the tail of the Tx FIFO
742 *  @hw: pointer to hardware structure
743 *  @mbx: pointer to mailbox
744 *  @msg: message array to read
745 *
746 *  This function enqueues a message up to the size specified by the length
747 *  contained in the first DWORD of the message and will place at the tail
748 *  of the FIFO.  It will return 0 on success, or a negative value on error.
749 **/
750static s32 fm10k_mbx_enqueue_tx(struct fm10k_hw *hw,
751				struct fm10k_mbx_info *mbx, const u32 *msg)
752{
753	u32 countdown = mbx->timeout;
754	s32 err;
755
756	switch (mbx->state) {
757	case FM10K_STATE_CLOSED:
758	case FM10K_STATE_DISCONNECT:
759		return FM10K_MBX_ERR_NO_MBX;
760	default:
761		break;
762	}
763
764	/* enqueue the message on the Tx FIFO */
765	err = fm10k_fifo_enqueue(&mbx->tx, msg);
766
767	/* if it failed give the FIFO a chance to drain */
768	while (err && countdown) {
769		countdown--;
770		udelay(mbx->udelay);
771		mbx->ops.process(hw, mbx);
772		err = fm10k_fifo_enqueue(&mbx->tx, msg);
773	}
774
775	/* if we failed treat the error */
776	if (err) {
777		mbx->timeout = 0;
778		mbx->tx_busy++;
779	}
780
781	/* begin processing message, ignore errors as this is just meant
782	 * to start the mailbox flow so we are not concerned if there
783	 * is a bad error, or the mailbox is already busy with a request
784	 */
785	if (!mbx->tail_len)
786		mbx->ops.process(hw, mbx);
787
788	return 0;
789}
790
791/**
792 *  fm10k_mbx_read - Copies the mbmem to local message buffer
793 *  @hw: pointer to hardware structure
794 *  @mbx: pointer to mailbox
795 *
796 *  This function copies the message from the mbmem to the message array
797 **/
798static s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
799{
800	/* only allow one reader in here at a time */
801	if (mbx->mbx_hdr)
802		return FM10K_MBX_ERR_BUSY;
803
804	/* read to capture initial interrupt bits */
805	if (fm10k_read_reg(hw, mbx->mbx_reg) & FM10K_MBX_REQ_INTERRUPT)
806		mbx->mbx_lock = FM10K_MBX_ACK;
807
808	/* write back interrupt bits to clear */
809	fm10k_write_reg(hw, mbx->mbx_reg,
810			FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT);
811
812	/* read remote header */
813	mbx->mbx_hdr = fm10k_read_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len);
814
815	return 0;
816}
817
818/**
819 *  fm10k_mbx_write - Copies the local message buffer to mbmem
820 *  @hw: pointer to hardware structure
821 *  @mbx: pointer to mailbox
822 *
823 *  This function copies the message from the the message array to mbmem
824 **/
825static void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
826{
827	u32 mbmem = mbx->mbmem_reg;
828
829	/* write new msg header to notify recipient of change */
830	fm10k_write_reg(hw, mbmem, mbx->mbx_hdr);
831
832	/* write mailbox to send interrupt */
833	if (mbx->mbx_lock)
834		fm10k_write_reg(hw, mbx->mbx_reg, mbx->mbx_lock);
835
836	/* we no longer are using the header so free it */
837	mbx->mbx_hdr = 0;
838	mbx->mbx_lock = 0;
839}
840
841/**
842 *  fm10k_mbx_create_connect_hdr - Generate a connect mailbox header
843 *  @mbx: pointer to mailbox
844 *
845 *  This function returns a connection mailbox header
846 **/
847static void fm10k_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx)
848{
849	mbx->mbx_lock |= FM10K_MBX_REQ;
850
851	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_CONNECT, TYPE) |
852		       FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD) |
853		       FM10K_MSG_HDR_FIELD_SET(mbx->rx.size - 1, CONNECT_SIZE);
854}
855
856/**
857 *  fm10k_mbx_create_data_hdr - Generate a data mailbox header
858 *  @mbx: pointer to mailbox
859 *
860 *  This function returns a data mailbox header
861 **/
862static void fm10k_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
863{
864	u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DATA, TYPE) |
865		  FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
866		  FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
867	struct fm10k_mbx_fifo *fifo = &mbx->tx;
868	u16 crc;
869
870	if (mbx->tail_len)
871		mbx->mbx_lock |= FM10K_MBX_REQ;
872
873	/* generate CRC for data in flight and header */
874	crc = fm10k_fifo_crc(fifo, fm10k_fifo_head_offset(fifo, mbx->pulled),
875			     mbx->tail_len, mbx->local);
876	crc = fm10k_crc_16b(&hdr, crc, 1);
877
878	/* load header to memory to be written */
879	mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
880}
881
882/**
883 *  fm10k_mbx_create_disconnect_hdr - Generate a disconnect mailbox header
884 *  @mbx: pointer to mailbox
885 *
886 *  This function returns a disconnect mailbox header
887 **/
888static void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx)
889{
890	u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
891		  FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
892		  FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
893	u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
894
895	mbx->mbx_lock |= FM10K_MBX_ACK;
896
897	/* load header to memory to be written */
898	mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
899}
900
901/**
902 *  fm10k_mbx_create_fake_disconnect_hdr - Generate a false disconnect mailbox header
903 *  @mbx: pointer to mailbox
904 *
905 *  This function creates a fake disconnect header for loading into remote
906 *  mailbox header. The primary purpose is to prevent errors on immediate
907 *  start up after mbx->connect.
908 **/
909static void fm10k_mbx_create_fake_disconnect_hdr(struct fm10k_mbx_info *mbx)
910{
911	u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
912		  FM10K_MSG_HDR_FIELD_SET(mbx->head, TAIL) |
913		  FM10K_MSG_HDR_FIELD_SET(mbx->tail, HEAD);
914	u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
915
916	mbx->mbx_lock |= FM10K_MBX_ACK;
917
918	/* load header to memory to be written */
919	mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
920}
921
922/**
923 *  fm10k_mbx_create_error_msg - Generate a error message
924 *  @mbx: pointer to mailbox
925 *  @err: local error encountered
926 *
927 *  This function will interpret the error provided by err, and based on
928 *  that it may shift the message by 1 DWORD and then place an error header
929 *  at the start of the message.
930 **/
931static void fm10k_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
932{
933	/* only generate an error message for these types */
934	switch (err) {
935	case FM10K_MBX_ERR_TAIL:
936	case FM10K_MBX_ERR_HEAD:
937	case FM10K_MBX_ERR_TYPE:
938	case FM10K_MBX_ERR_SIZE:
939	case FM10K_MBX_ERR_RSVD0:
940	case FM10K_MBX_ERR_CRC:
941		break;
942	default:
943		return;
944	}
945
946	mbx->mbx_lock |= FM10K_MBX_REQ;
947
948	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_ERROR, TYPE) |
949		       FM10K_MSG_HDR_FIELD_SET(err, ERR_NO) |
950		       FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
951}
952
953/**
954 *  fm10k_mbx_validate_msg_hdr - Validate common fields in the message header
955 *  @mbx: pointer to mailbox
956 *  @msg: message array to read
957 *
958 *  This function will parse up the fields in the mailbox header and return
959 *  an error if the header contains any of a number of invalid configurations
960 *  including unrecognized type, invalid route, or a malformed message.
961 **/
962static s32 fm10k_mbx_validate_msg_hdr(struct fm10k_mbx_info *mbx)
963{
964	u16 type, rsvd0, head, tail, size;
965	const u32 *hdr = &mbx->mbx_hdr;
966
967	type = FM10K_MSG_HDR_FIELD_GET(*hdr, TYPE);
968	rsvd0 = FM10K_MSG_HDR_FIELD_GET(*hdr, RSVD0);
969	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
970	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
971	size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
972
973	if (rsvd0)
974		return FM10K_MBX_ERR_RSVD0;
975
976	switch (type) {
977	case FM10K_MSG_DISCONNECT:
978		/* validate that all data has been received */
979		if (tail != mbx->head)
980			return FM10K_MBX_ERR_TAIL;
981
982		/* fall through */
983	case FM10K_MSG_DATA:
984		/* validate that head is moving correctly */
985		if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
986			return FM10K_MBX_ERR_HEAD;
987		if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
988			return FM10K_MBX_ERR_HEAD;
989
990		/* validate that tail is moving correctly */
991		if (!tail || (tail == FM10K_MSG_HDR_MASK(TAIL)))
992			return FM10K_MBX_ERR_TAIL;
993		if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
994			break;
995
996		return FM10K_MBX_ERR_TAIL;
997	case FM10K_MSG_CONNECT:
998		/* validate size is in range and is power of 2 mask */
999		if ((size < FM10K_VFMBX_MSG_MTU) || (size & (size + 1)))
1000			return FM10K_MBX_ERR_SIZE;
1001
1002		/* fall through */
1003	case FM10K_MSG_ERROR:
1004		if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
1005			return FM10K_MBX_ERR_HEAD;
1006		/* neither create nor error include a tail offset */
1007		if (tail)
1008			return FM10K_MBX_ERR_TAIL;
1009
1010		break;
1011	default:
1012		return FM10K_MBX_ERR_TYPE;
1013	}
1014
1015	return 0;
1016}
1017
1018/**
1019 *  fm10k_mbx_create_reply - Generate reply based on state and remote head
1020 *  @mbx: pointer to mailbox
1021 *  @head: acknowledgement number
1022 *
1023 *  This function will generate an outgoing message based on the current
1024 *  mailbox state and the remote fifo head.  It will return the length
1025 *  of the outgoing message excluding header on success, and a negative value
1026 *  on error.
1027 **/
1028static s32 fm10k_mbx_create_reply(struct fm10k_hw *hw,
1029				  struct fm10k_mbx_info *mbx, u16 head)
1030{
1031	switch (mbx->state) {
1032	case FM10K_STATE_OPEN:
1033	case FM10K_STATE_DISCONNECT:
1034		/* update our checksum for the outgoing data */
1035		fm10k_mbx_update_local_crc(mbx, head);
1036
1037		/* as long as other end recognizes us keep sending data */
1038		fm10k_mbx_pull_head(hw, mbx, head);
1039
1040		/* generate new header based on data */
1041		if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN))
1042			fm10k_mbx_create_data_hdr(mbx);
1043		else
1044			fm10k_mbx_create_disconnect_hdr(mbx);
1045		break;
1046	case FM10K_STATE_CONNECT:
1047		/* send disconnect even if we aren't connected */
1048		fm10k_mbx_create_connect_hdr(mbx);
1049		break;
1050	case FM10K_STATE_CLOSED:
1051		/* generate new header based on data */
1052		fm10k_mbx_create_disconnect_hdr(mbx);
1053	default:
1054		break;
1055	}
1056
1057	return 0;
1058}
1059
1060/**
1061 *  fm10k_mbx_reset_work- Reset internal pointers for any pending work
1062 *  @mbx: pointer to mailbox
1063 *
1064 *  This function will reset all internal pointers so any work in progress
1065 *  is dropped.  This call should occur every time we transition from the
1066 *  open state to the connect state.
1067 **/
1068static void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx)
1069{
1070	u16 len, head, ack;
1071
1072	/* reset our outgoing max size back to Rx limits */
1073	mbx->max_size = mbx->rx.size - 1;
1074
1075	/* update mbx->pulled to account for tail_len and ack */
1076	head = FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, HEAD);
1077	ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
1078	mbx->pulled += mbx->tail_len - ack;
1079
1080	/* now drop any messages which have started or finished transmitting */
1081	while (fm10k_fifo_head_len(&mbx->tx) && mbx->pulled) {
1082		len = fm10k_fifo_head_drop(&mbx->tx);
1083		mbx->tx_dropped++;
1084		if (mbx->pulled >= len)
1085			mbx->pulled -= len;
1086		else
1087			mbx->pulled = 0;
1088	}
1089
1090	/* just do a quick resysnc to start of message */
1091	mbx->pushed = 0;
1092	mbx->pulled = 0;
1093	mbx->tail_len = 0;
1094	mbx->head_len = 0;
1095	mbx->rx.tail = 0;
1096	mbx->rx.head = 0;
1097}
1098
1099/**
1100 *  fm10k_mbx_update_max_size - Update the max_size and drop any large messages
1101 *  @mbx: pointer to mailbox
1102 *  @size: new value for max_size
1103 *
1104 *  This function updates the max_size value and drops any outgoing messages
1105 *  at the head of the Tx FIFO if they are larger than max_size. It does not
1106 *  drop all messages, as this is too difficult to parse and remove them from
1107 *  the FIFO. Instead, rely on the checking to ensure that messages larger
1108 *  than max_size aren't pushed into the memory buffer.
1109 **/
1110static void fm10k_mbx_update_max_size(struct fm10k_mbx_info *mbx, u16 size)
1111{
1112	u16 len;
1113
1114	mbx->max_size = size;
1115
1116	/* flush any oversized messages from the queue */
1117	for (len = fm10k_fifo_head_len(&mbx->tx);
1118	     len > size;
1119	     len = fm10k_fifo_head_len(&mbx->tx)) {
1120		fm10k_fifo_head_drop(&mbx->tx);
1121		mbx->tx_dropped++;
1122	}
1123}
1124
1125/**
1126 *  fm10k_mbx_connect_reset - Reset following request for reset
1127 *  @mbx: pointer to mailbox
1128 *
1129 *  This function resets the mailbox to either a disconnected state
1130 *  or a connect state depending on the current mailbox state
1131 **/
1132static void fm10k_mbx_connect_reset(struct fm10k_mbx_info *mbx)
1133{
1134	/* just do a quick resysnc to start of frame */
1135	fm10k_mbx_reset_work(mbx);
1136
1137	/* reset CRC seeds */
1138	mbx->local = FM10K_MBX_CRC_SEED;
1139	mbx->remote = FM10K_MBX_CRC_SEED;
1140
1141	/* we cannot exit connect until the size is good */
1142	if (mbx->state == FM10K_STATE_OPEN)
1143		mbx->state = FM10K_STATE_CONNECT;
1144	else
1145		mbx->state = FM10K_STATE_CLOSED;
1146}
1147
1148/**
1149 *  fm10k_mbx_process_connect - Process connect header
1150 *  @mbx: pointer to mailbox
1151 *  @msg: message array to process
1152 *
1153 *  This function will read an incoming connect header and reply with the
1154 *  appropriate message.  It will return a value indicating the number of
1155 *  data DWORDs on success, or will return a negative value on failure.
1156 **/
1157static s32 fm10k_mbx_process_connect(struct fm10k_hw *hw,
1158				     struct fm10k_mbx_info *mbx)
1159{
1160	const enum fm10k_mbx_state state = mbx->state;
1161	const u32 *hdr = &mbx->mbx_hdr;
1162	u16 size, head;
1163
1164	/* we will need to pull all of the fields for verification */
1165	size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
1166	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1167
1168	switch (state) {
1169	case FM10K_STATE_DISCONNECT:
1170	case FM10K_STATE_OPEN:
1171		/* reset any in-progress work */
1172		fm10k_mbx_connect_reset(mbx);
1173		break;
1174	case FM10K_STATE_CONNECT:
1175		/* we cannot exit connect until the size is good */
1176		if (size > mbx->rx.size) {
1177			mbx->max_size = mbx->rx.size - 1;
1178		} else {
1179			/* record the remote system requesting connection */
1180			mbx->state = FM10K_STATE_OPEN;
1181
1182			fm10k_mbx_update_max_size(mbx, size);
1183		}
1184		break;
1185	default:
1186		break;
1187	}
1188
1189	/* align our tail index to remote head index */
1190	mbx->tail = head;
1191
1192	return fm10k_mbx_create_reply(hw, mbx, head);
1193}
1194
1195/**
1196 *  fm10k_mbx_process_data - Process data header
1197 *  @mbx: pointer to mailbox
1198 *
1199 *  This function will read an incoming data header and reply with the
1200 *  appropriate message.  It will return a value indicating the number of
1201 *  data DWORDs on success, or will return a negative value on failure.
1202 **/
1203static s32 fm10k_mbx_process_data(struct fm10k_hw *hw,
1204				  struct fm10k_mbx_info *mbx)
1205{
1206	const u32 *hdr = &mbx->mbx_hdr;
1207	u16 head, tail;
1208	s32 err;
1209
1210	/* we will need to pull all of the fields for verification */
1211	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1212	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
1213
1214	/* if we are in connect just update our data and go */
1215	if (mbx->state == FM10K_STATE_CONNECT) {
1216		mbx->tail = head;
1217		mbx->state = FM10K_STATE_OPEN;
1218	}
1219
1220	/* abort on message size errors */
1221	err = fm10k_mbx_push_tail(hw, mbx, tail);
1222	if (err < 0)
1223		return err;
1224
1225	/* verify the checksum on the incoming data */
1226	err = fm10k_mbx_verify_remote_crc(mbx);
1227	if (err)
1228		return err;
1229
1230	/* process messages if we have received any */
1231	fm10k_mbx_dequeue_rx(hw, mbx);
1232
1233	return fm10k_mbx_create_reply(hw, mbx, head);
1234}
1235
1236/**
1237 *  fm10k_mbx_process_disconnect - Process disconnect header
1238 *  @mbx: pointer to mailbox
1239 *
1240 *  This function will read an incoming disconnect header and reply with the
1241 *  appropriate message.  It will return a value indicating the number of
1242 *  data DWORDs on success, or will return a negative value on failure.
1243 **/
1244static s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw,
1245					struct fm10k_mbx_info *mbx)
1246{
1247	const enum fm10k_mbx_state state = mbx->state;
1248	const u32 *hdr = &mbx->mbx_hdr;
1249	u16 head;
1250	s32 err;
1251
1252	/* we will need to pull the header field for verification */
1253	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1254
1255	/* We should not be receiving disconnect if Rx is incomplete */
1256	if (mbx->pushed)
1257		return FM10K_MBX_ERR_TAIL;
1258
1259	/* we have already verified mbx->head == tail so we know this is 0 */
1260	mbx->head_len = 0;
1261
1262	/* verify the checksum on the incoming header is correct */
1263	err = fm10k_mbx_verify_remote_crc(mbx);
1264	if (err)
1265		return err;
1266
1267	switch (state) {
1268	case FM10K_STATE_DISCONNECT:
1269	case FM10K_STATE_OPEN:
1270		/* state doesn't change if we still have work to do */
1271		if (!fm10k_mbx_tx_complete(mbx))
1272			break;
1273
1274		/* verify the head indicates we completed all transmits */
1275		if (head != mbx->tail)
1276			return FM10K_MBX_ERR_HEAD;
1277
1278		/* reset any in-progress work */
1279		fm10k_mbx_connect_reset(mbx);
1280		break;
1281	default:
1282		break;
1283	}
1284
1285	return fm10k_mbx_create_reply(hw, mbx, head);
1286}
1287
1288/**
1289 *  fm10k_mbx_process_error - Process error header
1290 *  @mbx: pointer to mailbox
1291 *
1292 *  This function will read an incoming error header and reply with the
1293 *  appropriate message.  It will return a value indicating the number of
1294 *  data DWORDs on success, or will return a negative value on failure.
1295 **/
1296static s32 fm10k_mbx_process_error(struct fm10k_hw *hw,
1297				   struct fm10k_mbx_info *mbx)
1298{
1299	const u32 *hdr = &mbx->mbx_hdr;
1300	u16 head;
1301
1302	/* we will need to pull all of the fields for verification */
1303	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1304
1305	switch (mbx->state) {
1306	case FM10K_STATE_OPEN:
1307	case FM10K_STATE_DISCONNECT:
1308		/* flush any uncompleted work */
1309		fm10k_mbx_reset_work(mbx);
1310
1311		/* reset CRC seeds */
1312		mbx->local = FM10K_MBX_CRC_SEED;
1313		mbx->remote = FM10K_MBX_CRC_SEED;
1314
1315		/* reset tail index and size to prepare for reconnect */
1316		mbx->tail = head;
1317
1318		/* if open then reset max_size and go back to connect */
1319		if (mbx->state == FM10K_STATE_OPEN) {
1320			mbx->state = FM10K_STATE_CONNECT;
1321			break;
1322		}
1323
1324		/* send a connect message to get data flowing again */
1325		fm10k_mbx_create_connect_hdr(mbx);
1326		return 0;
1327	default:
1328		break;
1329	}
1330
1331	return fm10k_mbx_create_reply(hw, mbx, mbx->tail);
1332}
1333
1334/**
1335 *  fm10k_mbx_process - Process mailbox interrupt
1336 *  @hw: pointer to hardware structure
1337 *  @mbx: pointer to mailbox
1338 *
1339 *  This function will process incoming mailbox events and generate mailbox
1340 *  replies.  It will return a value indicating the number of DWORDs
1341 *  transmitted excluding header on success or a negative value on error.
1342 **/
1343static s32 fm10k_mbx_process(struct fm10k_hw *hw,
1344			     struct fm10k_mbx_info *mbx)
1345{
1346	s32 err;
1347
1348	/* we do not read mailbox if closed */
1349	if (mbx->state == FM10K_STATE_CLOSED)
1350		return 0;
1351
1352	/* copy data from mailbox */
1353	err = fm10k_mbx_read(hw, mbx);
1354	if (err)
1355		return err;
1356
1357	/* validate type, source, and destination */
1358	err = fm10k_mbx_validate_msg_hdr(mbx);
1359	if (err < 0)
1360		goto msg_err;
1361
1362	switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, TYPE)) {
1363	case FM10K_MSG_CONNECT:
1364		err = fm10k_mbx_process_connect(hw, mbx);
1365		break;
1366	case FM10K_MSG_DATA:
1367		err = fm10k_mbx_process_data(hw, mbx);
1368		break;
1369	case FM10K_MSG_DISCONNECT:
1370		err = fm10k_mbx_process_disconnect(hw, mbx);
1371		break;
1372	case FM10K_MSG_ERROR:
1373		err = fm10k_mbx_process_error(hw, mbx);
1374		break;
1375	default:
1376		err = FM10K_MBX_ERR_TYPE;
1377		break;
1378	}
1379
1380msg_err:
1381	/* notify partner of errors on our end */
1382	if (err < 0)
1383		fm10k_mbx_create_error_msg(mbx, err);
1384
1385	/* copy data from mailbox */
1386	fm10k_mbx_write(hw, mbx);
1387
1388	return err;
1389}
1390
1391/**
1392 *  fm10k_mbx_disconnect - Shutdown mailbox connection
1393 *  @hw: pointer to hardware structure
1394 *  @mbx: pointer to mailbox
1395 *
1396 *  This function will shut down the mailbox.  It places the mailbox first
1397 *  in the disconnect state, it then allows up to a predefined timeout for
1398 *  the mailbox to transition to close on its own.  If this does not occur
1399 *  then the mailbox will be forced into the closed state.
1400 *
1401 *  Any mailbox transactions not completed before calling this function
1402 *  are not guaranteed to complete and may be dropped.
1403 **/
1404static void fm10k_mbx_disconnect(struct fm10k_hw *hw,
1405				 struct fm10k_mbx_info *mbx)
1406{
1407	int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
1408
1409	/* Place mbx in ready to disconnect state */
1410	mbx->state = FM10K_STATE_DISCONNECT;
1411
1412	/* trigger interrupt to start shutdown process */
1413	fm10k_write_reg(hw, mbx->mbx_reg, FM10K_MBX_REQ |
1414					  FM10K_MBX_INTERRUPT_DISABLE);
1415	do {
1416		udelay(FM10K_MBX_POLL_DELAY);
1417		mbx->ops.process(hw, mbx);
1418		timeout -= FM10K_MBX_POLL_DELAY;
1419	} while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
1420
1421	/* in case we didn't close, just force the mailbox into shutdown and
1422	 * drop all left over messages in the FIFO.
1423	 */
1424	fm10k_mbx_connect_reset(mbx);
1425	fm10k_fifo_drop_all(&mbx->tx);
1426
1427	fm10k_write_reg(hw, mbx->mbmem_reg, 0);
1428}
1429
1430/**
1431 *  fm10k_mbx_connect - Start mailbox connection
1432 *  @hw: pointer to hardware structure
1433 *  @mbx: pointer to mailbox
1434 *
1435 *  This function will initiate a mailbox connection.  It will populate the
1436 *  mailbox with a broadcast connect message and then initialize the lock.
1437 *  This is safe since the connect message is a single DWORD so the mailbox
1438 *  transaction is guaranteed to be atomic.
1439 *
1440 *  This function will return an error if the mailbox has not been initiated
1441 *  or is currently in use.
1442 **/
1443static s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
1444{
1445	/* we cannot connect an uninitialized mailbox */
1446	if (!mbx->rx.buffer)
1447		return FM10K_MBX_ERR_NO_SPACE;
1448
1449	/* we cannot connect an already connected mailbox */
1450	if (mbx->state != FM10K_STATE_CLOSED)
1451		return FM10K_MBX_ERR_BUSY;
1452
1453	/* mailbox timeout can now become active */
1454	mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
1455
1456	/* Place mbx in ready to connect state */
1457	mbx->state = FM10K_STATE_CONNECT;
1458
1459	fm10k_mbx_reset_work(mbx);
1460
1461	/* initialize header of remote mailbox */
1462	fm10k_mbx_create_fake_disconnect_hdr(mbx);
1463	fm10k_write_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr);
1464
1465	/* enable interrupt and notify other party of new message */
1466	mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
1467			FM10K_MBX_INTERRUPT_ENABLE;
1468
1469	/* generate and load connect header into mailbox */
1470	fm10k_mbx_create_connect_hdr(mbx);
1471	fm10k_mbx_write(hw, mbx);
1472
1473	return 0;
1474}
1475
1476/**
1477 *  fm10k_mbx_validate_handlers - Validate layout of message parsing data
1478 *  @msg_data: handlers for mailbox events
1479 *
1480 *  This function validates the layout of the message parsing data.  This
1481 *  should be mostly static, but it is important to catch any errors that
1482 *  are made when constructing the parsers.
1483 **/
1484static s32 fm10k_mbx_validate_handlers(const struct fm10k_msg_data *msg_data)
1485{
1486	const struct fm10k_tlv_attr *attr;
1487	unsigned int id;
1488
1489	/* Allow NULL mailboxes that transmit but don't receive */
1490	if (!msg_data)
1491		return 0;
1492
1493	while (msg_data->id != FM10K_TLV_ERROR) {
1494		/* all messages should have a function handler */
1495		if (!msg_data->func)
1496			return FM10K_ERR_PARAM;
1497
1498		/* parser is optional */
1499		attr = msg_data->attr;
1500		if (attr) {
1501			while (attr->id != FM10K_TLV_ERROR) {
1502				id = attr->id;
1503				attr++;
1504				/* ID should always be increasing */
1505				if (id >= attr->id)
1506					return FM10K_ERR_PARAM;
1507				/* ID should fit in results array */
1508				if (id >= FM10K_TLV_RESULTS_MAX)
1509					return FM10K_ERR_PARAM;
1510			}
1511
1512			/* verify terminator is in the list */
1513			if (attr->id != FM10K_TLV_ERROR)
1514				return FM10K_ERR_PARAM;
1515		}
1516
1517		id = msg_data->id;
1518		msg_data++;
1519		/* ID should always be increasing */
1520		if (id >= msg_data->id)
1521			return FM10K_ERR_PARAM;
1522	}
1523
1524	/* verify terminator is in the list */
1525	if ((msg_data->id != FM10K_TLV_ERROR) || !msg_data->func)
1526		return FM10K_ERR_PARAM;
1527
1528	return 0;
1529}
1530
1531/**
1532 *  fm10k_mbx_register_handlers - Register a set of handler ops for mailbox
1533 *  @mbx: pointer to mailbox
1534 *  @msg_data: handlers for mailbox events
1535 *
1536 *  This function associates a set of message handling ops with a mailbox.
1537 **/
1538static s32 fm10k_mbx_register_handlers(struct fm10k_mbx_info *mbx,
1539				       const struct fm10k_msg_data *msg_data)
1540{
1541	/* validate layout of handlers before assigning them */
1542	if (fm10k_mbx_validate_handlers(msg_data))
1543		return FM10K_ERR_PARAM;
1544
1545	/* initialize the message handlers */
1546	mbx->msg_data = msg_data;
1547
1548	return 0;
1549}
1550
1551/**
1552 *  fm10k_pfvf_mbx_init - Initialize mailbox memory for PF/VF mailbox
1553 *  @hw: pointer to hardware structure
1554 *  @mbx: pointer to mailbox
1555 *  @msg_data: handlers for mailbox events
1556 *  @id: ID reference for PF as it supports up to 64 PF/VF mailboxes
1557 *
1558 *  This function initializes the mailbox for use.  It will split the
1559 *  buffer provided an use that th populate both the Tx and Rx FIFO by
1560 *  evenly splitting it.  In order to allow for easy masking of head/tail
1561 *  the value reported in size must be a power of 2 and is reported in
1562 *  DWORDs, not bytes.  Any invalid values will cause the mailbox to return
1563 *  error.
1564 **/
1565s32 fm10k_pfvf_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
1566			const struct fm10k_msg_data *msg_data, u8 id)
1567{
1568	/* initialize registers */
1569	switch (hw->mac.type) {
1570	case fm10k_mac_vf:
1571		mbx->mbx_reg = FM10K_VFMBX;
1572		mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR);
1573		break;
1574	case fm10k_mac_pf:
1575		/* there are only 64 VF <-> PF mailboxes */
1576		if (id < 64) {
1577			mbx->mbx_reg = FM10K_MBX(id);
1578			mbx->mbmem_reg = FM10K_MBMEM_VF(id, 0);
1579			break;
1580		}
1581		/* fallthough */
1582	default:
1583		return FM10K_MBX_ERR_NO_MBX;
1584	}
1585
1586	/* start out in closed state */
1587	mbx->state = FM10K_STATE_CLOSED;
1588
1589	/* validate layout of handlers before assigning them */
1590	if (fm10k_mbx_validate_handlers(msg_data))
1591		return FM10K_ERR_PARAM;
1592
1593	/* initialize the message handlers */
1594	mbx->msg_data = msg_data;
1595
1596	/* start mailbox as timed out and let the reset_hw call
1597	 * set the timeout value to begin communications
1598	 */
1599	mbx->timeout = 0;
1600	mbx->udelay = FM10K_MBX_INIT_DELAY;
1601
1602	/* initialize tail and head */
1603	mbx->tail = 1;
1604	mbx->head = 1;
1605
1606	/* initialize CRC seeds */
1607	mbx->local = FM10K_MBX_CRC_SEED;
1608	mbx->remote = FM10K_MBX_CRC_SEED;
1609
1610	/* Split buffer for use by Tx/Rx FIFOs */
1611	mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
1612	mbx->mbmem_len = FM10K_VFMBMEM_VF_XOR;
1613
1614	/* initialize the FIFOs, sizes are in 4 byte increments */
1615	fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
1616	fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
1617			FM10K_MBX_RX_BUFFER_SIZE);
1618
1619	/* initialize function pointers */
1620	mbx->ops.connect = fm10k_mbx_connect;
1621	mbx->ops.disconnect = fm10k_mbx_disconnect;
1622	mbx->ops.rx_ready = fm10k_mbx_rx_ready;
1623	mbx->ops.tx_ready = fm10k_mbx_tx_ready;
1624	mbx->ops.tx_complete = fm10k_mbx_tx_complete;
1625	mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
1626	mbx->ops.process = fm10k_mbx_process;
1627	mbx->ops.register_handlers = fm10k_mbx_register_handlers;
1628
1629	return 0;
1630}
1631
1632/**
1633 *  fm10k_sm_mbx_create_data_hdr - Generate a mailbox header for local FIFO
1634 *  @mbx: pointer to mailbox
1635 *
1636 *  This function returns a connection mailbox header
1637 **/
1638static void fm10k_sm_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
1639{
1640	if (mbx->tail_len)
1641		mbx->mbx_lock |= FM10K_MBX_REQ;
1642
1643	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
1644		       FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
1645		       FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD);
1646}
1647
1648/**
1649 *  fm10k_sm_mbx_create_connect_hdr - Generate a mailbox header for local FIFO
1650 *  @mbx: pointer to mailbox
1651 *  @err: error flags to report if any
1652 *
1653 *  This function returns a connection mailbox header
1654 **/
1655static void fm10k_sm_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx, u8 err)
1656{
1657	if (mbx->local)
1658		mbx->mbx_lock |= FM10K_MBX_REQ;
1659
1660	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
1661		       FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
1662		       FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD) |
1663		       FM10K_MSG_HDR_FIELD_SET(err, SM_ERR);
1664}
1665
1666/**
1667 *  fm10k_sm_mbx_connect_reset - Reset following request for reset
1668 *  @mbx: pointer to mailbox
1669 *
1670 *  This function resets the mailbox to a just connected state
1671 **/
1672static void fm10k_sm_mbx_connect_reset(struct fm10k_mbx_info *mbx)
1673{
1674	/* flush any uncompleted work */
1675	fm10k_mbx_reset_work(mbx);
1676
1677	/* set local version to max and remote version to 0 */
1678	mbx->local = FM10K_SM_MBX_VERSION;
1679	mbx->remote = 0;
1680
1681	/* initialize tail and head */
1682	mbx->tail = 1;
1683	mbx->head = 1;
1684
1685	/* reset state back to connect */
1686	mbx->state = FM10K_STATE_CONNECT;
1687}
1688
1689/**
1690 *  fm10k_sm_mbx_connect - Start switch manager mailbox connection
1691 *  @hw: pointer to hardware structure
1692 *  @mbx: pointer to mailbox
1693 *
1694 *  This function will initiate a mailbox connection with the switch
1695 *  manager.  To do this it will first disconnect the mailbox, and then
1696 *  reconnect it in order to complete a reset of the mailbox.
1697 *
1698 *  This function will return an error if the mailbox has not been initiated
1699 *  or is currently in use.
1700 **/
1701static s32 fm10k_sm_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
1702{
1703	/* we cannot connect an uninitialized mailbox */
1704	if (!mbx->rx.buffer)
1705		return FM10K_MBX_ERR_NO_SPACE;
1706
1707	/* we cannot connect an already connected mailbox */
1708	if (mbx->state != FM10K_STATE_CLOSED)
1709		return FM10K_MBX_ERR_BUSY;
1710
1711	/* mailbox timeout can now become active */
1712	mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
1713
1714	/* Place mbx in ready to connect state */
1715	mbx->state = FM10K_STATE_CONNECT;
1716	mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
1717
1718	/* reset interface back to connect */
1719	fm10k_sm_mbx_connect_reset(mbx);
1720
1721	/* enable interrupt and notify other party of new message */
1722	mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
1723			FM10K_MBX_INTERRUPT_ENABLE;
1724
1725	/* generate and load connect header into mailbox */
1726	fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1727	fm10k_mbx_write(hw, mbx);
1728
1729	/* enable interrupt and notify other party of new message */
1730
1731	return 0;
1732}
1733
1734/**
1735 *  fm10k_sm_mbx_disconnect - Shutdown mailbox connection
1736 *  @hw: pointer to hardware structure
1737 *  @mbx: pointer to mailbox
1738 *
1739 *  This function will shut down the mailbox.  It places the mailbox first
1740 *  in the disconnect state, it then allows up to a predefined timeout for
1741 *  the mailbox to transition to close on its own.  If this does not occur
1742 *  then the mailbox will be forced into the closed state.
1743 *
1744 *  Any mailbox transactions not completed before calling this function
1745 *  are not guaranteed to complete and may be dropped.
1746 **/
1747static void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw,
1748				    struct fm10k_mbx_info *mbx)
1749{
1750	int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
1751
1752	/* Place mbx in ready to disconnect state */
1753	mbx->state = FM10K_STATE_DISCONNECT;
1754
1755	/* trigger interrupt to start shutdown process */
1756	fm10k_write_reg(hw, mbx->mbx_reg, FM10K_MBX_REQ |
1757					  FM10K_MBX_INTERRUPT_DISABLE);
1758	do {
1759		udelay(FM10K_MBX_POLL_DELAY);
1760		mbx->ops.process(hw, mbx);
1761		timeout -= FM10K_MBX_POLL_DELAY;
1762	} while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
1763
1764	/* in case we didn't close just force the mailbox into shutdown */
1765	mbx->state = FM10K_STATE_CLOSED;
1766	mbx->remote = 0;
1767	fm10k_mbx_reset_work(mbx);
1768	fm10k_fifo_drop_all(&mbx->tx);
1769
1770	fm10k_write_reg(hw, mbx->mbmem_reg, 0);
1771}
1772
1773/**
1774 *  fm10k_mbx_validate_fifo_hdr - Validate fields in the remote FIFO header
1775 *  @mbx: pointer to mailbox
1776 *
1777 *  This function will parse up the fields in the mailbox header and return
1778 *  an error if the header contains any of a number of invalid configurations
1779 *  including unrecognized offsets or version numbers.
1780 **/
1781static s32 fm10k_sm_mbx_validate_fifo_hdr(struct fm10k_mbx_info *mbx)
1782{
1783	const u32 *hdr = &mbx->mbx_hdr;
1784	u16 tail, head, ver;
1785
1786	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
1787	ver = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_VER);
1788	head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
1789
1790	switch (ver) {
1791	case 0:
1792		break;
1793	case FM10K_SM_MBX_VERSION:
1794		if (!head || head > FM10K_SM_MBX_FIFO_LEN)
1795			return FM10K_MBX_ERR_HEAD;
1796		if (!tail || tail > FM10K_SM_MBX_FIFO_LEN)
1797			return FM10K_MBX_ERR_TAIL;
1798		if (mbx->tail < head)
1799			head += mbx->mbmem_len - 1;
1800		if (tail < mbx->head)
1801			tail += mbx->mbmem_len - 1;
1802		if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
1803			return FM10K_MBX_ERR_HEAD;
1804		if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
1805			break;
1806		return FM10K_MBX_ERR_TAIL;
1807	default:
1808		return FM10K_MBX_ERR_SRC;
1809	}
1810
1811	return 0;
1812}
1813
1814/**
1815 *  fm10k_sm_mbx_process_error - Process header with error flag set
1816 *  @mbx: pointer to mailbox
1817 *
1818 *  This function is meant to respond to a request where the error flag
1819 *  is set.  As a result we will terminate a connection if one is present
1820 *  and fall back into the reset state with a connection header of version
1821 *  0 (RESET).
1822 **/
1823static void fm10k_sm_mbx_process_error(struct fm10k_mbx_info *mbx)
1824{
1825	const enum fm10k_mbx_state state = mbx->state;
1826
1827	switch (state) {
1828	case FM10K_STATE_DISCONNECT:
1829		/* if there is an error just disconnect */
1830		mbx->remote = 0;
1831		break;
1832	case FM10K_STATE_OPEN:
1833		/* flush any uncompleted work */
1834		fm10k_sm_mbx_connect_reset(mbx);
1835		break;
1836	case FM10K_STATE_CONNECT:
1837		/* try connnecting at lower version */
1838		if (mbx->remote) {
1839			while (mbx->local > 1)
1840				mbx->local--;
1841			mbx->remote = 0;
1842		}
1843		break;
1844	default:
1845		break;
1846	}
1847
1848	fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1849}
1850
1851/**
1852 *  fm10k_sm_mbx_create_error_message - Process an error in FIFO hdr
1853 *  @mbx: pointer to mailbox
1854 *  @err: local error encountered
1855 *
1856 *  This function will interpret the error provided by err, and based on
1857 *  that it may set the error bit in the local message header
1858 **/
1859static void fm10k_sm_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
1860{
1861	/* only generate an error message for these types */
1862	switch (err) {
1863	case FM10K_MBX_ERR_TAIL:
1864	case FM10K_MBX_ERR_HEAD:
1865	case FM10K_MBX_ERR_SRC:
1866	case FM10K_MBX_ERR_SIZE:
1867	case FM10K_MBX_ERR_RSVD0:
1868		break;
1869	default:
1870		return;
1871	}
1872
1873	/* process it as though we received an error, and send error reply */
1874	fm10k_sm_mbx_process_error(mbx);
1875	fm10k_sm_mbx_create_connect_hdr(mbx, 1);
1876}
1877
1878/**
1879 *  fm10k_sm_mbx_receive - Take message from Rx mailbox FIFO and put it in Rx
1880 *  @hw: pointer to hardware structure
1881 *  @mbx: pointer to mailbox
1882 *
1883 *  This function will dequeue one message from the Rx switch manager mailbox
1884 *  FIFO and place it in the Rx mailbox FIFO for processing by software.
1885 **/
1886static s32 fm10k_sm_mbx_receive(struct fm10k_hw *hw,
1887				struct fm10k_mbx_info *mbx,
1888				u16 tail)
1889{
1890	/* reduce length by 1 to convert to a mask */
1891	u16 mbmem_len = mbx->mbmem_len - 1;
1892	s32 err;
1893
1894	/* push tail in front of head */
1895	if (tail < mbx->head)
1896		tail += mbmem_len;
1897
1898	/* copy data to the Rx FIFO */
1899	err = fm10k_mbx_push_tail(hw, mbx, tail);
1900	if (err < 0)
1901		return err;
1902
1903	/* process messages if we have received any */
1904	fm10k_mbx_dequeue_rx(hw, mbx);
1905
1906	/* guarantee head aligns with the end of the last message */
1907	mbx->head = fm10k_mbx_head_sub(mbx, mbx->pushed);
1908	mbx->pushed = 0;
1909
1910	/* clear any extra bits left over since index adds 1 extra bit */
1911	if (mbx->head > mbmem_len)
1912		mbx->head -= mbmem_len;
1913
1914	return err;
1915}
1916
1917/**
1918 *  fm10k_sm_mbx_transmit - Take message from Tx and put it in Tx mailbox FIFO
1919 *  @hw: pointer to hardware structure
1920 *  @mbx: pointer to mailbox
1921 *
1922 *  This function will dequeue one message from the Tx mailbox FIFO and place
1923 *  it in the Tx switch manager mailbox FIFO for processing by hardware.
1924 **/
1925static void fm10k_sm_mbx_transmit(struct fm10k_hw *hw,
1926				  struct fm10k_mbx_info *mbx, u16 head)
1927{
1928	struct fm10k_mbx_fifo *fifo = &mbx->tx;
1929	/* reduce length by 1 to convert to a mask */
1930	u16 mbmem_len = mbx->mbmem_len - 1;
1931	u16 tail_len, len = 0;
1932	u32 *msg;
1933
1934	/* push head behind tail */
1935	if (mbx->tail < head)
1936		head += mbmem_len;
1937
1938	fm10k_mbx_pull_head(hw, mbx, head);
1939
1940	/* determine msg aligned offset for end of buffer */
1941	do {
1942		msg = fifo->buffer + fm10k_fifo_head_offset(fifo, len);
1943		tail_len = len;
1944		len += FM10K_TLV_DWORD_LEN(*msg);
1945	} while ((len <= mbx->tail_len) && (len < mbmem_len));
1946
1947	/* guarantee we stop on a message boundary */
1948	if (mbx->tail_len > tail_len) {
1949		mbx->tail = fm10k_mbx_tail_sub(mbx, mbx->tail_len - tail_len);
1950		mbx->tail_len = tail_len;
1951	}
1952
1953	/* clear any extra bits left over since index adds 1 extra bit */
1954	if (mbx->tail > mbmem_len)
1955		mbx->tail -= mbmem_len;
1956}
1957
1958/**
1959 *  fm10k_sm_mbx_create_reply - Generate reply based on state and remote head
1960 *  @mbx: pointer to mailbox
1961 *  @head: acknowledgement number
1962 *
1963 *  This function will generate an outgoing message based on the current
1964 *  mailbox state and the remote fifo head.  It will return the length
1965 *  of the outgoing message excluding header on success, and a negative value
1966 *  on error.
1967 **/
1968static void fm10k_sm_mbx_create_reply(struct fm10k_hw *hw,
1969				      struct fm10k_mbx_info *mbx, u16 head)
1970{
1971	switch (mbx->state) {
1972	case FM10K_STATE_OPEN:
1973	case FM10K_STATE_DISCONNECT:
1974		/* flush out Tx data */
1975		fm10k_sm_mbx_transmit(hw, mbx, head);
1976
1977		/* generate new header based on data */
1978		if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) {
1979			fm10k_sm_mbx_create_data_hdr(mbx);
1980		} else {
1981			mbx->remote = 0;
1982			fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1983		}
1984		break;
1985	case FM10K_STATE_CONNECT:
1986	case FM10K_STATE_CLOSED:
1987		fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1988		break;
1989	default:
1990		break;
1991	}
1992}
1993
1994/**
1995 *  fm10k_sm_mbx_process_reset - Process header with version == 0 (RESET)
1996 *  @hw: pointer to hardware structure
1997 *  @mbx: pointer to mailbox
1998 *
1999 *  This function is meant to respond to a request where the version data
2000 *  is set to 0.  As such we will either terminate the connection or go
2001 *  into the connect state in order to re-establish the connection.  This
2002 *  function can also be used to respond to an error as the connection
2003 *  resetting would also be a means of dealing with errors.
2004 **/
2005static void fm10k_sm_mbx_process_reset(struct fm10k_hw *hw,
2006				       struct fm10k_mbx_info *mbx)
2007{
2008	const enum fm10k_mbx_state state = mbx->state;
2009
2010	switch (state) {
2011	case FM10K_STATE_DISCONNECT:
2012		/* drop remote connections and disconnect */
2013		mbx->state = FM10K_STATE_CLOSED;
2014		mbx->remote = 0;
2015		mbx->local = 0;
2016		break;
2017	case FM10K_STATE_OPEN:
2018		/* flush any incomplete work */
2019		fm10k_sm_mbx_connect_reset(mbx);
2020		break;
2021	case FM10K_STATE_CONNECT:
2022		/* Update remote value to match local value */
2023		mbx->remote = mbx->local;
2024	default:
2025		break;
2026	}
2027
2028	fm10k_sm_mbx_create_reply(hw, mbx, mbx->tail);
2029}
2030
2031/**
2032 *  fm10k_sm_mbx_process_version_1 - Process header with version == 1
2033 *  @hw: pointer to hardware structure
2034 *  @mbx: pointer to mailbox
2035 *
2036 *  This function is meant to process messages received when the remote
2037 *  mailbox is active.
2038 **/
2039static s32 fm10k_sm_mbx_process_version_1(struct fm10k_hw *hw,
2040					  struct fm10k_mbx_info *mbx)
2041{
2042	const u32 *hdr = &mbx->mbx_hdr;
2043	u16 head, tail;
2044	s32 len;
2045
2046	/* pull all fields needed for verification */
2047	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
2048	head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
2049
2050	/* if we are in connect and wanting version 1 then start up and go */
2051	if (mbx->state == FM10K_STATE_CONNECT) {
2052		if (!mbx->remote)
2053			goto send_reply;
2054		if (mbx->remote != 1)
2055			return FM10K_MBX_ERR_SRC;
2056
2057		mbx->state = FM10K_STATE_OPEN;
2058	}
2059
2060	do {
2061		/* abort on message size errors */
2062		len = fm10k_sm_mbx_receive(hw, mbx, tail);
2063		if (len < 0)
2064			return len;
2065
2066		/* continue until we have flushed the Rx FIFO */
2067	} while (len);
2068
2069send_reply:
2070	fm10k_sm_mbx_create_reply(hw, mbx, head);
2071
2072	return 0;
2073}
2074
2075/**
2076 *  fm10k_sm_mbx_process - Process mailbox switch mailbox interrupt
2077 *  @hw: pointer to hardware structure
2078 *  @mbx: pointer to mailbox
2079 *
2080 *  This function will process incoming mailbox events and generate mailbox
2081 *  replies.  It will return a value indicating the number of DWORDs
2082 *  transmitted excluding header on success or a negative value on error.
2083 **/
2084static s32 fm10k_sm_mbx_process(struct fm10k_hw *hw,
2085				struct fm10k_mbx_info *mbx)
2086{
2087	s32 err;
2088
2089	/* we do not read mailbox if closed */
2090	if (mbx->state == FM10K_STATE_CLOSED)
2091		return 0;
2092
2093	/* retrieve data from switch manager */
2094	err = fm10k_mbx_read(hw, mbx);
2095	if (err)
2096		return err;
2097
2098	err = fm10k_sm_mbx_validate_fifo_hdr(mbx);
2099	if (err < 0)
2100		goto fifo_err;
2101
2102	if (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_ERR)) {
2103		fm10k_sm_mbx_process_error(mbx);
2104		goto fifo_err;
2105	}
2106
2107	switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_VER)) {
2108	case 0:
2109		fm10k_sm_mbx_process_reset(hw, mbx);
2110		break;
2111	case FM10K_SM_MBX_VERSION:
2112		err = fm10k_sm_mbx_process_version_1(hw, mbx);
2113		break;
2114	}
2115
2116fifo_err:
2117	if (err < 0)
2118		fm10k_sm_mbx_create_error_msg(mbx, err);
2119
2120	/* report data to switch manager */
2121	fm10k_mbx_write(hw, mbx);
2122
2123	return err;
2124}
2125
2126/**
2127 *  fm10k_sm_mbx_init - Initialize mailbox memory for PF/SM mailbox
2128 *  @hw: pointer to hardware structure
2129 *  @mbx: pointer to mailbox
2130 *  @msg_data: handlers for mailbox events
2131 *
2132 *  This function for now is used to stub out the PF/SM mailbox
2133 **/
2134s32 fm10k_sm_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
2135		      const struct fm10k_msg_data *msg_data)
2136{
2137	mbx->mbx_reg = FM10K_GMBX;
2138	mbx->mbmem_reg = FM10K_MBMEM_PF(0);
2139	/* start out in closed state */
2140	mbx->state = FM10K_STATE_CLOSED;
2141
2142	/* validate layout of handlers before assigning them */
2143	if (fm10k_mbx_validate_handlers(msg_data))
2144		return FM10K_ERR_PARAM;
2145
2146	/* initialize the message handlers */
2147	mbx->msg_data = msg_data;
2148
2149	/* start mailbox as timed out and let the reset_hw call
2150	 * set the timeout value to begin communications
2151	 */
2152	mbx->timeout = 0;
2153	mbx->udelay = FM10K_MBX_INIT_DELAY;
2154
2155	/* Split buffer for use by Tx/Rx FIFOs */
2156	mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
2157	mbx->mbmem_len = FM10K_MBMEM_PF_XOR;
2158
2159	/* initialize the FIFOs, sizes are in 4 byte increments */
2160	fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
2161	fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
2162			FM10K_MBX_RX_BUFFER_SIZE);
2163
2164	/* initialize function pointers */
2165	mbx->ops.connect = fm10k_sm_mbx_connect;
2166	mbx->ops.disconnect = fm10k_sm_mbx_disconnect;
2167	mbx->ops.rx_ready = fm10k_mbx_rx_ready;
2168	mbx->ops.tx_ready = fm10k_mbx_tx_ready;
2169	mbx->ops.tx_complete = fm10k_mbx_tx_complete;
2170	mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
2171	mbx->ops.process = fm10k_sm_mbx_process;
2172	mbx->ops.register_handlers = fm10k_mbx_register_handlers;
2173
2174	return 0;
2175}
2176