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