]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blob - drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-eoan-kernel.git] / drivers / net / ethernet / hisilicon / hns3 / hns3pf / hclge_mdio.c
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 SUPPORTED_Pause | \
20 SUPPORTED_Asym_Pause | \
21 PHY_10BT_FEATURES | \
22 PHY_100BT_FEATURES | \
23 PHY_1000BT_FEATURES)
24
25 enum 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
44 struct 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
55 static 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
91 static 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
130 int 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);
161 if (!phydev) {
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
173 static 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");
187
188 ret = hclge_cfg_flowctrl(hdev);
189 if (ret)
190 netdev_err(netdev, "failed to configure flow control.\n");
191 }
192
193 int 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
210 phydev->supported &= HCLGE_PHY_SUPPORTED_FEATURES;
211 phydev->advertising = phydev->supported;
212
213 phy_start(phydev);
214
215 return 0;
216 }
217
218 void 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 }