summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/wangxun/libwx/wx_mbx.c
blob: 73af5f11c3bdcd9b5b62add924e508b5fa6cb7b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */

#include <linux/pci.h>
#include "wx_type.h"
#include "wx_mbx.h"

/**
 *  wx_obtain_mbx_lock_pf - obtain mailbox lock
 *  @wx: pointer to the HW structure
 *  @vf: the VF index
 *
 *  Return: return 0 on success and -EBUSY on failure
 **/
static int wx_obtain_mbx_lock_pf(struct wx *wx, u16 vf)
{
	int count = 5;
	u32 mailbox;

	while (count--) {
		/* Take ownership of the buffer */
		wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_PFU);

		/* reserve mailbox for vf use */
		mailbox = rd32(wx, WX_PXMAILBOX(vf));
		if (mailbox & WX_PXMAILBOX_PFU)
			return 0;
		else if (count)
			udelay(10);
	}
	wx_err(wx, "Failed to obtain mailbox lock for PF%d", vf);

	return -EBUSY;
}

static int wx_check_for_bit_pf(struct wx *wx, u32 mask, int index)
{
	u32 mbvficr = rd32(wx, WX_MBVFICR(index));

	if (!(mbvficr & mask))
		return -EBUSY;
	wr32(wx, WX_MBVFICR(index), mask);

	return 0;
}

/**
 *  wx_check_for_ack_pf - checks to see if the VF has acked
 *  @wx: pointer to the HW structure
 *  @vf: the VF index
 *
 *  Return: return 0 if the VF has set the status bit or else -EBUSY
 **/
int wx_check_for_ack_pf(struct wx *wx, u16 vf)
{
	u32 index = vf / 16, vf_bit = vf % 16;

	return wx_check_for_bit_pf(wx,
				   FIELD_PREP(WX_MBVFICR_VFACK_MASK,
					      BIT(vf_bit)),
				   index);
}

/**
 *  wx_check_for_msg_pf - checks to see if the VF has sent mail
 *  @wx: pointer to the HW structure
 *  @vf: the VF index
 *
 *  Return: return 0 if the VF has got req bit or else -EBUSY
 **/
int wx_check_for_msg_pf(struct wx *wx, u16 vf)
{
	u32 index = vf / 16, vf_bit = vf % 16;

	return wx_check_for_bit_pf(wx,
				   FIELD_PREP(WX_MBVFICR_VFREQ_MASK,
					      BIT(vf_bit)),
				   index);
}

/**
 *  wx_write_mbx_pf - Places a message in the mailbox
 *  @wx: pointer to the HW structure
 *  @msg: The message buffer
 *  @size: Length of buffer
 *  @vf: the VF index
 *
 *  Return: return 0 on success and -EINVAL/-EBUSY on failure
 **/
int wx_write_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf)
{
	struct wx_mbx_info *mbx = &wx->mbx;
	int ret, i;

	/* mbx->size is up to 15 */
	if (size > mbx->size) {
		wx_err(wx, "Invalid mailbox message size %d", size);
		return -EINVAL;
	}

	/* lock the mailbox to prevent pf/vf race condition */
	ret = wx_obtain_mbx_lock_pf(wx, vf);
	if (ret)
		return ret;

	/* flush msg and acks as we are overwriting the message buffer */
	wx_check_for_msg_pf(wx, vf);
	wx_check_for_ack_pf(wx, vf);

	/* copy the caller specified message to the mailbox memory buffer */
	for (i = 0; i < size; i++)
		wr32a(wx, WX_PXMBMEM(vf), i, msg[i]);

	/* Interrupt VF to tell it a message has been sent and release buffer */
	/* set mirrored mailbox flags */
	wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_STS);
	wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_STS);

	return 0;
}

/**
 *  wx_read_mbx_pf - Read a message from the mailbox
 *  @wx: pointer to the HW structure
 *  @msg: The message buffer
 *  @size: Length of buffer
 *  @vf: the VF index
 *
 *  Return: return 0 on success and -EBUSY on failure
 **/
int wx_read_mbx_pf(struct wx *wx, u32 *msg, u16 size, u16 vf)
{
	struct wx_mbx_info *mbx = &wx->mbx;
	int ret;
	u16 i;

	/* limit read to size of mailbox and mbx->size is up to 15 */
	if (size > mbx->size)
		size = mbx->size;

	/* lock the mailbox to prevent pf/vf race condition */
	ret = wx_obtain_mbx_lock_pf(wx, vf);
	if (ret)
		return ret;

	for (i = 0; i < size; i++)
		msg[i] = rd32a(wx, WX_PXMBMEM(vf), i);

	/* Acknowledge the message and release buffer */
	/* set mirrored mailbox flags */
	wr32a(wx, WX_PXMBMEM(vf), WX_VXMAILBOX_SIZE, WX_PXMAILBOX_ACK);
	wr32(wx, WX_PXMAILBOX(vf), WX_PXMAILBOX_ACK);

	return 0;
}

/**
 *  wx_check_for_rst_pf - checks to see if the VF has reset
 *  @wx: pointer to the HW structure
 *  @vf: the VF index
 *
 *  Return: return 0 on success and -EBUSY on failure
 **/
int wx_check_for_rst_pf(struct wx *wx, u16 vf)
{
	u32 reg_offset = WX_VF_REG_OFFSET(vf);
	u32 vf_shift = WX_VF_IND_SHIFT(vf);
	u32 vflre = 0;

	vflre = rd32(wx, WX_VFLRE(reg_offset));
	if (!(vflre & BIT(vf_shift)))
		return -EBUSY;
	wr32(wx, WX_VFLREC(reg_offset), BIT(vf_shift));

	return 0;
}