mirror of
https://github.com/torvalds/linux.git
synced 2026-01-12 00:42:35 +08:00
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>
This commit is contained in:
committed by
Jakub Kicinski
parent
4543534c3e
commit
c6d3f0198e
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
191
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c
Normal file
191
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c
Normal file
@@ -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;
|
||||
}
|
||||
88
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h
Normal file
88
drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h
Normal file
@@ -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 */
|
||||
Reference in New Issue
Block a user