/* PHY command */
        HCLGE_OPC_PHY_LINK_KSETTING     = 0x7025,
+       HCLGE_OPC_PHY_REG               = 0x7026,
 };
 
 #define HCLGE_TQP_REG_OFFSET           0x80000
        u8 rsv[22];
 };
 
+struct hclge_phy_reg_cmd {
+       __le16 reg_addr;
+       u8 rsv0[2];
+       __le16 reg_val;
+       u8 rsv1[18];
+};
+
 int hclge_cmd_init(struct hclge_dev *hdev);
 static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
 {
 
        return 0;
 }
 
+static int hclge_mii_ioctl(struct hclge_dev *hdev, struct ifreq *ifr, int cmd)
+{
+       struct mii_ioctl_data *data = if_mii(ifr);
+
+       if (!hnae3_dev_phy_imp_supported(hdev))
+               return -EOPNOTSUPP;
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               data->phy_id = hdev->hw.mac.phy_addr;
+               /* this command reads phy id and register at the same time */
+               fallthrough;
+       case SIOCGMIIREG:
+               data->val_out = hclge_read_phy_reg(hdev, data->reg_num);
+               return 0;
+
+       case SIOCSMIIREG:
+               return hclge_write_phy_reg(hdev, data->reg_num, data->val_in);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static int hclge_do_ioctl(struct hnae3_handle *handle, struct ifreq *ifr,
                          int cmd)
 {
        struct hclge_dev *hdev = vport->back;
 
        if (!hdev->hw.mac.phydev)
-               return -EOPNOTSUPP;
+               return hclge_mii_ioctl(hdev, ifr, cmd);
 
        return phy_mii_ioctl(hdev->hw.mac.phydev, ifr, cmd);
 }
 
 
        phy_stop(phydev);
 }
+
+u16 hclge_read_phy_reg(struct hclge_dev *hdev, u16 reg_addr)
+{
+       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);
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "failed to read phy reg, ret = %d.\n", ret);
+
+       return le16_to_cpu(req->reg_val);
+}
+
+int hclge_write_phy_reg(struct hclge_dev *hdev, 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->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 reg, ret = %d.\n", ret);
+
+       return ret;
+}
 
 void hclge_mac_disconnect_phy(struct hnae3_handle *handle);
 void hclge_mac_start_phy(struct hclge_dev *hdev);
 void hclge_mac_stop_phy(struct hclge_dev *hdev);
+u16 hclge_read_phy_reg(struct hclge_dev *hdev, u16 reg_addr);
+int hclge_write_phy_reg(struct hclge_dev *hdev, u16 reg_addr, u16 val);
 
 #endif