net: hns3: add ethtool -p support for fiber port
authorJian Shen <shenjian15@huawei.com>
Fri, 19 Jan 2018 06:41:11 +0000 (14:41 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 22 Jan 2018 21:05:49 +0000 (16:05 -0500)
Add led location support for fiber port. The led will keep blinking
when locating.

Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c

index d104ce50f9483a679212973222dc23acfe91ccae..fd06bc78c58ec90b9619205e698f2972c6433cf7 100644 (file)
@@ -405,6 +405,8 @@ struct hnae3_ae_ops {
        int (*set_channels)(struct hnae3_handle *handle, u32 new_tqps_num);
        void (*get_flowctrl_adv)(struct hnae3_handle *handle,
                                 u32 *flowctrl_adv);
+       int (*set_led_id)(struct hnae3_handle *handle,
+                         enum ethtool_phys_id_state status);
 };
 
 struct hnae3_dcb_ops {
index 1c8b293f822d62eb3649f1276a0f3614a3cc6c09..741020534b164fe02c4b0b9cbf4d57f2847f6ff5 100644 (file)
@@ -1084,6 +1084,17 @@ static void hns3_get_regs(struct net_device *netdev,
        h->ae_algo->ops->get_regs(h, &cmd->version, data);
 }
 
+static int hns3_set_phys_id(struct net_device *netdev,
+                           enum ethtool_phys_id_state state)
+{
+       struct hnae3_handle *h = hns3_get_handle(netdev);
+
+       if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_led_id)
+               return -EOPNOTSUPP;
+
+       return h->ae_algo->ops->set_led_id(h, state);
+}
+
 static const struct ethtool_ops hns3vf_ethtool_ops = {
        .get_drvinfo = hns3_get_drvinfo,
        .get_ringparam = hns3_get_ringparam,
@@ -1126,6 +1137,7 @@ static const struct ethtool_ops hns3_ethtool_ops = {
        .set_coalesce = hns3_set_coalesce,
        .get_regs_len = hns3_get_regs_len,
        .get_regs = hns3_get_regs,
+       .set_phys_id = hns3_set_phys_id,
 };
 
 void hns3_ethtool_set_ops(struct net_device *netdev)
index 1cd28e00846ff38752e6258b42477d4f0cf0b5a3..122f862b6d9c2eacf6878e80177e5881c6c33c3f 100644 (file)
@@ -227,6 +227,9 @@ enum hclge_opcode_type {
 
        /* Mailbox cmd */
        HCLGEVF_OPC_MBX_PF_TO_VF        = 0x2000,
+
+       /* Led command */
+       HCLGE_OPC_LED_STATUS_CFG        = 0xB000,
 };
 
 #define HCLGE_TQP_REG_OFFSET           0x80000
@@ -807,6 +810,23 @@ struct hclge_reset_cmd {
 #define HCLGE_NIC_CMQ_DESC_NUM         1024
 #define HCLGE_NIC_CMQ_DESC_NUM_S       3
 
+#define HCLGE_LED_PORT_SPEED_STATE_S   0
+#define HCLGE_LED_PORT_SPEED_STATE_M   GENMASK(5, 0)
+#define HCLGE_LED_ACTIVITY_STATE_S     0
+#define HCLGE_LED_ACTIVITY_STATE_M     GENMASK(1, 0)
+#define HCLGE_LED_LINK_STATE_S         0
+#define HCLGE_LED_LINK_STATE_M         GENMASK(1, 0)
+#define HCLGE_LED_LOCATE_STATE_S       0
+#define HCLGE_LED_LOCATE_STATE_M       GENMASK(1, 0)
+
+struct hclge_set_led_state_cmd {
+       u8 port_speed_led_config;
+       u8 link_led_config;
+       u8 activity_led_config;
+       u8 locate_led_config;
+       u8 rsv[20];
+};
+
 int hclge_cmd_init(struct hclge_dev *hdev);
 static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
 {
index 6e64bed299ddd57d4e87af0e5b99617925b54023..12150f26d00d2b856f128789fab9abe44f7c1397 100644 (file)
@@ -5819,6 +5819,75 @@ static void hclge_get_regs(struct hnae3_handle *handle, u32 *version,
                        "Get 64 bit register failed, ret = %d.\n", ret);
 }
 
+static int hclge_set_led_status_sfp(struct hclge_dev *hdev, u8 speed_led_status,
+                                   u8 act_led_status, u8 link_led_status,
+                                   u8 locate_led_status)
+{
+       struct hclge_set_led_state_cmd *req;
+       struct hclge_desc desc;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_LED_STATUS_CFG, false);
+
+       req = (struct hclge_set_led_state_cmd *)desc.data;
+       hnae_set_field(req->port_speed_led_config, HCLGE_LED_PORT_SPEED_STATE_M,
+                      HCLGE_LED_PORT_SPEED_STATE_S, speed_led_status);
+       hnae_set_field(req->link_led_config, HCLGE_LED_ACTIVITY_STATE_M,
+                      HCLGE_LED_ACTIVITY_STATE_S, act_led_status);
+       hnae_set_field(req->activity_led_config, HCLGE_LED_LINK_STATE_M,
+                      HCLGE_LED_LINK_STATE_S, link_led_status);
+       hnae_set_field(req->locate_led_config, HCLGE_LED_LOCATE_STATE_M,
+                      HCLGE_LED_LOCATE_STATE_S, locate_led_status);
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "Send set led state cmd error, ret =%d\n", ret);
+
+       return ret;
+}
+
+enum hclge_led_status {
+       HCLGE_LED_OFF,
+       HCLGE_LED_ON,
+       HCLGE_LED_NO_CHANGE = 0xFF,
+};
+
+static int hclge_set_led_id(struct hnae3_handle *handle,
+                           enum ethtool_phys_id_state status)
+{
+#define BLINK_FREQUENCY                2
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hclge_dev *hdev = vport->back;
+       struct phy_device *phydev = hdev->hw.mac.phydev;
+       int ret = 0;
+
+       if (phydev || hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_FIBER)
+               return -EOPNOTSUPP;
+
+       switch (status) {
+       case ETHTOOL_ID_ACTIVE:
+               ret = hclge_set_led_status_sfp(hdev,
+                                              HCLGE_LED_NO_CHANGE,
+                                              HCLGE_LED_NO_CHANGE,
+                                              HCLGE_LED_NO_CHANGE,
+                                              HCLGE_LED_ON);
+               break;
+       case ETHTOOL_ID_INACTIVE:
+               ret = hclge_set_led_status_sfp(hdev,
+                                              HCLGE_LED_NO_CHANGE,
+                                              HCLGE_LED_NO_CHANGE,
+                                              HCLGE_LED_NO_CHANGE,
+                                              HCLGE_LED_OFF);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static const struct hnae3_ae_ops hclge_ops = {
        .init_ae_dev = hclge_init_ae_dev,
        .uninit_ae_dev = hclge_uninit_ae_dev,
@@ -5872,6 +5941,7 @@ static const struct hnae3_ae_ops hclge_ops = {
        .get_flowctrl_adv = hclge_get_flowctrl_adv,
        .get_regs_len = hclge_get_regs_len,
        .get_regs = hclge_get_regs,
+       .set_led_id = hclge_set_led_id,
 };
 
 static struct hnae3_ae_algo ae_algo = {