Commit 504159c3 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-hns3-enhance-capabilities-for-fibre-port'

Jian Shen says:

====================
net: hns3: enhance capabilities for fibre port

This patchset enhances more capabilities for fibre port,
include multipe media type identification, autoneg,
change port speed and FEC encoding.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e28441e2 7e6ec914
......@@ -120,6 +120,25 @@ enum hnae3_media_type {
HNAE3_MEDIA_TYPE_NONE,
};
/* must be consistent with definition in firmware */
enum hnae3_module_type {
HNAE3_MODULE_TYPE_UNKNOWN = 0x00,
HNAE3_MODULE_TYPE_FIBRE_LR = 0x01,
HNAE3_MODULE_TYPE_FIBRE_SR = 0x02,
HNAE3_MODULE_TYPE_AOC = 0x03,
HNAE3_MODULE_TYPE_CR = 0x04,
HNAE3_MODULE_TYPE_KR = 0x05,
HNAE3_MODULE_TYPE_TP = 0x06,
};
enum hnae3_fec_mode {
HNAE3_FEC_AUTO = 0,
HNAE3_FEC_BASER,
HNAE3_FEC_RS,
HNAE3_FEC_USER_DEF,
};
enum hnae3_reset_notify_type {
HNAE3_UP_CLIENT,
HNAE3_DOWN_CLIENT,
......@@ -230,10 +249,10 @@ struct hnae3_ae_dev {
* non-ok
* get_ksettings_an_result()
* Get negotiation status,speed and duplex
* update_speed_duplex_h()
* Update hardware speed and duplex
* get_media_type()
* Get media type of MAC
* check_port_speed()
* Check target speed whether is supported
* adjust_link()
* Adjust link status
* set_loopback()
......@@ -250,6 +269,8 @@ struct hnae3_ae_dev {
* set auto autonegotiation of pause frame use
* get_autoneg()
* get auto autonegotiation of pause frame use
* restart_autoneg()
* restart autonegotiation
* get_coalesce_usecs()
* get usecs to delay a TX interrupt after a packet is sent
* get_rx_max_coalesced_frames()
......@@ -340,11 +361,15 @@ struct hnae3_ae_ops {
void (*get_ksettings_an_result)(struct hnae3_handle *handle,
u8 *auto_neg, u32 *speed, u8 *duplex);
int (*update_speed_duplex_h)(struct hnae3_handle *handle);
int (*cfg_mac_speed_dup_h)(struct hnae3_handle *handle, int speed,
u8 duplex);
void (*get_media_type)(struct hnae3_handle *handle, u8 *media_type);
void (*get_media_type)(struct hnae3_handle *handle, u8 *media_type,
u8 *module_type);
int (*check_port_speed)(struct hnae3_handle *handle, u32 speed);
void (*get_fec)(struct hnae3_handle *handle, u8 *fec_ability,
u8 *fec_mode);
int (*set_fec)(struct hnae3_handle *handle, u32 fec_mode);
void (*adjust_link)(struct hnae3_handle *handle, int speed, int duplex);
int (*set_loopback)(struct hnae3_handle *handle,
enum hnae3_loop loop_mode, bool en);
......@@ -360,6 +385,7 @@ struct hnae3_ae_ops {
int (*set_autoneg)(struct hnae3_handle *handle, bool enable);
int (*get_autoneg)(struct hnae3_handle *handle);
int (*restart_autoneg)(struct hnae3_handle *handle);
void (*get_coalesce_usecs)(struct hnae3_handle *handle,
u32 *tx_usecs, u32 *rx_usecs);
......
......@@ -604,6 +604,7 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
{
struct hnae3_handle *h = hns3_get_handle(netdev);
const struct hnae3_ae_ops *ops;
u8 module_type;
u8 media_type;
u8 link_stat;
......@@ -612,7 +613,7 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
ops = h->ae_algo->ops;
if (ops->get_media_type)
ops->get_media_type(h, &media_type);
ops->get_media_type(h, &media_type, &module_type);
else
return -EOPNOTSUPP;
......@@ -622,7 +623,15 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
hns3_get_ksettings(h, cmd);
break;
case HNAE3_MEDIA_TYPE_FIBER:
cmd->base.port = PORT_FIBRE;
if (module_type == HNAE3_MODULE_TYPE_CR)
cmd->base.port = PORT_DA;
else
cmd->base.port = PORT_FIBRE;
hns3_get_ksettings(h, cmd);
break;
case HNAE3_MEDIA_TYPE_BACKPLANE:
cmd->base.port = PORT_NONE;
hns3_get_ksettings(h, cmd);
break;
case HNAE3_MEDIA_TYPE_COPPER:
......@@ -650,10 +659,54 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
return 0;
}
static int hns3_check_ksettings_param(struct net_device *netdev,
const struct ethtool_link_ksettings *cmd)
{
struct hnae3_handle *handle = hns3_get_handle(netdev);
const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN;
u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN;
u8 autoneg;
u32 speed;
u8 duplex;
int ret;
if (ops->get_ksettings_an_result) {
ops->get_ksettings_an_result(handle, &autoneg, &speed, &duplex);
if (cmd->base.autoneg == autoneg && cmd->base.speed == speed &&
cmd->base.duplex == duplex)
return 0;
}
if (ops->get_media_type)
ops->get_media_type(handle, &media_type, &module_type);
if (cmd->base.duplex != DUPLEX_FULL &&
media_type != HNAE3_MEDIA_TYPE_COPPER) {
netdev_err(netdev,
"only copper port supports half duplex!");
return -EINVAL;
}
if (ops->check_port_speed) {
ret = ops->check_port_speed(handle, cmd->base.speed);
if (ret) {
netdev_err(netdev, "unsupported speed\n");
return ret;
}
}
return 0;
}
static int hns3_set_link_ksettings(struct net_device *netdev,
const struct ethtool_link_ksettings *cmd)
{
/* Chip doesn't support this mode. */
struct hnae3_handle *handle = hns3_get_handle(netdev);
const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
int ret = 0;
/* Chip don't support this mode. */
if (cmd->base.speed == SPEED_1000 && cmd->base.duplex == DUPLEX_HALF)
return -EINVAL;
......@@ -661,7 +714,24 @@ static int hns3_set_link_ksettings(struct net_device *netdev,
if (netdev->phydev)
return phy_ethtool_ksettings_set(netdev->phydev, cmd);
return -EOPNOTSUPP;
if (handle->pdev->revision == 0x20)
return -EOPNOTSUPP;
ret = hns3_check_ksettings_param(netdev, cmd);
if (ret)
return ret;
if (ops->set_autoneg) {
ret = ops->set_autoneg(handle, cmd->base.autoneg);
if (ret)
return ret;
}
if (ops->cfg_mac_speed_dup_h)
ret = ops->cfg_mac_speed_dup_h(handle, cmd->base.speed,
cmd->base.duplex);
return ret;
}
static u32 hns3_get_rss_key_size(struct net_device *netdev)
......@@ -866,19 +936,36 @@ static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
static int hns3_nway_reset(struct net_device *netdev)
{
struct hnae3_handle *handle = hns3_get_handle(netdev);
const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
struct phy_device *phy = netdev->phydev;
int autoneg;
if (!netif_running(netdev))
return 0;
/* Only support nway_reset for netdev with phy attached for now */
if (!phy)
if (hns3_nic_resetting(netdev)) {
netdev_err(netdev, "dev resetting!");
return -EBUSY;
}
if (!ops->get_autoneg || !ops->restart_autoneg)
return -EOPNOTSUPP;
if (phy->autoneg != AUTONEG_ENABLE)
autoneg = ops->get_autoneg(handle);
if (autoneg != AUTONEG_ENABLE) {
netdev_err(netdev,
"Autoneg is off, don't support to restart it\n");
return -EINVAL;
}
return genphy_restart_aneg(phy);
if (phy)
return genphy_restart_aneg(phy);
if (handle->pdev->revision == 0x20)
return -EOPNOTSUPP;
return ops->restart_autoneg(handle);
}
static void hns3_get_channels(struct net_device *netdev,
......@@ -1124,6 +1211,81 @@ static void hns3_set_msglevel(struct net_device *netdev, u32 msg_level)
h->msg_enable = msg_level;
}
/* Translate local fec value into ethtool value. */
static unsigned int loc_to_eth_fec(u8 loc_fec)
{
u32 eth_fec = 0;
if (loc_fec & BIT(HNAE3_FEC_AUTO))
eth_fec |= ETHTOOL_FEC_AUTO;
if (loc_fec & BIT(HNAE3_FEC_RS))
eth_fec |= ETHTOOL_FEC_RS;
if (loc_fec & BIT(HNAE3_FEC_BASER))
eth_fec |= ETHTOOL_FEC_BASER;
/* if nothing is set, then FEC is off */
if (!eth_fec)
eth_fec = ETHTOOL_FEC_OFF;
return eth_fec;
}
/* Translate ethtool fec value into local value. */
static unsigned int eth_to_loc_fec(unsigned int eth_fec)
{
u32 loc_fec = 0;
if (eth_fec & ETHTOOL_FEC_OFF)
return loc_fec;
if (eth_fec & ETHTOOL_FEC_AUTO)
loc_fec |= BIT(HNAE3_FEC_AUTO);
if (eth_fec & ETHTOOL_FEC_RS)
loc_fec |= BIT(HNAE3_FEC_RS);
if (eth_fec & ETHTOOL_FEC_BASER)
loc_fec |= BIT(HNAE3_FEC_BASER);
return loc_fec;
}
static int hns3_get_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fec)
{
struct hnae3_handle *handle = hns3_get_handle(netdev);
const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
u8 fec_ability;
u8 fec_mode;
if (handle->pdev->revision == 0x20)
return -EOPNOTSUPP;
if (!ops->get_fec)
return -EOPNOTSUPP;
ops->get_fec(handle, &fec_ability, &fec_mode);
fec->fec = loc_to_eth_fec(fec_ability);
fec->active_fec = loc_to_eth_fec(fec_mode);
return 0;
}
static int hns3_set_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fec)
{
struct hnae3_handle *handle = hns3_get_handle(netdev);
const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
u32 fec_mode;
if (handle->pdev->revision == 0x20)
return -EOPNOTSUPP;
if (!ops->set_fec)
return -EOPNOTSUPP;
fec_mode = eth_to_loc_fec(fec->fec);
return ops->set_fec(handle, fec_mode);
}
static const struct ethtool_ops hns3vf_ethtool_ops = {
.get_drvinfo = hns3_get_drvinfo,
.get_ringparam = hns3_get_ringparam,
......@@ -1177,6 +1339,8 @@ static const struct ethtool_ops hns3_ethtool_ops = {
.set_phys_id = hns3_set_phys_id,
.get_msglevel = hns3_get_msglevel,
.set_msglevel = hns3_set_msglevel,
.get_fecparam = hns3_get_fecparam,
.set_fecparam = hns3_set_fecparam,
};
void hns3_ethtool_set_ops(struct net_device *netdev)
......
......@@ -113,6 +113,7 @@ enum hclge_opcode_type {
HCLGE_OPC_MAC_TNL_INT_EN = 0x0311,
HCLGE_OPC_CLEAR_MAC_TNL_INT = 0x0312,
HCLGE_OPC_SERDES_LOOPBACK = 0x0315,
HCLGE_OPC_CONFIG_FEC_MODE = 0x031A,
/* PFC/Pause commands */
HCLGE_OPC_CFG_MAC_PAUSE_EN = 0x0701,
......@@ -244,7 +245,7 @@ enum hclge_opcode_type {
HCLGE_OPC_QUERY_NCL_CONFIG = 0x7011,
/* SFP command */
HCLGE_OPC_SFP_GET_SPEED = 0x7104,
HCLGE_OPC_GET_SFP_INFO = 0x7104,
/* Error INT commands */
HCLGE_MAC_COMMON_INT_EN = 0x030E,
......@@ -599,9 +600,30 @@ struct hclge_config_auto_neg_cmd {
u8 rsv[20];
};
struct hclge_sfp_speed_cmd {
__le32 sfp_speed;
u32 rsv[5];
struct hclge_sfp_info_cmd {
__le32 speed;
u8 query_type; /* 0: sfp speed, 1: active speed */
u8 active_fec;
u8 autoneg; /* autoneg state */
u8 autoneg_ability; /* whether support autoneg */
__le32 speed_ability; /* speed ability for current media */
__le32 module_type;
u8 rsv[8];
};
#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)
#define HCLGE_MAC_CFG_FEC_SET_DEF_B 0
#define HCLGE_MAC_CFG_FEC_CLR_DEF_B 1
#define HCLGE_MAC_FEC_OFF 0
#define HCLGE_MAC_FEC_BASER 1
#define HCLGE_MAC_FEC_RS 2
struct hclge_config_fec_cmd {
u8 fec_mode;
u8 default_config;
u8 rsv[22];
};
#define HCLGE_MAC_UPLINK_PORT 0x100
......
......@@ -189,6 +189,8 @@ enum HLCGE_PORT_TYPE {
#define HCLGE_SUPPORT_25G_BIT BIT(2)
#define HCLGE_SUPPORT_50G_BIT BIT(3)
#define HCLGE_SUPPORT_100G_BIT BIT(4)
/* to be compatible with exsit board */
#define HCLGE_SUPPORT_40G_BIT BIT(5)
#define HCLGE_SUPPORT_100M_BIT BIT(6)
#define HCLGE_SUPPORT_10M_BIT BIT(7)
#define HCLGE_SUPPORT_GE \
......@@ -236,15 +238,25 @@ enum HCLGE_MAC_DUPLEX {
HCLGE_MAC_FULL
};
#define QUERY_SFP_SPEED 0
#define QUERY_ACTIVE_SPEED 1
struct hclge_mac {
u8 phy_addr;
u8 flag;
u8 media_type;
u8 media_type; /* port media type, e.g. fibre/copper/backplane */
u8 mac_addr[ETH_ALEN];
u8 autoneg;
u8 duplex;
u8 support_autoneg;
u8 speed_type; /* 0: sfp speed, 1: active speed */
u32 speed;
int link; /* store the link status of mac & phy (if phy exit)*/
u32 speed_ability; /* speed ability supported by current media */
u32 module_type; /* sub media type, e.g. kr/cr/sr/lr */
u32 fec_mode; /* active fec mode */
u32 user_fec_mode;
u32 fec_ability;
int link; /* store the link status of mac & phy (if phy exit) */
struct phy_device *phydev;
struct mii_bus *mdio_bus;
phy_interface_t phy_if;
......
......@@ -412,10 +412,11 @@ static int hclge_get_vf_media_type(struct hclge_vport *vport,
struct hclge_mbx_vf_to_pf_cmd *mbx_req)
{
struct hclge_dev *hdev = vport->back;
u8 resp_data;
u8 resp_data[2];
resp_data = hdev->hw.mac.media_type;
return hclge_gen_resp_to_vf(vport, mbx_req, 0, &resp_data,
resp_data[0] = hdev->hw.mac.media_type;
resp_data[1] = hdev->hw.mac.module_type;
return hclge_gen_resp_to_vf(vport, mbx_req, 0, resp_data,
sizeof(resp_data));
}
......
......@@ -330,11 +330,11 @@ static u16 hclgevf_get_qid_global(struct hnae3_handle *handle, u16 queue_id)
static int hclgevf_get_pf_media_type(struct hclgevf_dev *hdev)
{
u8 resp_msg;
u8 resp_msg[2];
int ret;
ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_MEDIA_TYPE, 0, NULL, 0,
true, &resp_msg, sizeof(resp_msg));
true, resp_msg, sizeof(resp_msg));
if (ret) {
dev_err(&hdev->pdev->dev,
"VF request to get the pf port media type failed %d",
......@@ -342,7 +342,8 @@ static int hclgevf_get_pf_media_type(struct hclgevf_dev *hdev)
return ret;
}
hdev->hw.mac.media_type = resp_msg;
hdev->hw.mac.media_type = resp_msg[0];
hdev->hw.mac.module_type = resp_msg[1];
return 0;
}
......@@ -2747,12 +2748,16 @@ static int hclgevf_gro_en(struct hnae3_handle *handle, bool enable)
return hclgevf_config_gro(hdev, enable);
}
static void hclgevf_get_media_type(struct hnae3_handle *handle,
u8 *media_type)
static void hclgevf_get_media_type(struct hnae3_handle *handle, u8 *media_type,
u8 *module_type)
{
struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
if (media_type)
*media_type = hdev->hw.mac.media_type;
if (module_type)
*module_type = hdev->hw.mac.module_type;
}
static bool hclgevf_get_hw_reset_stat(struct hnae3_handle *handle)
......
......@@ -143,6 +143,7 @@ enum hclgevf_states {
struct hclgevf_mac {
u8 media_type;
u8 module_type;
u8 mac_addr[ETH_ALEN];
int link;
u8 duplex;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment