Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: rnpgbe: Add basic mbx_fw support

Add fundamental firmware (FW) communication operations via PF-FW
mailbox, including:
- FW sync (via HW info query with retries)
- HW reset (post FW command to reset hardware)
- MAC address retrieval (request FW for port-specific MAC)
- Power management (powerup/powerdown notification to FW)

Signed-off-by: Dong Yibo <dong100@mucse.com>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://patch.msgid.link/20251101013849.120565-5-dong100@mucse.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Dong Yibo and committed by
Jakub Kicinski
c6d3f019 4543534c

+286 -1
+2 -1
drivers/net/ethernet/mucse/rnpgbe/Makefile
··· 7 7 obj-$(CONFIG_MGBE) += rnpgbe.o 8 8 rnpgbe-objs := rnpgbe_main.o\ 9 9 rnpgbe_chip.o\ 10 - rnpgbe_mbx.o 10 + rnpgbe_mbx.o\ 11 + rnpgbe_mbx_fw.o
+4
drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h
··· 5 5 #define _RNPGBE_H 6 6 7 7 #include <linux/types.h> 8 + #include <linux/mutex.h> 8 9 9 10 enum rnpgbe_boards { 10 11 board_n500, ··· 17 16 u32 delay_us; 18 17 u16 fw_req; 19 18 u16 fw_ack; 19 + /* lock for only one use mbx */ 20 + struct mutex lock; 20 21 /* fw <--> pf mbx */ 21 22 u32 fwpf_shm_base; 22 23 u32 pf2fw_mbx_ctrl; ··· 29 26 struct mucse_hw { 30 27 void __iomem *hw_addr; 31 28 struct mucse_mbx_info mbx; 29 + u8 pfvfnum; 32 30 }; 33 31 34 32 struct mucse {
+1
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.c
··· 401 401 402 402 mbx->delay_us = 100; 403 403 mbx->timeout_us = 4 * USEC_PER_SEC; 404 + mutex_init(&mbx->lock); 404 405 mucse_mbx_reset(hw); 405 406 }
+191
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c
··· 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 + }
+88
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright(c) 2020 - 2025 Mucse Corporation. */ 3 + 4 + #ifndef _RNPGBE_MBX_FW_H 5 + #define _RNPGBE_MBX_FW_H 6 + 7 + #include <linux/types.h> 8 + 9 + #include "rnpgbe.h" 10 + 11 + #define MUCSE_MBX_REQ_HDR_LEN 24 12 + 13 + enum MUCSE_FW_CMD { 14 + GET_HW_INFO = 0x0601, 15 + GET_MAC_ADDRESS = 0x0602, 16 + RESET_HW = 0x0603, 17 + POWER_UP = 0x0803, 18 + }; 19 + 20 + struct mucse_hw_info { 21 + u8 link_stat; 22 + u8 port_mask; 23 + __le32 speed; 24 + __le16 phy_type; 25 + __le16 nic_mode; 26 + __le16 pfnum; 27 + __le32 fw_version; 28 + __le32 axi_mhz; 29 + union { 30 + u8 port_id[4]; 31 + __le32 port_ids; 32 + }; 33 + __le32 bd_uid; 34 + __le32 phy_id; 35 + __le32 wol_status; 36 + __le32 ext_info; 37 + } __packed; 38 + 39 + struct mbx_fw_cmd_req { 40 + __le16 flags; 41 + __le16 opcode; 42 + __le16 datalen; 43 + __le16 ret_value; 44 + __le32 cookie_lo; 45 + __le32 cookie_hi; 46 + __le32 reply_lo; 47 + __le32 reply_hi; 48 + union { 49 + u8 data[32]; 50 + struct { 51 + __le32 version; 52 + __le32 status; 53 + } powerup; 54 + struct { 55 + __le32 port_mask; 56 + __le32 pfvf_num; 57 + } get_mac_addr; 58 + }; 59 + } __packed; 60 + 61 + struct mbx_fw_cmd_reply { 62 + __le16 flags; 63 + __le16 opcode; 64 + __le16 error_code; 65 + __le16 datalen; 66 + __le32 cookie_lo; 67 + __le32 cookie_hi; 68 + union { 69 + u8 data[40]; 70 + struct mac_addr { 71 + __le32 ports; 72 + struct _addr { 73 + /* for macaddr:01:02:03:04:05:06 74 + * mac-hi=0x01020304 mac-lo=0x05060000 75 + */ 76 + u8 mac[8]; 77 + } addrs[4]; 78 + } mac_addr; 79 + struct mucse_hw_info hw_info; 80 + }; 81 + } __packed; 82 + 83 + int mucse_mbx_sync_fw(struct mucse_hw *hw); 84 + int mucse_mbx_powerup(struct mucse_hw *hw, bool is_powerup); 85 + int mucse_mbx_reset_hw(struct mucse_hw *hw); 86 + int mucse_mbx_get_macaddr(struct mucse_hw *hw, int pfvfnum, 87 + u8 *mac_addr, int port); 88 + #endif /* _RNPGBE_MBX_FW_H */