]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: rnpgbe: Add basic mbx_fw support
authorDong Yibo <dong100@mucse.com>
Sat, 1 Nov 2025 01:38:48 +0000 (09:38 +0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 5 Nov 2025 02:11:36 +0000 (18:11 -0800)
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>
drivers/net/ethernet/mucse/rnpgbe/Makefile
drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.c
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c [new file with mode: 0644]
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h [new file with mode: 0644]

index 5fc878ada4b1116f8a3ef21c25cf0c4112d32a8c..de8bcb7772ab41c7ce6945e2477fd9f404e640ad 100644 (file)
@@ -7,4 +7,5 @@
 obj-$(CONFIG_MGBE) += rnpgbe.o
 rnpgbe-objs := rnpgbe_main.o\
               rnpgbe_chip.o\
-              rnpgbe_mbx.o
+              rnpgbe_mbx.o\
+              rnpgbe_mbx_fw.o
index 4c70b0cedd1ff8ae76ead6f070d6f365c7580564..37bd9278beaa0aae3ea2a8bc5d423010e374dcfb 100644 (file)
@@ -5,6 +5,7 @@
 #define _RNPGBE_H
 
 #include <linux/types.h>
+#include <linux/mutex.h>
 
 enum rnpgbe_boards {
        board_n500,
@@ -16,6 +17,8 @@ struct mucse_mbx_info {
        u32 delay_us;
        u16 fw_req;
        u16 fw_ack;
+       /* lock for only one use mbx */
+       struct mutex lock;
        /* fw <--> pf mbx */
        u32 fwpf_shm_base;
        u32 pf2fw_mbx_ctrl;
@@ -26,6 +29,7 @@ struct mucse_mbx_info {
 struct mucse_hw {
        void __iomem *hw_addr;
        struct mucse_mbx_info mbx;
+       u8 pfvfnum;
 };
 
 struct mucse {
index 5de4b104455e721f08663cebe6708dbc26fbb9be..de5e29230b3c8deb12f1da98ae9bc1d2bc92f8e0 100644 (file)
@@ -401,5 +401,6 @@ void mucse_init_mbx_params_pf(struct mucse_hw *hw)
 
        mbx->delay_us = 100;
        mbx->timeout_us = 4 * USEC_PER_SEC;
+       mutex_init(&mbx->lock);
        mucse_mbx_reset(hw);
 }
diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c
new file mode 100644 (file)
index 0000000..8c8bd5e
--- /dev/null
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2020 - 2025 Mucse Corporation. */
+
+#include <linux/if_ether.h>
+#include <linux/bitfield.h>
+
+#include "rnpgbe.h"
+#include "rnpgbe_mbx.h"
+#include "rnpgbe_mbx_fw.h"
+
+/**
+ * mucse_fw_send_cmd_wait_resp - Send cmd req and wait for response
+ * @hw: pointer to the HW structure
+ * @req: pointer to the cmd req structure
+ * @reply: pointer to the fw reply structure
+ *
+ * mucse_fw_send_cmd_wait_resp sends req to pf-fw mailbox and wait
+ * reply from fw.
+ *
+ * Return: 0 on success, negative errno on failure
+ **/
+static int mucse_fw_send_cmd_wait_resp(struct mucse_hw *hw,
+                                      struct mbx_fw_cmd_req *req,
+                                      struct mbx_fw_cmd_reply *reply)
+{
+       int len = le16_to_cpu(req->datalen);
+       int retry_cnt = 3;
+       int err;
+
+       mutex_lock(&hw->mbx.lock);
+       err = mucse_write_and_wait_ack_mbx(hw, (u32 *)req, len);
+       if (err)
+               goto out;
+       do {
+               err = mucse_poll_and_read_mbx(hw, (u32 *)reply,
+                                             sizeof(*reply));
+               if (err)
+                       goto out;
+               /* mucse_write_and_wait_ack_mbx return 0 means fw has
+                * received request, wait for the expect opcode
+                * reply with 'retry_cnt' times.
+                */
+       } while (--retry_cnt >= 0 && reply->opcode != req->opcode);
+out:
+       mutex_unlock(&hw->mbx.lock);
+       if (!err && retry_cnt < 0)
+               return -ETIMEDOUT;
+       if (!err && reply->error_code)
+               return -EIO;
+
+       return err;
+}
+
+/**
+ * mucse_mbx_get_info - Get hw info from fw
+ * @hw: pointer to the HW structure
+ *
+ * mucse_mbx_get_info tries to get hw info from hw.
+ *
+ * Return: 0 on success, negative errno on failure
+ **/
+static int mucse_mbx_get_info(struct mucse_hw *hw)
+{
+       struct mbx_fw_cmd_req req = {
+               .datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN),
+               .opcode  = cpu_to_le16(GET_HW_INFO),
+       };
+       struct mbx_fw_cmd_reply reply = {};
+       int err;
+
+       err = mucse_fw_send_cmd_wait_resp(hw, &req, &reply);
+       if (!err)
+               hw->pfvfnum = FIELD_GET(GENMASK_U16(7, 0),
+                                       le16_to_cpu(reply.hw_info.pfnum));
+
+       return err;
+}
+
+/**
+ * mucse_mbx_sync_fw - Try to sync with fw
+ * @hw: pointer to the HW structure
+ *
+ * mucse_mbx_sync_fw tries to sync with fw. It is only called in
+ * probe. Nothing (register network) todo if failed.
+ * Try more times to do sync.
+ *
+ * Return: 0 on success, negative errno on failure
+ **/
+int mucse_mbx_sync_fw(struct mucse_hw *hw)
+{
+       int try_cnt = 3;
+       int err;
+
+       do {
+               err = mucse_mbx_get_info(hw);
+       } while (err == -ETIMEDOUT && try_cnt--);
+
+       return err;
+}
+
+/**
+ * mucse_mbx_powerup - Echo fw to powerup
+ * @hw: pointer to the HW structure
+ * @is_powerup: true for powerup, false for powerdown
+ *
+ * mucse_mbx_powerup echo fw to change working frequency
+ * to normal after received true, and reduce working frequency
+ * if false.
+ *
+ * Return: 0 on success, negative errno on failure
+ **/
+int mucse_mbx_powerup(struct mucse_hw *hw, bool is_powerup)
+{
+       struct mbx_fw_cmd_req req = {
+               .datalen = cpu_to_le16(sizeof(req.powerup) +
+                                      MUCSE_MBX_REQ_HDR_LEN),
+               .opcode  = cpu_to_le16(POWER_UP),
+               .powerup = {
+                       /* fw needs this to reply correct cmd */
+                       .version = cpu_to_le32(GENMASK_U32(31, 0)),
+                       .status  = cpu_to_le32(is_powerup ? 1 : 0),
+               },
+       };
+       int len, err;
+
+       len = le16_to_cpu(req.datalen);
+       mutex_lock(&hw->mbx.lock);
+       err = mucse_write_and_wait_ack_mbx(hw, (u32 *)&req, len);
+       mutex_unlock(&hw->mbx.lock);
+
+       return err;
+}
+
+/**
+ * mucse_mbx_reset_hw - Posts a mbx req to reset hw
+ * @hw: pointer to the HW structure
+ *
+ * mucse_mbx_reset_hw posts a mbx req to firmware to reset hw.
+ * We use mucse_fw_send_cmd_wait_resp to wait hw reset ok.
+ *
+ * Return: 0 on success, negative errno on failure
+ **/
+int mucse_mbx_reset_hw(struct mucse_hw *hw)
+{
+       struct mbx_fw_cmd_req req = {
+               .datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN),
+               .opcode  = cpu_to_le16(RESET_HW),
+       };
+       struct mbx_fw_cmd_reply reply = {};
+
+       return mucse_fw_send_cmd_wait_resp(hw, &req, &reply);
+}
+
+/**
+ * mucse_mbx_get_macaddr - Posts a mbx req to request macaddr
+ * @hw: pointer to the HW structure
+ * @pfvfnum: index of pf/vf num
+ * @mac_addr: pointer to store mac_addr
+ * @port: port index
+ *
+ * mucse_mbx_get_macaddr posts a mbx req to firmware to get mac_addr.
+ *
+ * Return: 0 on success, negative errno on failure
+ **/
+int mucse_mbx_get_macaddr(struct mucse_hw *hw, int pfvfnum,
+                         u8 *mac_addr,
+                         int port)
+{
+       struct mbx_fw_cmd_req req = {
+               .datalen      = cpu_to_le16(sizeof(req.get_mac_addr) +
+                                           MUCSE_MBX_REQ_HDR_LEN),
+               .opcode       = cpu_to_le16(GET_MAC_ADDRESS),
+               .get_mac_addr = {
+                       .port_mask = cpu_to_le32(BIT(port)),
+                       .pfvf_num  = cpu_to_le32(pfvfnum),
+               },
+       };
+       struct mbx_fw_cmd_reply reply = {};
+       int err;
+
+       err = mucse_fw_send_cmd_wait_resp(hw, &req, &reply);
+       if (err)
+               return err;
+
+       if (le32_to_cpu(reply.mac_addr.ports) & BIT(port))
+               memcpy(mac_addr, reply.mac_addr.addrs[port].mac, ETH_ALEN);
+       else
+               return -ENODATA;
+
+       return 0;
+}
diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h
new file mode 100644 (file)
index 0000000..fb24fc1
--- /dev/null
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2020 - 2025 Mucse Corporation. */
+
+#ifndef _RNPGBE_MBX_FW_H
+#define _RNPGBE_MBX_FW_H
+
+#include <linux/types.h>
+
+#include "rnpgbe.h"
+
+#define MUCSE_MBX_REQ_HDR_LEN 24
+
+enum MUCSE_FW_CMD {
+       GET_HW_INFO     = 0x0601,
+       GET_MAC_ADDRESS = 0x0602,
+       RESET_HW        = 0x0603,
+       POWER_UP        = 0x0803,
+};
+
+struct mucse_hw_info {
+       u8 link_stat;
+       u8 port_mask;
+       __le32 speed;
+       __le16 phy_type;
+       __le16 nic_mode;
+       __le16 pfnum;
+       __le32 fw_version;
+       __le32 axi_mhz;
+       union {
+               u8 port_id[4];
+               __le32 port_ids;
+       };
+       __le32 bd_uid;
+       __le32 phy_id;
+       __le32 wol_status;
+       __le32 ext_info;
+} __packed;
+
+struct mbx_fw_cmd_req {
+       __le16 flags;
+       __le16 opcode;
+       __le16 datalen;
+       __le16 ret_value;
+       __le32 cookie_lo;
+       __le32 cookie_hi;
+       __le32 reply_lo;
+       __le32 reply_hi;
+       union {
+               u8 data[32];
+               struct {
+                       __le32 version;
+                       __le32 status;
+               } powerup;
+               struct {
+                       __le32 port_mask;
+                       __le32 pfvf_num;
+               } get_mac_addr;
+       };
+} __packed;
+
+struct mbx_fw_cmd_reply {
+       __le16 flags;
+       __le16 opcode;
+       __le16 error_code;
+       __le16 datalen;
+       __le32 cookie_lo;
+       __le32 cookie_hi;
+       union {
+               u8 data[40];
+               struct mac_addr {
+                       __le32 ports;
+                       struct _addr {
+                               /* for macaddr:01:02:03:04:05:06
+                                * mac-hi=0x01020304 mac-lo=0x05060000
+                                */
+                               u8 mac[8];
+                       } addrs[4];
+               } mac_addr;
+               struct mucse_hw_info hw_info;
+       };
+} __packed;
+
+int mucse_mbx_sync_fw(struct mucse_hw *hw);
+int mucse_mbx_powerup(struct mucse_hw *hw, bool is_powerup);
+int mucse_mbx_reset_hw(struct mucse_hw *hw);
+int mucse_mbx_get_macaddr(struct mucse_hw *hw, int pfvfnum,
+                         u8 *mac_addr, int port);
+#endif /* _RNPGBE_MBX_FW_H */