xref: /linux/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c (revision fab183d632628381b466a41479489541ac0e29a0)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2020 - 2025 Mucse Corporation. */
3 
4 #include <linux/if_ether.h>
5 #include <linux/bitfield.h>
6 
7 #include "rnpgbe.h"
8 #include "rnpgbe_mbx.h"
9 #include "rnpgbe_mbx_fw.h"
10 
11 /**
12  * mucse_fw_send_cmd_wait_resp - Send cmd req and wait for response
13  * @hw: pointer to the HW structure
14  * @req: pointer to the cmd req structure
15  * @reply: pointer to the fw reply structure
16  *
17  * mucse_fw_send_cmd_wait_resp sends req to pf-fw mailbox and wait
18  * reply from fw.
19  *
20  * Return: 0 on success, negative errno on failure
21  **/
mucse_fw_send_cmd_wait_resp(struct mucse_hw * hw,union mbx_fw_cmd_req_u * req,union mbx_fw_cmd_reply_u * reply)22 static int mucse_fw_send_cmd_wait_resp(struct mucse_hw *hw,
23 				       union mbx_fw_cmd_req_u *req,
24 				       union mbx_fw_cmd_reply_u *reply)
25 {
26 	int len = le16_to_cpu(req->r.datalen);
27 	int retry_cnt = 3;
28 	int err;
29 
30 	mutex_lock(&hw->mbx.lock);
31 	err = mucse_write_and_wait_ack_mbx(hw, req->dwords, len);
32 	if (err)
33 		goto out;
34 	do {
35 		err = mucse_poll_and_read_mbx(hw, reply->dwords,
36 					      sizeof(reply->r));
37 		if (err)
38 			goto out;
39 		/* mucse_write_and_wait_ack_mbx return 0 means fw has
40 		 * received request, wait for the expect opcode
41 		 * reply with 'retry_cnt' times.
42 		 */
43 	} while (--retry_cnt >= 0 && reply->r.opcode != req->r.opcode);
44 out:
45 	mutex_unlock(&hw->mbx.lock);
46 	if (!err && retry_cnt < 0)
47 		return -ETIMEDOUT;
48 	if (!err && reply->r.error_code)
49 		return -EIO;
50 
51 	return err;
52 }
53 
54 /**
55  * mucse_mbx_get_info - Get hw info from fw
56  * @hw: pointer to the HW structure
57  *
58  * mucse_mbx_get_info tries to get hw info from hw.
59  *
60  * Return: 0 on success, negative errno on failure
61  **/
mucse_mbx_get_info(struct mucse_hw * hw)62 static int mucse_mbx_get_info(struct mucse_hw *hw)
63 {
64 	union mbx_fw_cmd_req_u req = {
65 		.r = {
66 			.datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN),
67 			.opcode  = cpu_to_le16(GET_HW_INFO),
68 		},
69 	};
70 	union mbx_fw_cmd_reply_u reply = {};
71 	int err;
72 
73 	err = mucse_fw_send_cmd_wait_resp(hw, &req, &reply);
74 	if (!err)
75 		hw->pfvfnum = FIELD_GET(GENMASK_U16(7, 0),
76 					le16_to_cpu(reply.r.hw_info.pfnum));
77 
78 	return err;
79 }
80 
81 /**
82  * mucse_mbx_sync_fw - Try to sync with fw
83  * @hw: pointer to the HW structure
84  *
85  * mucse_mbx_sync_fw tries to sync with fw. It is only called in
86  * probe. Nothing (register network) todo if failed.
87  * Try more times to do sync.
88  *
89  * Return: 0 on success, negative errno on failure
90  **/
mucse_mbx_sync_fw(struct mucse_hw * hw)91 int mucse_mbx_sync_fw(struct mucse_hw *hw)
92 {
93 	int try_cnt = 3;
94 	int err;
95 
96 	do {
97 		err = mucse_mbx_get_info(hw);
98 	} while (err == -ETIMEDOUT && try_cnt--);
99 
100 	return err;
101 }
102 
103 /**
104  * mucse_mbx_powerup - Echo fw to powerup
105  * @hw: pointer to the HW structure
106  * @is_powerup: true for powerup, false for powerdown
107  *
108  * mucse_mbx_powerup echo fw to change working frequency
109  * to normal after received true, and reduce working frequency
110  * if false.
111  *
112  * Return: 0 on success, negative errno on failure
113  **/
mucse_mbx_powerup(struct mucse_hw * hw,bool is_powerup)114 int mucse_mbx_powerup(struct mucse_hw *hw, bool is_powerup)
115 {
116 	union mbx_fw_cmd_req_u req = {
117 		.r = {
118 			.datalen = cpu_to_le16(sizeof(req.r.powerup) +
119 					       MUCSE_MBX_REQ_HDR_LEN),
120 			.opcode  = cpu_to_le16(POWER_UP),
121 			.powerup = {
122 				/* fw needs this to reply correct cmd */
123 				.version = cpu_to_le32(GENMASK_U32(31, 0)),
124 				.status  = cpu_to_le32(is_powerup ? 1 : 0),
125 			},
126 		},
127 	};
128 	int len, err;
129 
130 	len = le16_to_cpu(req.r.datalen);
131 	mutex_lock(&hw->mbx.lock);
132 	err = mucse_write_and_wait_ack_mbx(hw, req.dwords, len);
133 	mutex_unlock(&hw->mbx.lock);
134 
135 	return err;
136 }
137 
138 /**
139  * mucse_mbx_reset_hw - Posts a mbx req to reset hw
140  * @hw: pointer to the HW structure
141  *
142  * mucse_mbx_reset_hw posts a mbx req to firmware to reset hw.
143  * We use mucse_fw_send_cmd_wait_resp to wait hw reset ok.
144  *
145  * Return: 0 on success, negative errno on failure
146  **/
mucse_mbx_reset_hw(struct mucse_hw * hw)147 int mucse_mbx_reset_hw(struct mucse_hw *hw)
148 {
149 	union mbx_fw_cmd_req_u req = {
150 		.r = {
151 			.datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN),
152 			.opcode  = cpu_to_le16(RESET_HW),
153 		},
154 	};
155 	union mbx_fw_cmd_reply_u reply = {};
156 
157 	return mucse_fw_send_cmd_wait_resp(hw, &req, &reply);
158 }
159 
160 /**
161  * mucse_mbx_get_macaddr - Posts a mbx req to request macaddr
162  * @hw: pointer to the HW structure
163  * @pfvfnum: index of pf/vf num
164  * @mac_addr: pointer to store mac_addr
165  * @port: port index
166  *
167  * mucse_mbx_get_macaddr posts a mbx req to firmware to get mac_addr.
168  *
169  * Return: 0 on success, negative errno on failure
170  **/
mucse_mbx_get_macaddr(struct mucse_hw * hw,int pfvfnum,u8 * mac_addr,int port)171 int mucse_mbx_get_macaddr(struct mucse_hw *hw, int pfvfnum,
172 			  u8 *mac_addr,
173 			  int port)
174 {
175 	union mbx_fw_cmd_req_u req = {
176 		.r = {
177 			.datalen      = cpu_to_le16(sizeof(req.r.get_mac_addr) +
178 						    MUCSE_MBX_REQ_HDR_LEN),
179 			.opcode       = cpu_to_le16(GET_MAC_ADDRESS),
180 			.get_mac_addr = {
181 				.port_mask = cpu_to_le32(BIT(port)),
182 				.pfvf_num  = cpu_to_le32(pfvfnum),
183 			},
184 		},
185 	};
186 	union mbx_fw_cmd_reply_u reply = {};
187 	int err;
188 
189 	err = mucse_fw_send_cmd_wait_resp(hw, &req, &reply);
190 	if (err)
191 		return err;
192 
193 	if (le32_to_cpu(reply.r.mac_addr.ports) & BIT(port))
194 		memcpy(mac_addr, reply.r.mac_addr.addrs[port].mac, ETH_ALEN);
195 	else
196 		return -ENODATA;
197 
198 	return 0;
199 }
200