xref: /linux/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
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  **/
22 static int mucse_fw_send_cmd_wait_resp(struct mucse_hw *hw,
23 				       struct mbx_fw_cmd_req *req,
24 				       struct mbx_fw_cmd_reply *reply)
25 {
26 	int len = le16_to_cpu(req->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, (u32 *)req, len);
32 	if (err)
33 		goto out;
34 	do {
35 		err = mucse_poll_and_read_mbx(hw, (u32 *)reply,
36 					      sizeof(*reply));
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->opcode != req->opcode);
44 out:
45 	mutex_unlock(&hw->mbx.lock);
46 	if (!err && retry_cnt < 0)
47 		return -ETIMEDOUT;
48 	if (!err && reply->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  **/
62 static int mucse_mbx_get_info(struct mucse_hw *hw)
63 {
64 	struct mbx_fw_cmd_req req = {
65 		.datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN),
66 		.opcode  = cpu_to_le16(GET_HW_INFO),
67 	};
68 	struct mbx_fw_cmd_reply reply = {};
69 	int err;
70 
71 	err = mucse_fw_send_cmd_wait_resp(hw, &req, &reply);
72 	if (!err)
73 		hw->pfvfnum = FIELD_GET(GENMASK_U16(7, 0),
74 					le16_to_cpu(reply.hw_info.pfnum));
75 
76 	return err;
77 }
78 
79 /**
80  * mucse_mbx_sync_fw - Try to sync with fw
81  * @hw: pointer to the HW structure
82  *
83  * mucse_mbx_sync_fw tries to sync with fw. It is only called in
84  * probe. Nothing (register network) todo if failed.
85  * Try more times to do sync.
86  *
87  * Return: 0 on success, negative errno on failure
88  **/
89 int mucse_mbx_sync_fw(struct mucse_hw *hw)
90 {
91 	int try_cnt = 3;
92 	int err;
93 
94 	do {
95 		err = mucse_mbx_get_info(hw);
96 	} while (err == -ETIMEDOUT && try_cnt--);
97 
98 	return err;
99 }
100 
101 /**
102  * mucse_mbx_powerup - Echo fw to powerup
103  * @hw: pointer to the HW structure
104  * @is_powerup: true for powerup, false for powerdown
105  *
106  * mucse_mbx_powerup echo fw to change working frequency
107  * to normal after received true, and reduce working frequency
108  * if false.
109  *
110  * Return: 0 on success, negative errno on failure
111  **/
112 int mucse_mbx_powerup(struct mucse_hw *hw, bool is_powerup)
113 {
114 	struct mbx_fw_cmd_req req = {
115 		.datalen = cpu_to_le16(sizeof(req.powerup) +
116 				       MUCSE_MBX_REQ_HDR_LEN),
117 		.opcode  = cpu_to_le16(POWER_UP),
118 		.powerup = {
119 			/* fw needs this to reply correct cmd */
120 			.version = cpu_to_le32(GENMASK_U32(31, 0)),
121 			.status  = cpu_to_le32(is_powerup ? 1 : 0),
122 		},
123 	};
124 	int len, err;
125 
126 	len = le16_to_cpu(req.datalen);
127 	mutex_lock(&hw->mbx.lock);
128 	err = mucse_write_and_wait_ack_mbx(hw, (u32 *)&req, len);
129 	mutex_unlock(&hw->mbx.lock);
130 
131 	return err;
132 }
133 
134 /**
135  * mucse_mbx_reset_hw - Posts a mbx req to reset hw
136  * @hw: pointer to the HW structure
137  *
138  * mucse_mbx_reset_hw posts a mbx req to firmware to reset hw.
139  * We use mucse_fw_send_cmd_wait_resp to wait hw reset ok.
140  *
141  * Return: 0 on success, negative errno on failure
142  **/
143 int mucse_mbx_reset_hw(struct mucse_hw *hw)
144 {
145 	struct mbx_fw_cmd_req req = {
146 		.datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN),
147 		.opcode  = cpu_to_le16(RESET_HW),
148 	};
149 	struct mbx_fw_cmd_reply reply = {};
150 
151 	return mucse_fw_send_cmd_wait_resp(hw, &req, &reply);
152 }
153 
154 /**
155  * mucse_mbx_get_macaddr - Posts a mbx req to request macaddr
156  * @hw: pointer to the HW structure
157  * @pfvfnum: index of pf/vf num
158  * @mac_addr: pointer to store mac_addr
159  * @port: port index
160  *
161  * mucse_mbx_get_macaddr posts a mbx req to firmware to get mac_addr.
162  *
163  * Return: 0 on success, negative errno on failure
164  **/
165 int mucse_mbx_get_macaddr(struct mucse_hw *hw, int pfvfnum,
166 			  u8 *mac_addr,
167 			  int port)
168 {
169 	struct mbx_fw_cmd_req req = {
170 		.datalen      = cpu_to_le16(sizeof(req.get_mac_addr) +
171 					    MUCSE_MBX_REQ_HDR_LEN),
172 		.opcode       = cpu_to_le16(GET_MAC_ADDRESS),
173 		.get_mac_addr = {
174 			.port_mask = cpu_to_le32(BIT(port)),
175 			.pfvf_num  = cpu_to_le32(pfvfnum),
176 		},
177 	};
178 	struct mbx_fw_cmd_reply reply = {};
179 	int err;
180 
181 	err = mucse_fw_send_cmd_wait_resp(hw, &req, &reply);
182 	if (err)
183 		return err;
184 
185 	if (le32_to_cpu(reply.mac_addr.ports) & BIT(port))
186 		memcpy(mac_addr, reply.mac_addr.addrs[port].mac, ETH_ALEN);
187 	else
188 		return -ENODATA;
189 
190 	return 0;
191 }
192