]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blame - drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
[mirror_ubuntu-eoan-kernel.git] / drivers / net / ethernet / hisilicon / hns3 / hns3pf / hclge_mdio.c
CommitLineData
256727da
S
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
439adf88
FL
17#define HCLGE_PHY_SUPPORTED_FEATURES (SUPPORTED_Autoneg | \
18 SUPPORTED_TP | \
19 SUPPORTED_Pause | \
f16121c8 20 SUPPORTED_Asym_Pause | \
439adf88
FL
21 PHY_10BT_FEATURES | \
22 PHY_100BT_FEATURES | \
23 PHY_1000BT_FEATURES)
24
256727da
S
25enum hclge_mdio_c22_op_seq {
26 HCLGE_MDIO_C22_WRITE = 1,
27 HCLGE_MDIO_C22_READ = 2
28};
29
30#define HCLGE_MDIO_CTRL_START_B 0
31#define HCLGE_MDIO_CTRL_ST_S 1
32#define HCLGE_MDIO_CTRL_ST_M (0x3 << HCLGE_MDIO_CTRL_ST_S)
33#define HCLGE_MDIO_CTRL_OP_S 3
34#define HCLGE_MDIO_CTRL_OP_M (0x3 << HCLGE_MDIO_CTRL_OP_S)
35
36#define HCLGE_MDIO_PHYID_S 0
37#define HCLGE_MDIO_PHYID_M (0x1f << HCLGE_MDIO_PHYID_S)
38
39#define HCLGE_MDIO_PHYREG_S 0
40#define HCLGE_MDIO_PHYREG_M (0x1f << HCLGE_MDIO_PHYREG_S)
41
42#define HCLGE_MDIO_STA_B 0
43
44struct hclge_mdio_cfg_cmd {
45 u8 ctrl_bit;
46 u8 phyid;
47 u8 phyad;
48 u8 rsvd;
49 __le16 reserve;
50 __le16 data_wr;
51 __le16 data_rd;
52 __le16 sta;
53};
54
55static int hclge_mdio_write(struct mii_bus *bus, int phyid, int regnum,
56 u16 data)
57{
58 struct hclge_mdio_cfg_cmd *mdio_cmd;
59 struct hclge_dev *hdev = bus->priv;
60 struct hclge_desc desc;
61 int ret;
62
63 hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, false);
64
65 mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
66
67 hnae_set_field(mdio_cmd->phyid, HCLGE_MDIO_PHYID_M,
68 HCLGE_MDIO_PHYID_S, phyid);
69 hnae_set_field(mdio_cmd->phyad, HCLGE_MDIO_PHYREG_M,
70 HCLGE_MDIO_PHYREG_S, regnum);
71
72 hnae_set_bit(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_START_B, 1);
73 hnae_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_ST_M,
74 HCLGE_MDIO_CTRL_ST_S, 1);
75 hnae_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_OP_M,
76 HCLGE_MDIO_CTRL_OP_S, HCLGE_MDIO_C22_WRITE);
77
78 mdio_cmd->data_wr = cpu_to_le16(data);
79
80 ret = hclge_cmd_send(&hdev->hw, &desc, 1);
81 if (ret) {
82 dev_err(&hdev->pdev->dev,
83 "mdio write fail when sending cmd, status is %d.\n",
84 ret);
85 return ret;
86 }
87
88 return 0;
89}
90
91static int hclge_mdio_read(struct mii_bus *bus, int phyid, int regnum)
92{
93 struct hclge_mdio_cfg_cmd *mdio_cmd;
94 struct hclge_dev *hdev = bus->priv;
95 struct hclge_desc desc;
96 int ret;
97
98 hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MDIO_CONFIG, true);
99
100 mdio_cmd = (struct hclge_mdio_cfg_cmd *)desc.data;
101
102 hnae_set_field(mdio_cmd->phyid, HCLGE_MDIO_PHYID_M,
103 HCLGE_MDIO_PHYID_S, phyid);
104 hnae_set_field(mdio_cmd->phyad, HCLGE_MDIO_PHYREG_M,
105 HCLGE_MDIO_PHYREG_S, regnum);
106
107 hnae_set_bit(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_START_B, 1);
108 hnae_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_ST_M,
109 HCLGE_MDIO_CTRL_ST_S, 1);
110 hnae_set_field(mdio_cmd->ctrl_bit, HCLGE_MDIO_CTRL_OP_M,
111 HCLGE_MDIO_CTRL_OP_S, HCLGE_MDIO_C22_READ);
112
113 /* Read out phy data */
114 ret = hclge_cmd_send(&hdev->hw, &desc, 1);
115 if (ret) {
116 dev_err(&hdev->pdev->dev,
117 "mdio read fail when get data, status is %d.\n",
118 ret);
119 return ret;
120 }
121
122 if (hnae_get_bit(le16_to_cpu(mdio_cmd->sta), HCLGE_MDIO_STA_B)) {
123 dev_err(&hdev->pdev->dev, "mdio read data error\n");
124 return -EIO;
125 }
126
127 return le16_to_cpu(mdio_cmd->data_rd);
128}
129
130int hclge_mac_mdio_config(struct hclge_dev *hdev)
131{
132 struct hclge_mac *mac = &hdev->hw.mac;
133 struct phy_device *phydev;
134 struct mii_bus *mdio_bus;
135 int ret;
136
137 if (hdev->hw.mac.phy_addr >= PHY_MAX_ADDR)
138 return 0;
139
140 mdio_bus = devm_mdiobus_alloc(&hdev->pdev->dev);
141 if (!mdio_bus)
142 return -ENOMEM;
143
144 mdio_bus->name = "hisilicon MII bus";
145 mdio_bus->read = hclge_mdio_read;
146 mdio_bus->write = hclge_mdio_write;
147 snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii",
148 dev_name(&hdev->pdev->dev));
149
150 mdio_bus->parent = &hdev->pdev->dev;
151 mdio_bus->priv = hdev;
152 mdio_bus->phy_mask = ~(1 << mac->phy_addr);
153 ret = mdiobus_register(mdio_bus);
154 if (ret) {
155 dev_err(mdio_bus->parent,
156 "Failed to register MDIO bus ret = %#x\n", ret);
157 return ret;
158 }
159
160 phydev = mdiobus_get_phy(mdio_bus, mac->phy_addr);
752b0694 161 if (!phydev) {
256727da
S
162 dev_err(mdio_bus->parent, "Failed to get phy device\n");
163 mdiobus_unregister(mdio_bus);
164 return -EIO;
165 }
166
167 mac->phydev = phydev;
168 mac->mdio_bus = mdio_bus;
169
170 return 0;
171}
172
173static void hclge_mac_adjust_link(struct net_device *netdev)
174{
175 struct hnae3_handle *h = *((void **)netdev_priv(netdev));
176 struct hclge_vport *vport = hclge_get_vport(h);
177 struct hclge_dev *hdev = vport->back;
178 int duplex, speed;
179 int ret;
180
181 speed = netdev->phydev->speed;
182 duplex = netdev->phydev->duplex;
183
184 ret = hclge_cfg_mac_speed_dup(hdev, speed, duplex);
185 if (ret)
186 netdev_err(netdev, "failed to adjust link.\n");
1770a7a3
PL
187
188 ret = hclge_cfg_flowctrl(hdev);
189 if (ret)
190 netdev_err(netdev, "failed to configure flow control.\n");
256727da
S
191}
192
193int hclge_mac_start_phy(struct hclge_dev *hdev)
194{
195 struct net_device *netdev = hdev->vport[0].nic.netdev;
196 struct phy_device *phydev = hdev->hw.mac.phydev;
197 int ret;
198
199 if (!phydev)
200 return 0;
201
202 ret = phy_connect_direct(netdev, phydev,
203 hclge_mac_adjust_link,
204 PHY_INTERFACE_MODE_SGMII);
205 if (ret) {
206 netdev_err(netdev, "phy_connect_direct err.\n");
207 return ret;
208 }
209
439adf88
FL
210 phydev->supported &= HCLGE_PHY_SUPPORTED_FEATURES;
211 phydev->advertising = phydev->supported;
212
256727da
S
213 phy_start(phydev);
214
215 return 0;
216}
217
218void hclge_mac_stop_phy(struct hclge_dev *hdev)
219{
220 struct net_device *netdev = hdev->vport[0].nic.netdev;
221 struct phy_device *phydev = netdev->phydev;
222
223 if (!phydev)
224 return;
225
226 phy_stop(phydev);
227 phy_disconnect(phydev);
228}