未验证 提交 a696cb69 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!616 net: hns3: supports customization requirements

Merge Pull Request from: @svishen 
 
The PR incorporates the customization code framework to support hns3 customization requirements. The following functions are supported:
1.add support PF provides customized interfaces to detect port faults
2.add support detect port wire type
3.add support set mac state
4.add support set led
5.add extend interface support for read and write phy register

issue:
https://gitee.com/openeuler/kernel/issues/I6YE0O 
 
Link:https://gitee.com/openeuler/kernel/pulls/616 

Reviewed-by: Jialin Zhang <zhangjialin11@huawei.com> 
Signed-off-by: Jialin Zhang <zhangjialin11@huawei.com> 
......@@ -44,6 +44,32 @@ enum hnae3_ext_opcode {
HNAE3_EXT_OPC_GET_LANE_STATUS,
HNAE3_EXT_OPC_DISABLE_CLOCK,
HNAE3_EXT_OPC_SET_PFC_TIME,
HNAE3_EXT_OPC_GET_HILINK_REF_LOS,
HNAE3_EXT_OPC_GET_PORT_FAULT_STATUS,
HNAE3_EXT_OPC_GET_PORT_TYPE,
HNAE3_EXT_OPC_SET_MAC_STATE,
HNAE3_EXT_OPC_SET_LED,
HNAE3_EXT_OPC_GET_LED_SIGNAL,
HNAE3_EXT_OPC_GET_PHY_REG,
HNAE3_EXT_OPC_SET_PHY_REG,
};
struct hnae3_led_state_para {
u32 type;
u32 status;
};
struct hnae3_phy_para {
u32 page_select_addr;
u32 reg_addr;
u16 page;
u16 data;
};
struct hnae3_lamp_signal {
u8 error;
u8 locate;
u8 activity;
};
struct hnae3_pfc_storm_para {
......@@ -54,6 +80,19 @@ struct hnae3_pfc_storm_para {
u32 recovery_period_ms;
};
enum hnae3_port_fault_type {
HNAE3_FAULT_TYPE_CDR_FLASH,
HNAE3_FAULT_TYPE_9545_ERR,
HNAE3_FAULT_TYPE_CDR_CORE,
HNAE3_FAULT_TYPE_HILINK_REF_LOS,
HNAE3_FAULT_TYPE_INVALID
};
struct hnae3_port_fault {
u32 fault_type;
u32 fault_status;
};
struct hnae3_notify_pkt_param {
u32 ipg; /* inter-packet gap of sending, the unit is one cycle of clock */
u16 num; /* packet number of sending */
......
......@@ -439,3 +439,94 @@ int nic_set_pfc_time_cfg(struct net_device *ndev, u16 time)
&time, sizeof(time));
}
EXPORT_SYMBOL(nic_set_pfc_time_cfg);
int nic_get_port_fault_status(struct net_device *ndev, u32 fault_type, u32 *status)
{
int opcode = HNAE3_EXT_OPC_GET_PORT_FAULT_STATUS;
struct hnae3_port_fault fault_para;
int ret;
if (!status)
return -EINVAL;
if (fault_type == HNAE3_FAULT_TYPE_HILINK_REF_LOS)
opcode = HNAE3_EXT_OPC_GET_HILINK_REF_LOS;
fault_para.fault_type = fault_type;
ret = nic_invoke_pri_ops(ndev, opcode, &fault_para, sizeof(fault_para));
if (ret)
return ret;
*status = fault_para.fault_status;
return 0;
}
EXPORT_SYMBOL(nic_get_port_fault_status);
int nic_get_port_wire_type(struct net_device *ndev, u32 *wire_type)
{
return nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_GET_PORT_TYPE,
wire_type, sizeof(*wire_type));
}
EXPORT_SYMBOL(nic_get_port_wire_type);
int nic_set_mac_state(struct net_device *ndev, int enable)
{
return nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_SET_MAC_STATE,
&enable, sizeof(enable));
}
EXPORT_SYMBOL(nic_set_mac_state);
int nic_set_led(struct net_device *ndev, int type, int status)
{
struct hnae3_led_state_para para;
para.status = status;
para.type = type;
return nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_SET_LED,
&para, sizeof(para));
}
EXPORT_SYMBOL(nic_set_led);
int nic_get_led_signal(struct net_device *ndev, struct hnae3_lamp_signal *signal)
{
return nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_GET_LED_SIGNAL,
signal, sizeof(*signal));
}
EXPORT_SYMBOL(nic_get_led_signal);
int nic_get_phy_reg(struct net_device *ndev, u32 page_select_addr,
u16 page, u32 reg_addr, u16 *data)
{
struct hnae3_phy_para para;
int ret;
if (!data)
return -EINVAL;
para.page_select_addr = page_select_addr;
para.page = page;
para.reg_addr = reg_addr;
ret = nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_GET_PHY_REG,
&para, sizeof(para));
if (ret)
return ret;
*data = para.data;
return 0;
}
EXPORT_SYMBOL(nic_get_phy_reg);
int nic_set_phy_reg(struct net_device *ndev, u32 page_select_addr,
u16 page, u32 reg_addr, u16 data)
{
struct hnae3_phy_para para;
para.page_select_addr = page_select_addr;
para.page = page;
para.reg_addr = reg_addr;
para.data = data;
return nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_SET_PHY_REG,
&para, sizeof(para));
}
EXPORT_SYMBOL(nic_set_phy_reg);
......@@ -14,6 +14,18 @@
#define HNS3_PFC_STORM_PARA_PERIOD_MIN 5
#define HNS3_PFC_STORM_PARA_PERIOD_MAX 2000
#define nic_set_8211_phy_reg nic_set_phy_reg
#define nic_get_8211_phy_reg nic_get_phy_reg
#define nic_set_8521_phy_reg(ndev, page_region, page, reg_addr, data) \
nic_set_phy_reg(ndev, 0, page_region, page, reg_addr, data)
#define nic_get_8521_phy_reg(ndev, page_region, page, reg_addr, data) \
nic_get_phy_reg(ndev, 0, page_region, page, reg_addr, data)
#define nic_get_cdr_flash_status(ndev, status) \
nic_get_port_fault_status(ndev, HNAE3_FAULT_TYPE_CDR_FLASH, status)
#define nic_get_hilink_ref_los(ndev, status) \
nic_get_port_fault_status(ndev, HNAE3_FAULT_TYPE_HILINK_REF_LOS, status)
int nic_netdev_match_check(struct net_device *netdev);
void nic_chip_recover_handler(struct net_device *ndev,
enum hnae3_event_type_custom event_t);
......@@ -42,4 +54,13 @@ int nic_disable_net_lane(struct net_device *ndev);
int nic_get_net_lane_status(struct net_device *ndev, u32 *status);
int nic_disable_clock(struct net_device *ndev);
int nic_set_pfc_time_cfg(struct net_device *ndev, u16 time);
int nic_get_port_fault_status(struct net_device *ndev, u32 fault_type, u32 *status);
int nic_get_port_wire_type(struct net_device *ndev, u32 *wire_type);
int nic_set_mac_state(struct net_device *ndev, int enable);
int nic_set_led(struct net_device *ndev, int type, int status);
int nic_get_led_signal(struct net_device *ndev, struct hnae3_lamp_signal *signal);
int nic_get_phy_reg(struct net_device *ndev, u32 page_select_addr,
u16 page, u32 reg_addr, u16 *data);
int nic_set_phy_reg(struct net_device *ndev, u32 page_select_addr,
u16 page, u32 reg_addr, u16 data);
#endif
......@@ -355,6 +355,12 @@ struct hclge_sfp_info_cmd {
u8 rsv[6];
};
struct hclge_port_fault_cmd {
__le32 fault_status;
__le32 port_type;
u8 rsv[16];
};
#define HCLGE_MAC_CFG_FEC_AUTO_EN_B 0
#define HCLGE_MAC_CFG_FEC_MODE_S 1
#define HCLGE_MAC_CFG_FEC_MODE_M GENMASK(3, 1)
......@@ -879,11 +885,17 @@ struct hclge_phy_link_ksetting_1_cmd {
u8 rsv[22];
};
#define HCLGE_PHY_RW_DIRECTLY 0
#define HCLGE_PHY_RW_WITH_PAGE 1
struct hclge_phy_reg_cmd {
__le16 reg_addr;
u8 rsv0[2];
__le16 reg_val;
u8 rsv1[18];
u8 rsv1[2];
u8 type;
u8 dev_addr;
__le16 page;
u8 rsv2[12];
};
enum HCLGE_WOL_MODE {
......
......@@ -582,6 +582,707 @@ static int hclge_set_pause_trans_time(struct hclge_dev *hdev, void *data,
return 0;
}
static int hclge_get_hilink_ref_los(struct hclge_dev *hdev, void *data,
size_t length)
{
struct hclge_port_fault_cmd *fault_cmd;
struct hclge_desc desc;
int ret;
if (length != sizeof(struct hnae3_port_fault))
return -EINVAL;
fault_cmd = (struct hclge_port_fault_cmd *)desc.data;
ret = hclge_get_info_from_cmd(hdev, &desc, 1, HCLGE_OPC_CFG_GET_HILINK_REF_LOS);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to get hilink ref los, ret = %d\n", ret);
return ret;
}
*(u32 *)data = le32_to_cpu(fault_cmd->fault_status);
return 0;
}
static int hclge_get_port_fault_status(struct hclge_dev *hdev, void *data,
size_t length)
{
struct hclge_port_fault_cmd *fault_cmd;
struct hnae3_port_fault *para;
struct hclge_desc desc;
int ret;
if (length != sizeof(struct hnae3_port_fault))
return -EINVAL;
para = (struct hnae3_port_fault *)data;
fault_cmd = (struct hclge_port_fault_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_PORT_FAULT_STATUS, true);
fault_cmd->port_type = cpu_to_le32(para->fault_type);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to get port fault status, type = %u, ret = %d\n",
para->fault_type, ret);
return ret;
}
para->fault_status = le32_to_cpu(fault_cmd->fault_status);
return 0;
}
static int hclge_get_port_wire_type(struct hclge_dev *hdev, void *data,
size_t length)
{
u8 module_type;
if (length != sizeof(u32))
return -EINVAL;
hclge_get_media_type(&hdev->vport[0].nic, NULL, &module_type);
*(u32 *)data = module_type;
return 0;
}
static void hclge_set_phy_state(struct hclge_dev *hdev, bool enable)
{
struct phy_device *phydev = hdev->hw.mac.phydev;
if (!phydev)
return;
if (enable && (phydev->state == PHY_READY || phydev->state == PHY_HALTED))
phy_start(phydev);
else if (!enable && (phy_is_started(phydev) || phydev->state == PHY_DOWN))
phy_stop(phydev);
}
static int hclge_set_mac_state(struct hclge_dev *hdev, void *data,
size_t length)
{
bool enable;
int ret;
if (length != sizeof(int))
return -EINVAL;
enable = !!*(int *)data;
ret = hclge_cfg_mac_mode(hdev, enable);
if (!ret && !hclge_comm_dev_phy_imp_supported(hdev->ae_dev))
hclge_set_phy_state(hdev, enable);
return ret;
}
static int hclge_set_led(struct hclge_dev *hdev, void *data,
size_t length)
{
struct hclge_lamp_signal_cmd *para_cmd;
struct hnae3_led_state_para *para;
struct hclge_desc desc;
int ret;
if (length != sizeof(struct hnae3_led_state_para))
return -EINVAL;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_LED, false);
para = (struct hnae3_led_state_para *)data;
para_cmd = (struct hclge_lamp_signal_cmd *)desc.data;
para_cmd->type = cpu_to_le32(para->type);
para_cmd->status = cpu_to_le32(para->status);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev, "failed to set led, ret = %d\n", ret);
return ret;
}
static int hclge_get_led_signal(struct hclge_dev *hdev, void *data,
size_t length)
{
struct hclge_lamp_signal_cmd *signal_cmd;
struct hnae3_lamp_signal *signal;
struct hclge_desc desc;
int ret;
if (length != sizeof(struct hnae3_lamp_signal))
return -EINVAL;
ret = hclge_get_info_from_cmd(hdev, &desc, 1, HCLGE_OPC_SET_LED);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to get led signal, ret = %d\n", ret);
return ret;
}
signal = (struct hnae3_lamp_signal *)data;
signal_cmd = (struct hclge_lamp_signal_cmd *)desc.data;
signal->error = signal_cmd->error;
signal->locate = signal_cmd->locate;
signal->activity = signal_cmd->activity;
return 0;
}
static int hclge_def_phy_opt(struct mii_bus *mdio_bus, u32 phy_addr,
u16 reg_addr, u16 *data,
enum hclge_phy_op_code opt_type)
{
int ret;
if (opt_type == PHY_OP_READ) {
ret = mdio_bus->read(mdio_bus, phy_addr, reg_addr);
if (ret >= 0) {
*data = (u16)ret;
ret = 0;
}
} else {
ret = mdio_bus->write(mdio_bus, phy_addr, reg_addr, *data);
}
return ret;
}
static int hclge_phy_reg_opt(struct hclge_dev *hdev,
struct hnae3_phy_para *para,
enum hclge_phy_op_code opt_type)
{
struct mii_bus *mdio_bus = hdev->hw.mac.mdio_bus;
u32 phy_addr = hdev->hw.mac.phy_addr;
bool need_page_select = false;
u16 cur_page;
int ret;
/* operate flow:
* 1 record current page addr
* 2 jump to operated page
* 3 operate register(read or write)
* 4 come back to the page recorded in the first step.
*/
mutex_lock(&mdio_bus->mdio_lock);
/* check if page select is needed and record current page addr.
* no need to change page when read page 0
*/
if (opt_type != PHY_OP_READ || para->page != 0) {
ret = mdio_bus->read(mdio_bus, phy_addr,
para->page_select_addr);
if (ret < 0) {
dev_err(&hdev->pdev->dev,
"failed to read current phy %u reg page\n",
phy_addr);
mutex_unlock(&mdio_bus->mdio_lock);
return ret;
}
cur_page = (u16)ret;
need_page_select = cur_page != para->page;
}
/* jump to operated page */
if (need_page_select) {
ret = mdio_bus->write(mdio_bus, phy_addr,
para->page_select_addr, para->page);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
dev_err(&hdev->pdev->dev,
"failed to change phy %u page %u to page %u\n",
phy_addr, cur_page, para->page);
return ret;
}
}
/* operate register(read or write) */
ret = hclge_def_phy_opt(mdio_bus, phy_addr, para->reg_addr, &para->data,
opt_type);
if (ret < 0)
dev_err(&hdev->pdev->dev,
"failed to %s phy %u page %u reg %u\n, ret = %d",
opt_type == PHY_OP_READ ? "read" : "write",
phy_addr, para->page, para->reg_addr, ret);
/* come back to the page recorded in the first step. */
if (need_page_select) {
ret = mdio_bus->write(mdio_bus, phy_addr,
para->page_select_addr, cur_page);
if (ret < 0)
dev_err(&hdev->pdev->dev,
"failed to restore phy %u reg page %u\n",
phy_addr, cur_page);
}
mutex_unlock(&mdio_bus->mdio_lock);
return ret;
}
static int hclge_8521_phy_ext_opt(struct mii_bus *mdio_bus, u32 phy_addr,
u16 reg_addr, u16 *data,
enum hclge_phy_op_code opt_type)
{
#define EXT_REG_ADDR 0x1e
#define EXT_DATA_ADDR 0x1f
int ret;
ret = mdio_bus->write(mdio_bus, phy_addr, EXT_REG_ADDR, reg_addr);
if (ret < 0)
return ret;
return hclge_def_phy_opt(mdio_bus, phy_addr, EXT_DATA_ADDR, data,
opt_type);
}
static int hclge_8521_phy_mmd_opt(struct mii_bus *mdio_bus, u32 phy_addr,
u32 reg_addr, u16 *data,
enum hclge_phy_op_code opt_type)
{
#define MMD_REG_ADDR 0xd
#define MMD_DATA_ADDR 0xe
u16 mmd_index;
u16 mmd_reg;
int ret;
mmd_index = reg_addr >> 16U;
mmd_reg = reg_addr & 0xFFFF;
ret = mdio_bus->write(mdio_bus, phy_addr, MMD_REG_ADDR, mmd_index);
if (ret < 0)
return ret;
ret = mdio_bus->write(mdio_bus, phy_addr, MMD_DATA_ADDR, mmd_reg);
if (ret < 0)
return ret;
ret = mdio_bus->write(mdio_bus, phy_addr, MMD_REG_ADDR,
mmd_index | 0x4000);
if (ret < 0)
return ret;
return hclge_def_phy_opt(mdio_bus, phy_addr, MMD_DATA_ADDR, data,
opt_type);
}
static void hclge_8521_phy_restores_to_utp_mii(struct hclge_dev *hdev,
struct mii_bus *mdio_bus,
u32 phy_addr)
{
u16 phy_mii_region_val = 0x6;
u16 utp_region_val = 0x0;
int ret;
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_SMI_SDS_ADDR,
&utp_region_val, PHY_OP_WRITE);
if (ret)
dev_err(&hdev->pdev->dev,
"failed to choose phy space, ret = %d\n", ret);
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_LDS_MII_ADDR,
&phy_mii_region_val, PHY_OP_WRITE);
if (ret)
dev_err(&hdev->pdev->dev,
"failed to choose phy MII, ret = %d\n", ret);
}
static int hclge_8521_phy_utp_mii_opt(struct hnae3_phy_para *para,
struct mii_bus *mdio_bus, u32 phy_addr,
enum hclge_phy_op_code opt_type)
{
u16 phy_mii_region_val = 0x6;
u16 utp_region_val = 0x0;
int ret;
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_SMI_SDS_ADDR,
&utp_region_val, PHY_OP_WRITE);
if (ret)
return ret;
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_LDS_MII_ADDR,
&phy_mii_region_val, PHY_OP_WRITE);
if (ret)
return ret;
return hclge_def_phy_opt(mdio_bus, phy_addr, (u16)para->reg_addr,
&para->data, opt_type);
}
static int hclge_8521_phy_utp_mmd_opt(struct hnae3_phy_para *para,
struct mii_bus *mdio_bus, u32 phy_addr,
enum hclge_phy_op_code opt_type)
{
u16 utp_region_val = 0x0;
int ret;
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_SMI_SDS_ADDR,
&utp_region_val, PHY_OP_WRITE);
if (ret)
return ret;
return hclge_8521_phy_mmd_opt(mdio_bus, phy_addr, para->reg_addr,
&para->data, opt_type);
}
static int hclge_8521_phy_utp_lds_opt(struct hnae3_phy_para *para,
struct mii_bus *mdio_bus, u32 phy_addr,
enum hclge_phy_op_code opt_type)
{
u16 lds_mii_region_val = 0x4;
u16 utp_region_val = 0x0;
int ret;
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_SMI_SDS_ADDR,
&utp_region_val, PHY_OP_WRITE);
if (ret)
return ret;
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_LDS_MII_ADDR,
&lds_mii_region_val, PHY_OP_WRITE);
if (ret)
return ret;
return hclge_def_phy_opt(mdio_bus, phy_addr, (u16)para->reg_addr,
&para->data, opt_type);
}
static int hclge_8521_phy_utp_ext_opt(struct hnae3_phy_para *para,
struct mii_bus *mdio_bus, u32 phy_addr,
enum hclge_phy_op_code opt_type)
{
u16 utp_region_val = 0x0;
int ret;
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_SMI_SDS_ADDR,
&utp_region_val, PHY_OP_WRITE);
if (ret)
return ret;
return hclge_8521_phy_ext_opt(mdio_bus, phy_addr, (u16)para->reg_addr,
&para->data, opt_type);
}
static int hclge_8521_phy_sds_mii_opt(struct hnae3_phy_para *para,
struct mii_bus *mdio_bus, u32 phy_addr,
enum hclge_phy_op_code opt_type)
{
u16 sds_region_val = 0x2;
int ret;
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_SMI_SDS_ADDR,
&sds_region_val, PHY_OP_WRITE);
if (ret)
return ret;
return hclge_def_phy_opt(mdio_bus, phy_addr, (u16)para->reg_addr,
&para->data, opt_type);
}
static int hclge_8521_phy_sds_ext_opt(struct hnae3_phy_para *para,
struct mii_bus *mdio_bus, u32 phy_addr,
enum hclge_phy_op_code opt_type)
{
u16 sds_region_val = 0x2;
int ret;
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
HCLGE_8521_PHY_SMI_SDS_ADDR,
&sds_region_val, PHY_OP_WRITE);
if (ret)
return ret;
return hclge_8521_phy_ext_opt(mdio_bus, phy_addr, (u16)para->reg_addr,
&para->data, opt_type);
}
static int hclge_8521_phy_opt(struct hclge_dev *hdev,
struct hnae3_phy_para *para,
enum hclge_phy_op_code opt_type)
{
struct mii_bus *mdio_bus = hdev->hw.mac.mdio_bus;
u32 phy_addr = hdev->hw.mac.phy_addr;
int ret;
mutex_lock(&mdio_bus->mdio_lock);
switch (para->page) {
case HCLGE_PHY_REGION_UTP_MII:
ret = hclge_8521_phy_utp_mii_opt(para, mdio_bus,
phy_addr, opt_type);
break;
case HCLGE_PHY_REGION_UTP_MMD:
ret = hclge_8521_phy_utp_mmd_opt(para, mdio_bus,
phy_addr, opt_type);
break;
case HCLGE_PHY_REGION_UTP_LDS:
ret = hclge_8521_phy_utp_lds_opt(para, mdio_bus,
phy_addr, opt_type);
break;
case HCLGE_PHY_REGION_UTP_EXT:
ret = hclge_8521_phy_utp_ext_opt(para, mdio_bus,
phy_addr, opt_type);
break;
case HCLGE_PHY_REGION_SDS_MII:
ret = hclge_8521_phy_sds_mii_opt(para, mdio_bus,
phy_addr, opt_type);
break;
case HCLGE_PHY_REGION_SDS_EXT:
ret = hclge_8521_phy_sds_ext_opt(para, mdio_bus,
phy_addr, opt_type);
break;
case HCLGE_PHY_REGION_COM_REG:
ret = hclge_8521_phy_ext_opt(mdio_bus, phy_addr,
(u16)para->reg_addr,
&para->data, opt_type);
break;
default:
dev_err(&hdev->pdev->dev, "invalid reg region: %d\n",
para->page);
mutex_unlock(&mdio_bus->mdio_lock);
return -EINVAL;
}
if (ret)
dev_err(&hdev->pdev->dev,
"phy operation failed %d, reg_region: %d, data: 0x%x\n",
ret, para->page, para->data);
/* Set the region to UTP MII after operating the 8521 phy register */
hclge_8521_phy_restores_to_utp_mii(hdev, mdio_bus, phy_addr);
mutex_unlock(&mdio_bus->mdio_lock);
return ret;
}
static int hclge_check_phy_opt_param(struct hclge_dev *hdev, void *data,
size_t length)
{
struct hnae3_phy_para *para = (struct hnae3_phy_para *)data;
struct hclge_mac *mac = &hdev->hw.mac;
if (length != sizeof(*para))
return -EINVAL;
if (mac->media_type != HNAE3_MEDIA_TYPE_COPPER) {
dev_err(&hdev->pdev->dev, "this is not a copper port");
return -EOPNOTSUPP;
}
if (hnae3_dev_phy_imp_supported(hdev))
return 0;
if (!mac->phydev) {
dev_err(&hdev->pdev->dev, "this net device has no phy");
return -EINVAL;
}
if (!mac->mdio_bus) {
dev_err(&hdev->pdev->dev, "this net device has no mdio bus");
return -EINVAL;
}
return 0;
}
static int hclge_8211_phy_indirect_opt(struct hclge_dev *hdev,
struct hnae3_phy_para *para,
struct mii_bus *mdio_bus, u32 phy_addr,
enum hclge_phy_op_code opt_type)
{
u32 indirect_reg_data;
int ret;
/* select indirect page 0xa43 */
ret = mdio_bus->write(mdio_bus, phy_addr, para->page_select_addr,
HCLGE_8211_PHY_INDIRECT_PAGE);
if (ret < 0) {
dev_err(&hdev->pdev->dev,
"failed to change phy %u indirect page 0xa43\n",
phy_addr);
return ret;
}
/* indirect access addr = page_no*16 + 2*(reg_no%16) */
indirect_reg_data = (para->page << 4) + ((para->reg_addr % 16) << 1);
ret = mdio_bus->write(mdio_bus, phy_addr, HCLGE_8211_PHY_INDIRECT_REG,
indirect_reg_data);
if (ret < 0) {
dev_err(&hdev->pdev->dev,
"failed to write phy %u indirect reg\n", phy_addr);
return ret;
}
ret = hclge_def_phy_opt(mdio_bus, phy_addr,
HCLGE_8211_PHY_INDIRECT_DATA, &para->data,
opt_type);
if (ret < 0)
dev_err(&hdev->pdev->dev,
"failed to %s phy %u indirect data\n, ret = %d",
opt_type == PHY_OP_READ ? "read" : "write",
phy_addr, ret);
return ret;
}
static int hclge_8211_phy_need_indirect_access(u16 page)
{
if (page >= HCLGE_8211_PHY_INDIRECT_RANGE1_S &&
page <= HCLGE_8211_PHY_INDIRECT_RANGE1_E)
return true;
else if (page >= HCLGE_8211_PHY_INDIRECT_RANGE2_S &&
page <= HCLGE_8211_PHY_INDIRECT_RANGE2_E)
return true;
return false;
}
static int hclge_8211_phy_reg_opt(struct hclge_dev *hdev,
struct hnae3_phy_para *para,
enum hclge_phy_op_code opt_type)
{
struct mii_bus *mdio_bus = hdev->hw.mac.mdio_bus;
u32 phy_addr = hdev->hw.mac.phy_addr;
u16 save_page;
int ret;
mutex_lock(&mdio_bus->mdio_lock);
ret = mdio_bus->read(mdio_bus, phy_addr, para->page_select_addr);
if (ret < 0) {
dev_err(&hdev->pdev->dev,
"failed to record phy %u reg page\n", phy_addr);
mutex_unlock(&mdio_bus->mdio_lock);
return ret;
}
save_page = ret;
ret = hclge_8211_phy_indirect_opt(hdev, para, mdio_bus, phy_addr,
opt_type);
if (ret)
dev_err(&hdev->pdev->dev,
"failed to indirect access 8211 phy %u\n", phy_addr);
ret = mdio_bus->write(mdio_bus, phy_addr, para->page_select_addr,
save_page);
if (ret < 0)
dev_err(&hdev->pdev->dev,
"failed to restore phy %u reg page %u\n",
phy_addr, save_page);
mutex_unlock(&mdio_bus->mdio_lock);
return ret;
}
static int hclge_rw_8211_phy_reg(struct hclge_dev *hdev,
struct hnae3_phy_para *para,
enum hclge_phy_op_code opt_type)
{
if (hclge_8211_phy_need_indirect_access(para->page))
return hclge_8211_phy_reg_opt(hdev, para, opt_type);
return hclge_phy_reg_opt(hdev, para, opt_type);
}
/* used when imp support phy drvier */
static int hclge_read_phy_reg_with_page(struct hclge_dev *hdev, u16 page,
u16 reg_addr, u16 *val)
{
struct hclge_phy_reg_cmd *req;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PHY_REG, true);
req = (struct hclge_phy_reg_cmd *)desc.data;
req->reg_addr = cpu_to_le16(reg_addr);
req->type = HCLGE_PHY_RW_WITH_PAGE;
req->page = cpu_to_le16(page);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"failed to read phy page %u reg %u, ret = %d\n",
page, reg_addr, ret);
return ret;
}
*val = le16_to_cpu(req->reg_val);
return 0;
}
/* used when imp support phy drvier */
static int hclge_write_phy_reg_with_page(struct hclge_dev *hdev, u16 page,
u16 reg_addr, u16 val)
{
struct hclge_phy_reg_cmd *req;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PHY_REG, false);
req = (struct hclge_phy_reg_cmd *)desc.data;
req->reg_addr = cpu_to_le16(reg_addr);
req->type = HCLGE_PHY_RW_WITH_PAGE;
req->page = cpu_to_le16(page);
req->reg_val = cpu_to_le16(val);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev,
"failed to write phy page %u reg %u, ret = %d\n",
page, reg_addr, ret);
return ret;
}
static int hclge_rw_phy_reg_with_page(struct hclge_dev *hdev,
struct hnae3_phy_para *para,
enum hclge_phy_op_code opt_type)
{
if (opt_type == PHY_OP_READ)
return hclge_read_phy_reg_with_page(hdev, para->page,
para->reg_addr,
&para->data);
return hclge_write_phy_reg_with_page(hdev, para->page, para->reg_addr,
para->data);
}
static int hclge_rw_phy_reg(struct hclge_dev *hdev, void *data,
size_t length, enum hclge_phy_op_code opt_type)
{
struct hnae3_phy_para *para = (struct hnae3_phy_para *)data;
struct hclge_mac *mac = &hdev->hw.mac;
u32 phy_id;
int ret;
ret = hclge_check_phy_opt_param(hdev, data, length);
if (ret < 0)
return ret;
if (hnae3_dev_phy_imp_supported(hdev))
return hclge_rw_phy_reg_with_page(hdev, para, opt_type);
phy_id = mac->phydev->phy_id & HCLGE_PHY_ID_MASK;
switch (phy_id) {
case HCLGE_PHY_ID_FOR_RTL8211:
return hclge_rw_8211_phy_reg(hdev, para, opt_type);
case HCLGE_PHY_ID_FOR_YT8521:
return hclge_8521_phy_opt(hdev, para, opt_type);
case HCLGE_PHY_ID_FOR_MVL1512:
default:
return hclge_phy_reg_opt(hdev, para, opt_type);
}
}
static int hclge_get_phy_reg(struct hclge_dev *hdev, void *data, size_t length)
{
return hclge_rw_phy_reg(hdev, data, length, PHY_OP_READ);
}
static int hclge_set_phy_reg(struct hclge_dev *hdev, void *data, size_t length)
{
return hclge_rw_phy_reg(hdev, data, length, PHY_OP_WRITE);
}
static void hclge_ext_resotre_config(struct hclge_dev *hdev)
{
if (hdev->reset_type != HNAE3_IMP_RESET &&
......@@ -749,6 +1450,14 @@ static const hclge_priv_ops_fn hclge_ext_func_arr[] = {
[HNAE3_EXT_OPC_GET_LANE_STATUS] = hclge_get_net_lane_status,
[HNAE3_EXT_OPC_DISABLE_CLOCK] = hclge_disable_nic_clock,
[HNAE3_EXT_OPC_SET_PFC_TIME] = hclge_set_pause_trans_time,
[HNAE3_EXT_OPC_GET_HILINK_REF_LOS] = hclge_get_hilink_ref_los,
[HNAE3_EXT_OPC_GET_PORT_FAULT_STATUS] = hclge_get_port_fault_status,
[HNAE3_EXT_OPC_GET_PORT_TYPE] = hclge_get_port_wire_type,
[HNAE3_EXT_OPC_SET_MAC_STATE] = hclge_set_mac_state,
[HNAE3_EXT_OPC_SET_LED] = hclge_set_led,
[HNAE3_EXT_OPC_GET_LED_SIGNAL] = hclge_get_led_signal,
[HNAE3_EXT_OPC_GET_PHY_REG] = hclge_get_phy_reg,
[HNAE3_EXT_OPC_SET_PHY_REG] = hclge_set_phy_reg,
};
int hclge_ext_ops_handle(struct hnae3_handle *handle, int opcode,
......
......@@ -5,6 +5,38 @@
#define __HCLGE_EXT_H
#include <linux/types.h>
#define HCLGE_PHY_ID_FOR_RTL8211 0x001cc910
#define HCLGE_PHY_ID_FOR_MVL1512 0x01410dd0
#define HCLGE_PHY_ID_FOR_YT8521 0x00000110
#define HCLGE_PHY_ID_MASK 0xFFFFFFF0U
enum hclge_phy_page_region {
HCLGE_PHY_REGION_UTP_MII,
HCLGE_PHY_REGION_UTP_MMD,
HCLGE_PHY_REGION_UTP_LDS,
HCLGE_PHY_REGION_UTP_EXT,
HCLGE_PHY_REGION_SDS_MII,
HCLGE_PHY_REGION_SDS_EXT,
HCLGE_PHY_REGION_COM_REG,
HCLGE_PHY_REGION_MAX
};
enum hclge_phy_op_code {
PHY_OP_READ,
PHY_OP_WRITE
};
#define HCLGE_8211_PHY_INDIRECT_PAGE 0xa43
#define HCLGE_8211_PHY_INDIRECT_REG 0x1b
#define HCLGE_8211_PHY_INDIRECT_DATA 0x1c
#define HCLGE_8211_PHY_INDIRECT_RANGE1_S 0xDC0
#define HCLGE_8211_PHY_INDIRECT_RANGE1_E 0xDCF
#define HCLGE_8211_PHY_INDIRECT_RANGE2_S 0xDE0
#define HCLGE_8211_PHY_INDIRECT_RANGE2_E 0xDF0
#define HCLGE_8521_PHY_SMI_SDS_ADDR 0xA000
#define HCLGE_8521_PHY_LDS_MII_ADDR 0x100
#define HCLGE_NOTIFY_PARA_CFG_PKT_EN BIT(0)
#define HCLGE_NOTIFY_PARA_CFG_START_EN BIT(1)
#define HCLGE_NOTIFY_PARA_CFG_PKT_NUM_M GENMASK(5, 2)
......@@ -83,6 +115,15 @@ struct hclge_sfp_enable_cmd {
__le32 rsv[5];
};
struct hclge_lamp_signal_cmd {
__le32 type;
__le32 status;
u8 error;
u8 locate;
u8 activity;
u8 rsv[13];
};
enum hclge_ext_opcode_type {
HCLGE_OPC_CONFIG_NIC_CLOCK = 0x0060,
HCLGE_OPC_CONFIG_SWITCH_PARAM = 0x1033,
......@@ -92,8 +133,11 @@ enum hclge_ext_opcode_type {
HCLGE_OPC_CHIP_ID_GET = 0x7003,
HCLGE_OPC_GET_CHIP_NUM = 0x7005,
HCLGE_OPC_GET_PORT_NUM = 0x7006,
HCLGE_OPC_SET_LED = 0x7007,
HCLGE_OPC_DISABLE_NET_LANE = 0x7008,
HCLGE_OPC_CFG_PAUSE_STORM_PARA = 0x7019,
HCLGE_OPC_CFG_GET_HILINK_REF_LOS = 0x701B,
HCLGE_OPC_GET_PORT_FAULT_STATUS = 0x7023,
HCLGE_OPC_SFP_GET_PRESENT = 0x7101,
HCLGE_OPC_SFP_SET_STATUS = 0x7102,
};
......
......@@ -7977,7 +7977,7 @@ static void hclge_enable_fd(struct hnae3_handle *handle, bool enable)
hclge_task_schedule(hdev, 0);
}
static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
int hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
{
struct hclge_desc desc;
struct hclge_config_mac_mode_cmd *req =
......@@ -8004,8 +8004,10 @@ static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev,
"mac enable fail, ret =%d.\n", ret);
dev_err(&hdev->pdev->dev, "failed to %s mac, ret = %d.\n",
enable ? "enable" : "disable", ret);
return ret;
}
static int hclge_config_switch_param(struct hclge_dev *hdev, int vfid,
......@@ -11493,8 +11495,8 @@ static void hclge_get_ksettings_an_result(struct hnae3_handle *handle,
*auto_neg = hdev->hw.mac.autoneg;
}
static void hclge_get_media_type(struct hnae3_handle *handle, u8 *media_type,
u8 *module_type)
void hclge_get_media_type(struct hnae3_handle *handle, u8 *media_type,
u8 *module_type)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
......
......@@ -1167,4 +1167,7 @@ struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf);
int hclge_inform_vf_reset(struct hclge_vport *vport, u16 reset_type);
void hclge_reset_task_schedule(struct hclge_dev *hdev);
void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle);
void hclge_get_media_type(struct hnae3_handle *handle, u8 *media_type,
u8 *module_type);
int hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable);
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册