xref: /linux/drivers/net/ethernet/wangxun/libwx/wx_mbx.c (revision 3186a8e55ae3428ec1e06af09075e20885376e4e)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
3 
4 #include <linux/pci.h>
5 #include "wx_type.h"
6 #include "wx_mbx.h"
7 
8 /**
9  *  wx_obtain_mbx_lock_pf - obtain mailbox lock
10  *  @wx: pointer to the HW structure
11  *  @vf: the VF index
12  *
13  *  Return: return 0 on success and -EBUSY on failure
14  **/
15 static int wx_obtain_mbx_lock_pf(struct wx *wx, u16 vf)
16 {
17 	int count = 5;
18 	u32 mailbox;
19 
20 	while (count--) {
21 		/* Take ownership of the buffer */
22 		wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_PFU);
23 
24 		/* reserve mailbox for vf use */
25 		mailbox = rd32(wx, WX_PXMAILBOX(vf));
26 		if (mailbox & WX_PXMAILBOX_PFU)
27 			return 0;
28 		else if (count)
29 			udelay(10);
30 	}
31 	wx_err(wx, "Failed to obtain mailbox lock for PF%d", vf);
32 
33 	return -EBUSY;
34 }
35 
36 static int wx_check_for_bit_pf(struct wx *wx, u32 mask, int index)
37 {
38 	u32 mbvficr = rd32(wx, WX_MBVFICR(index));
39 
40 	if (!(mbvficr & mask))
41 		return -EBUSY;
42 	wr32(wx, WX_MBVFICR(index), mask);
43 
44 	return 0;
45 }
46 
47 /**
48  *  wx_check_for_ack_pf - checks to see if the VF has acked
49  *  @wx: pointer to the HW structure
50  *  @vf: the VF index
51  *
52  *  Return: return 0 if the VF has set the status bit or else -EBUSY
53  **/
54 int wx_check_for_ack_pf(struct wx *wx, u16 vf)
55 {
56 	u32 index = vf / 16, vf_bit = vf % 16;
57 
58 	return wx_check_for_bit_pf(wx,
59 				   FIELD_PREP(WX_MBVFICR_VFACK_MASK,
60 					      BIT(vf_bit)),
61 				   index);
62 }
63 
64 /**
65  *  wx_check_for_msg_pf - checks to see if the VF has sent mail
66  *  @wx: pointer to the HW structure
67  *  @vf: the VF index
68  *
69  *  Return: return 0 if the VF has got req bit or else -EBUSY
70  **/
71 int wx_check_for_msg_pf(struct wx *wx, u16 vf)
72 {
73 	u32 index = vf / 16, vf_bit = vf % 16;
74 
75 	return wx_check_for_bit_pf(wx,
76 				   FIELD_PREP(WX_MBVFICR_VFREQ_MASK,
77 					      BIT(vf_bit)),
78 				   index);
79 }
80 
81 /**
82  *  wx_write_mbx_pf - Places a message in the mailbox
83  *  @wx: pointer to the HW structure
84  *  @msg: The message buffer
85  *  @size: Length of buffer
86  *  @vf: the VF index
87  *
88  *  Return: return 0 on success and -EINVAL/-EBUSY on failure
89  **/
90 int wx_write_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf)
91 {
92 	struct wx_mbx_info *mbx = &wx->mbx;
93 	int ret, i;
94 
95 	/* mbx->size is up to 15 */
96 	if (size > mbx->size) {
97 		wx_err(wx, "Invalid mailbox message size %d", size);
98 		return -EINVAL;
99 	}
100 
101 	/* lock the mailbox to prevent pf/vf race condition */
102 	ret = wx_obtain_mbx_lock_pf(wx, vf);
103 	if (ret)
104 		return ret;
105 
106 	/* flush msg and acks as we are overwriting the message buffer */
107 	wx_check_for_msg_pf(wx, vf);
108 	wx_check_for_ack_pf(wx, vf);
109 
110 	/* copy the caller specified message to the mailbox memory buffer */
111 	for (i = 0; i < size; i++)
112 		wr32a(wx, WX_PXMBMEM(vf), i, msg[i]);
113 
114 	/* Interrupt VF to tell it a message has been sent and release buffer */
115 	/* set mirrored mailbox flags */
116 	wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_STS);
117 	wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_STS);
118 
119 	return 0;
120 }
121 
122 /**
123  *  wx_read_mbx_pf - Read a message from the mailbox
124  *  @wx: pointer to the HW structure
125  *  @msg: The message buffer
126  *  @size: Length of buffer
127  *  @vf: the VF index
128  *
129  *  Return: return 0 on success and -EBUSY on failure
130  **/
131 int wx_read_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf)
132 {
133 	struct wx_mbx_info *mbx = &wx->mbx;
134 	int ret;
135 	u16 i;
136 
137 	/* limit read to size of mailbox and mbx->size is up to 15 */
138 	if (size > mbx->size)
139 		size = mbx->size;
140 
141 	/* lock the mailbox to prevent pf/vf race condition */
142 	ret = wx_obtain_mbx_lock_pf(wx, vf);
143 	if (ret)
144 		return ret;
145 
146 	for (i = 0; i < size; i++)
147 		msg[i] = rd32a(wx, WX_PXMBMEM(vf), i);
148 
149 	/* Acknowledge the message and release buffer */
150 	/* set mirrored mailbox flags */
151 	wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_ACK);
152 	wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_ACK);
153 
154 	return 0;
155 }
156 
157 /**
158  *  wx_check_for_rst_pf - checks to see if the VF has reset
159  *  @wx: pointer to the HW structure
160  *  @vf: the VF index
161  *
162  *  Return: return 0 on success and -EBUSY on failure
163  **/
164 int wx_check_for_rst_pf(struct wx *wx, u16 vf)
165 {
166 	u32 reg_offset = WX_VF_REG_OFFSET(vf);
167 	u32 vf_shift = WX_VF_IND_SHIFT(vf);
168 	u32 vflre = 0;
169 
170 	vflre = rd32(wx, WX_VFLRE(reg_offset));
171 	if (!(vflre & BIT(vf_shift)))
172 		return -EBUSY;
173 	wr32(wx, WX_VFLREC(reg_offset), BIT(vf_shift));
174 
175 	return 0;
176 }
177