linux/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016~2017 Hisilicon Limited.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 */
   9
  10#include <linux/etherdevice.h>
  11#include <linux/kernel.h>
  12
  13#include "hclge_cmd.h"
  14#include "hclge_main.h"
  15#include "hclge_mdio.h"
  16
  17#define HCLGE_PHY_SUPPORTED_FEATURES    (SUPPORTED_Autoneg | \
  18                                         SUPPORTED_TP | \
  19                                         PHY_10BT_FEATURES | \
  20                                         PHY_100BT_FEATURES | \
  21                                         PHY_1000BT_FEATURES)
  22
  23enum hclge_mdio_c22_op_seq {
  24        HCLGE_MDIO_C22_WRITE = 1,
  25        HCLGE_MDIO_C22_READ = 2
  26};
  27
  28#define HCLGE_MDIO_CTRL_START_B         0
  29#define HCLGE_MDIO_CTRL_ST_S            1
  30#define HCLGE_MDIO_CTRL_ST_M            (0x3 << HCLGE_MDIO_CTRL_ST_S)
  31#define HCLGE_MDIO_CTRL_OP_S            3
  32#define HCLGE_MDIO_CTRL_OP_M            (0x3 << HCLGE_MDIO_CTRL_OP_S)
  33
  34#define HCLGE_MDIO_PHYID_S              0
  35#define HCLGE_MDIO_PHYID_M              (0x1f << HCLGE_MDIO_PHYID_S)
  36
  37#define HCLGE_MDIO_PHYREG_S             0
  38#define HCLGE_MDIO_PHYREG_M             (0x1f << HCLGE_MDIO_PHYREG_S)
  39
  40#define HCLGE_MDIO_STA_B                0
  41
  42struct hclge_mdio_cfg_cmd {
  43        u8 ctrl_bit;
  44        u8 phyid;
  45        u8 phyad;
  46        u8 rsvd;
  47        __le16 reserve;
  48        __le16 data_wr;
  49        __le16 data_rd;
  50        __le16 sta;
  51};
  52
  53static int hclge_mdio_write(struct mii_bus *bus, int phyid, int regnum,
  54                            u16 data)
  55{
  56        struct hclge_mdio_cfg_cmd *mdio_cmd;
  57        struct hclge_dev *hdev = bus->priv;
  58        struct hclge_desc desc;
  59        int ret;
  60
  61        if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
  62                return 0;
  63
  64        hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, false);
  65
  66        mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
  67
  68        hnae3_set_field(mdio_cmd->phyid, HCLGE_MDIO_PHYID_M,
  69                        HCLGE_MDIO_PHYID_S, phyid);
  70        hnae3_set_field(mdio_cmd->phyad, HCLGE_MDIO_PHYREG_M,
  71                        HCLGE_MDIO_PHYREG_S, regnum);
  72
  73        hnae3_set_bit(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_START_B, 1);
  74        hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_ST_M,
  75                        HCLGE_MDIO_CTRL_ST_S, 1);
  76        hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_OP_M,
  77                        HCLGE_MDIO_CTRL_OP_S, HCLGE_MDIO_C22_WRITE);
  78
  79        mdio_cmd->data_wr = cpu_to_le16(data);
  80
  81        ret = hclge_cmd_send(&hdev->hw, &desc, 1);
  82        if (ret) {
  83                dev_err(&hdev->pdev->dev,
  84                        "mdio write fail when sending cmd, status is %d.\n",
  85                        ret);
  86                return ret;
  87        }
  88
  89        return 0;
  90}
  91
  92static int hclge_mdio_read(struct mii_bus *bus, int phyid, int regnum)
  93{
  94        struct hclge_mdio_cfg_cmd *mdio_cmd;
  95        struct hclge_dev *hdev = bus->priv;
  96        struct hclge_desc desc;
  97        int ret;
  98
  99        if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
 100                return 0;
 101
 102        hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, true);
 103
 104        mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
 105
 106        hnae3_set_field(mdio_cmd->phyid, HCLGE_MDIO_PHYID_M,
 107                        HCLGE_MDIO_PHYID_S, phyid);
 108        hnae3_set_field(mdio_cmd->phyad, HCLGE_MDIO_PHYREG_M,
 109                        HCLGE_MDIO_PHYREG_S, regnum);
 110
 111        hnae3_set_bit(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_START_B, 1);
 112        hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_ST_M,
 113                        HCLGE_MDIO_CTRL_ST_S, 1);
 114        hnae3_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_OP_M,
 115                        HCLGE_MDIO_CTRL_OP_S, HCLGE_MDIO_C22_READ);
 116
 117        /* Read out phy data */
 118        ret = hclge_cmd_send(&hdev->hw, &desc, 1);
 119        if (ret) {
 120                dev_err(&hdev->pdev->dev,
 121                        "mdio read fail when get data, status is %d.\n",
 122                        ret);
 123                return ret;
 124        }
 125
 126        if (hnae3_get_bit(le16_to_cpu(mdio_cmd->sta), HCLGE_MDIO_STA_B)) {
 127                dev_err(&hdev->pdev->dev, "mdio read data error\n");
 128                return -EIO;
 129        }
 130
 131        return le16_to_cpu(mdio_cmd->data_rd);
 132}
 133
 134int hclge_mac_mdio_config(struct hclge_dev *hdev)
 135{
 136        struct hclge_mac *mac = &hdev->hw.mac;
 137        struct phy_device *phydev;
 138        struct mii_bus *mdio_bus;
 139        int ret;
 140
 141        if (hdev->hw.mac.phy_addr >= PHY_MAX_ADDR) {
 142                dev_err(&hdev->pdev->dev, "phy_addr(%d) is too large.\n",
 143                        hdev->hw.mac.phy_addr);
 144                return -EINVAL;
 145        }
 146
 147        mdio_bus = devm_mdiobus_alloc(&hdev->pdev->dev);
 148        if (!mdio_bus)
 149                return -ENOMEM;
 150
 151        mdio_bus->name = "hisilicon MII bus";
 152        mdio_bus->read = hclge_mdio_read;
 153        mdio_bus->write = hclge_mdio_write;
 154        snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii",
 155                 dev_name(&hdev->pdev->dev));
 156
 157        mdio_bus->parent = &hdev->pdev->dev;
 158        mdio_bus->priv = hdev;
 159        mdio_bus->phy_mask = ~(1 << mac->phy_addr);
 160        ret = mdiobus_register(mdio_bus);
 161        if (ret) {
 162                dev_err(mdio_bus->parent,
 163                        "Failed to register MDIO bus ret = %#x\n", ret);
 164                return ret;
 165        }
 166
 167        phydev = mdiobus_get_phy(mdio_bus, mac->phy_addr);
 168        if (!phydev) {
 169                dev_err(mdio_bus->parent, "Failed to get phy device\n");
 170                mdiobus_unregister(mdio_bus);
 171                return -EIO;
 172        }
 173
 174        mac->phydev = phydev;
 175        mac->mdio_bus = mdio_bus;
 176
 177        return 0;
 178}
 179
 180static void hclge_mac_adjust_link(struct net_device *netdev)
 181{
 182        struct hnae3_handle *h = *((void **)netdev_priv(netdev));
 183        struct hclge_vport *vport = hclge_get_vport(h);
 184        struct hclge_dev *hdev = vport->back;
 185        int duplex, speed;
 186        int ret;
 187
 188        speed = netdev->phydev->speed;
 189        duplex = netdev->phydev->duplex;
 190
 191        ret = hclge_cfg_mac_speed_dup(hdev, speed, duplex);
 192        if (ret)
 193                netdev_err(netdev, "failed to adjust link.\n");
 194
 195        ret = hclge_cfg_flowctrl(hdev);
 196        if (ret)
 197                netdev_err(netdev, "failed to configure flow control.\n");
 198}
 199
 200int hclge_mac_connect_phy(struct hnae3_handle *handle)
 201{
 202        struct hclge_vport *vport = hclge_get_vport(handle);
 203        struct hclge_dev *hdev = vport->back;
 204        struct net_device *netdev = hdev->vport[0].nic.netdev;
 205        struct phy_device *phydev = hdev->hw.mac.phydev;
 206        __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
 207        int ret;
 208
 209        if (!phydev)
 210                return 0;
 211
 212        linkmode_clear_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
 213
 214        ret = phy_connect_direct(netdev, phydev,
 215                                 hclge_mac_adjust_link,
 216                                 PHY_INTERFACE_MODE_SGMII);
 217        if (ret) {
 218                netdev_err(netdev, "phy_connect_direct err.\n");
 219                return ret;
 220        }
 221
 222        linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mask);
 223        linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, mask);
 224        linkmode_set_bit_array(phy_10_100_features_array,
 225                               ARRAY_SIZE(phy_10_100_features_array),
 226                               mask);
 227        linkmode_set_bit_array(phy_gbit_features_array,
 228                               ARRAY_SIZE(phy_gbit_features_array),
 229                               mask);
 230        linkmode_and(phydev->supported, phydev->supported, mask);
 231        phy_support_asym_pause(phydev);
 232
 233        return 0;
 234}
 235
 236void hclge_mac_disconnect_phy(struct hnae3_handle *handle)
 237{
 238        struct hclge_vport *vport = hclge_get_vport(handle);
 239        struct hclge_dev *hdev = vport->back;
 240        struct phy_device *phydev = hdev->hw.mac.phydev;
 241
 242        if (!phydev)
 243                return;
 244
 245        phy_disconnect(phydev);
 246}
 247
 248void hclge_mac_start_phy(struct hclge_dev *hdev)
 249{
 250        struct phy_device *phydev = hdev->hw.mac.phydev;
 251
 252        if (!phydev)
 253                return;
 254
 255        phy_start(phydev);
 256}
 257
 258void hclge_mac_stop_phy(struct hclge_dev *hdev)
 259{
 260        struct net_device *netdev = hdev->vport[0].nic.netdev;
 261        struct phy_device *phydev = netdev->phydev;
 262
 263        if (!phydev)
 264                return;
 265
 266        phy_stop(phydev);
 267}
 268