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