blob: 6d99943f84b23a72b7a7102917bc9695010edd51 [file] [log] [blame]
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001/*
2 * AMD 10Gb Ethernet driver
3 *
4 * This file is available to you under your choice of the following two
5 * licenses:
6 *
7 * License 1: GPLv2
8 *
Lendacky, Thomasced3fca2016-02-17 11:49:28 -06009 * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -050010 *
11 * This file is free software; you may copy, redistribute and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 2 of the License, or (at
14 * your option) any later version.
15 *
16 * This file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 *
24 * This file incorporates work covered by the following copyright and
25 * permission notice:
26 * The Synopsys DWC ETHER XGMAC Software Driver and documentation
27 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,
28 * Inc. unless otherwise expressly agreed to in writing between Synopsys
29 * and you.
30 *
31 * The Software IS NOT an item of Licensed Software or Licensed Product
32 * under any End User Software License Agreement or Agreement for Licensed
33 * Product with Synopsys or any supplement thereto. Permission is hereby
34 * granted, free of charge, to any person obtaining a copy of this software
35 * annotated with this license and the Software, to deal in the Software
36 * without restriction, including without limitation the rights to use,
37 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies
38 * of the Software, and to permit persons to whom the Software is furnished
39 * to do so, subject to the following conditions:
40 *
41 * The above copyright notice and this permission notice shall be included
42 * in all copies or substantial portions of the Software.
43 *
44 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
45 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
54 * THE POSSIBILITY OF SUCH DAMAGE.
55 *
56 *
57 * License 2: Modified BSD
58 *
Lendacky, Thomasced3fca2016-02-17 11:49:28 -060059 * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -050060 * All rights reserved.
61 *
62 * Redistribution and use in source and binary forms, with or without
63 * modification, are permitted provided that the following conditions are met:
64 * * Redistributions of source code must retain the above copyright
65 * notice, this list of conditions and the following disclaimer.
66 * * Redistributions in binary form must reproduce the above copyright
67 * notice, this list of conditions and the following disclaimer in the
68 * documentation and/or other materials provided with the distribution.
69 * * Neither the name of Advanced Micro Devices, Inc. nor the
70 * names of its contributors may be used to endorse or promote products
71 * derived from this software without specific prior written permission.
72 *
73 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
74 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
76 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
77 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
78 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
79 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
80 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
81 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
82 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
83 *
84 * This file incorporates work covered by the following copyright and
85 * permission notice:
86 * The Synopsys DWC ETHER XGMAC Software Driver and documentation
87 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,
88 * Inc. unless otherwise expressly agreed to in writing between Synopsys
89 * and you.
90 *
91 * The Software IS NOT an item of Licensed Software or Licensed Product
92 * under any End User Software License Agreement or Agreement for Licensed
93 * Product with Synopsys or any supplement thereto. Permission is hereby
94 * granted, free of charge, to any person obtaining a copy of this software
95 * annotated with this license and the Software, to deal in the Software
96 * without restriction, including without limitation the rights to use,
97 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies
98 * of the Software, and to permit persons to whom the Software is furnished
99 * to do so, subject to the following conditions:
100 *
101 * The above copyright notice and this permission notice shall be included
102 * in all copies or substantial portions of the Software.
103 *
104 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
105 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
106 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
107 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
108 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
109 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
110 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
111 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
112 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
113 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
114 * THE POSSIBILITY OF SUCH DAMAGE.
115 */
116
117#include <linux/module.h>
118#include <linux/kmod.h>
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500119#include <linux/mdio.h>
120#include <linux/phy.h>
121#include <linux/of.h>
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500122#include <linux/bitops.h>
123#include <linux/jiffies.h>
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500124
125#include "xgbe.h"
126#include "xgbe-common.h"
127
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500128static void xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata)
129{
130 int reg;
131
132 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
133 reg &= ~XGBE_AN_CL37_INT_MASK;
134 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
135}
136
137static void xgbe_an37_disable_interrupts(struct xgbe_prv_data *pdata)
138{
139 int reg;
140
141 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
142 reg &= ~XGBE_AN_CL37_INT_MASK;
143 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
144
145 reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
146 reg &= ~XGBE_PCS_CL37_BP;
147 XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
148}
149
150static void xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata)
151{
152 int reg;
153
154 reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
155 reg |= XGBE_PCS_CL37_BP;
156 XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
157
158 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
159 reg |= XGBE_AN_CL37_INT_MASK;
160 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
161}
162
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500163static void xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata)
164{
165 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
166}
167
168static void xgbe_an73_disable_interrupts(struct xgbe_prv_data *pdata)
169{
170 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
171}
172
173static void xgbe_an73_enable_interrupts(struct xgbe_prv_data *pdata)
174{
175 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK);
176}
177
178static void xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata)
179{
180 switch (pdata->an_mode) {
181 case XGBE_AN_MODE_CL73:
182 xgbe_an73_enable_interrupts(pdata);
183 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500184 case XGBE_AN_MODE_CL37:
185 case XGBE_AN_MODE_CL37_SGMII:
186 xgbe_an37_enable_interrupts(pdata);
187 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500188 default:
189 break;
190 }
191}
192
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500193static void xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata)
194{
195 xgbe_an73_clear_interrupts(pdata);
196 xgbe_an37_clear_interrupts(pdata);
197}
198
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500199static void xgbe_an73_enable_kr_training(struct xgbe_prv_data *pdata)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500200{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500201 unsigned int reg;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500202
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500203 reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500204
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500205 reg |= XGBE_KR_TRAINING_ENABLE;
206 XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500207}
208
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500209static void xgbe_an73_disable_kr_training(struct xgbe_prv_data *pdata)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500210{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500211 unsigned int reg;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500212
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500213 reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500214
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500215 reg &= ~XGBE_KR_TRAINING_ENABLE;
216 XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
217}
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500218
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500219static void xgbe_kr_mode(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500220{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500221 /* Enable KR training */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500222 xgbe_an73_enable_kr_training(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500223
224 /* Set MAC to 10G speed */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500225 pdata->hw_if.set_speed(pdata, SPEED_10000);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500226
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500227 /* Call PHY implementation support to complete rate change */
228 pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500229}
230
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500231static void xgbe_kx_2500_mode(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500232{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500233 /* Disable KR training */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500234 xgbe_an73_disable_kr_training(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500235
236 /* Set MAC to 2.5G speed */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500237 pdata->hw_if.set_speed(pdata, SPEED_2500);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500238
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500239 /* Call PHY implementation support to complete rate change */
240 pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500241}
242
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500243static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500244{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500245 /* Disable KR training */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500246 xgbe_an73_disable_kr_training(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500247
248 /* Set MAC to 1G speed */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500249 pdata->hw_if.set_speed(pdata, SPEED_1000);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500250
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500251 /* Call PHY implementation support to complete rate change */
252 pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500253}
254
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500255static enum xgbe_mode xgbe_cur_mode(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500256{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500257 return pdata->phy_if.phy_impl.cur_mode(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500258}
259
260static bool xgbe_in_kr_mode(struct xgbe_prv_data *pdata)
261{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500262 return (xgbe_cur_mode(pdata) == XGBE_MODE_KR);
263}
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500264
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500265static void xgbe_change_mode(struct xgbe_prv_data *pdata,
266 enum xgbe_mode mode)
267{
268 switch (mode) {
269 case XGBE_MODE_KX_1000:
270 xgbe_kx_1000_mode(pdata);
271 break;
272 case XGBE_MODE_KX_2500:
273 xgbe_kx_2500_mode(pdata);
274 break;
275 case XGBE_MODE_KR:
276 xgbe_kr_mode(pdata);
277 break;
278 case XGBE_MODE_UNKNOWN:
279 break;
280 default:
281 netif_dbg(pdata, link, pdata->netdev,
282 "invalid operation mode requested (%u)\n", mode);
283 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500284}
285
286static void xgbe_switch_mode(struct xgbe_prv_data *pdata)
287{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500288 xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500289}
290
291static void xgbe_set_mode(struct xgbe_prv_data *pdata,
292 enum xgbe_mode mode)
293{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500294 if (mode == xgbe_cur_mode(pdata))
295 return;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500296
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500297 xgbe_change_mode(pdata, mode);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500298}
299
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500300static bool xgbe_use_mode(struct xgbe_prv_data *pdata,
301 enum xgbe_mode mode)
Lendacky, Thomas471e14b2015-05-22 16:32:14 -0500302{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500303 return pdata->phy_if.phy_impl.use_mode(pdata, mode);
Lendacky, Thomas471e14b2015-05-22 16:32:14 -0500304}
305
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500306static void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable,
307 bool restart)
308{
309 unsigned int reg;
310
311 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1);
312 reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE;
313
314 if (enable)
315 reg |= MDIO_VEND2_CTRL1_AN_ENABLE;
316
317 if (restart)
318 reg |= MDIO_VEND2_CTRL1_AN_RESTART;
319
320 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
321}
322
323static void xgbe_an37_restart(struct xgbe_prv_data *pdata)
324{
325 xgbe_an37_enable_interrupts(pdata);
326 xgbe_an37_set(pdata, true, true);
327
328 netif_dbg(pdata, link, pdata->netdev, "CL37 AN enabled/restarted\n");
329}
330
331static void xgbe_an37_disable(struct xgbe_prv_data *pdata)
332{
333 xgbe_an37_set(pdata, false, false);
334 xgbe_an37_disable_interrupts(pdata);
335
336 netif_dbg(pdata, link, pdata->netdev, "CL37 AN disabled\n");
337}
338
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500339static void xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable,
340 bool restart)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500341{
342 unsigned int reg;
343
344 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
345 reg &= ~MDIO_AN_CTRL1_ENABLE;
346
347 if (enable)
348 reg |= MDIO_AN_CTRL1_ENABLE;
349
350 if (restart)
351 reg |= MDIO_AN_CTRL1_RESTART;
352
353 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg);
354}
355
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500356static void xgbe_an73_restart(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500357{
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500358 xgbe_an73_enable_interrupts(pdata);
359 xgbe_an73_set(pdata, true, true);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500360
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500361 netif_dbg(pdata, link, pdata->netdev, "CL73 AN enabled/restarted\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500362}
363
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500364static void xgbe_an73_disable(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500365{
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500366 xgbe_an73_set(pdata, false, false);
367 xgbe_an73_disable_interrupts(pdata);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500368
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500369 netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500370}
371
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500372static void xgbe_an_restart(struct xgbe_prv_data *pdata)
373{
374 switch (pdata->an_mode) {
375 case XGBE_AN_MODE_CL73:
376 xgbe_an73_restart(pdata);
377 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500378 case XGBE_AN_MODE_CL37:
379 case XGBE_AN_MODE_CL37_SGMII:
380 xgbe_an37_restart(pdata);
381 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500382 default:
383 break;
384 }
385}
386
387static void xgbe_an_disable(struct xgbe_prv_data *pdata)
388{
389 switch (pdata->an_mode) {
390 case XGBE_AN_MODE_CL73:
391 xgbe_an73_disable(pdata);
392 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500393 case XGBE_AN_MODE_CL37:
394 case XGBE_AN_MODE_CL37_SGMII:
395 xgbe_an37_disable(pdata);
396 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500397 default:
398 break;
399 }
400}
401
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500402static void xgbe_an_disable_all(struct xgbe_prv_data *pdata)
403{
404 xgbe_an73_disable(pdata);
405 xgbe_an37_disable(pdata);
406}
407
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500408static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
409 enum xgbe_rx *state)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500410{
411 unsigned int ad_reg, lp_reg, reg;
412
413 *state = XGBE_RX_COMPLETE;
414
415 /* If we're not in KR mode then we're done */
416 if (!xgbe_in_kr_mode(pdata))
417 return XGBE_AN_PAGE_RECEIVED;
418
419 /* Enable/Disable FEC */
420 ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
421 lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
422
423 reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL);
424 reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE);
425 if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
426 reg |= pdata->fec_ability;
427
428 XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg);
429
430 /* Start KR training */
431 reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
432 if (reg & XGBE_KR_TRAINING_ENABLE) {
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500433 if (pdata->phy_if.phy_impl.kr_training_pre)
434 pdata->phy_if.phy_impl.kr_training_pre(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500435
436 reg |= XGBE_KR_TRAINING_START;
437 XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
438 reg);
439
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500440 if (pdata->phy_if.phy_impl.kr_training_post)
441 pdata->phy_if.phy_impl.kr_training_post(pdata);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500442
443 netif_dbg(pdata, link, pdata->netdev,
444 "KR training initiated\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500445 }
446
447 return XGBE_AN_PAGE_RECEIVED;
448}
449
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500450static enum xgbe_an xgbe_an73_tx_xnp(struct xgbe_prv_data *pdata,
451 enum xgbe_rx *state)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500452{
453 u16 msg;
454
455 *state = XGBE_RX_XNP;
456
457 msg = XGBE_XNP_MCF_NULL_MESSAGE;
458 msg |= XGBE_XNP_MP_FORMATTED;
459
460 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0);
461 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
462 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg);
463
464 return XGBE_AN_PAGE_RECEIVED;
465}
466
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500467static enum xgbe_an xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata,
468 enum xgbe_rx *state)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500469{
470 unsigned int link_support;
471 unsigned int reg, ad_reg, lp_reg;
472
473 /* Read Base Ability register 2 first */
474 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
475
476 /* Check for a supported mode, otherwise restart in a different one */
477 link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20;
478 if (!(reg & link_support))
479 return XGBE_AN_INCOMPAT_LINK;
480
481 /* Check Extended Next Page support */
482 ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
483 lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
484
485 return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
486 (lp_reg & XGBE_XNP_NP_EXCHANGE))
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500487 ? xgbe_an73_tx_xnp(pdata, state)
488 : xgbe_an73_tx_training(pdata, state);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500489}
490
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500491static enum xgbe_an xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata,
492 enum xgbe_rx *state)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500493{
494 unsigned int ad_reg, lp_reg;
495
496 /* Check Extended Next Page support */
497 ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP);
498 lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX);
499
500 return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
501 (lp_reg & XGBE_XNP_NP_EXCHANGE))
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500502 ? xgbe_an73_tx_xnp(pdata, state)
503 : xgbe_an73_tx_training(pdata, state);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500504}
505
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500506static enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500507{
508 enum xgbe_rx *state;
509 unsigned long an_timeout;
510 enum xgbe_an ret;
511
512 if (!pdata->an_start) {
513 pdata->an_start = jiffies;
514 } else {
515 an_timeout = pdata->an_start +
516 msecs_to_jiffies(XGBE_AN_MS_TIMEOUT);
517 if (time_after(jiffies, an_timeout)) {
518 /* Auto-negotiation timed out, reset state */
519 pdata->kr_state = XGBE_RX_BPA;
520 pdata->kx_state = XGBE_RX_BPA;
521
522 pdata->an_start = jiffies;
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500523
524 netif_dbg(pdata, link, pdata->netdev,
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500525 "CL73 AN timed out, resetting state\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500526 }
527 }
528
529 state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500530 : &pdata->kx_state;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500531
532 switch (*state) {
533 case XGBE_RX_BPA:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500534 ret = xgbe_an73_rx_bpa(pdata, state);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500535 break;
536
537 case XGBE_RX_XNP:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500538 ret = xgbe_an73_rx_xnp(pdata, state);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500539 break;
540
541 default:
542 ret = XGBE_AN_ERROR;
543 }
544
545 return ret;
546}
547
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500548static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500549{
550 /* Be sure we aren't looping trying to negotiate */
551 if (xgbe_in_kr_mode(pdata)) {
552 pdata->kr_state = XGBE_RX_ERROR;
553
554 if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) &&
555 !(pdata->phy.advertising & ADVERTISED_2500baseX_Full))
556 return XGBE_AN_NO_LINK;
557
558 if (pdata->kx_state != XGBE_RX_BPA)
559 return XGBE_AN_NO_LINK;
560 } else {
561 pdata->kx_state = XGBE_RX_ERROR;
562
563 if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full))
564 return XGBE_AN_NO_LINK;
565
566 if (pdata->kr_state != XGBE_RX_BPA)
567 return XGBE_AN_NO_LINK;
568 }
569
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500570 xgbe_an73_disable(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500571
572 xgbe_switch_mode(pdata);
573
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500574 xgbe_an73_restart(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500575
576 return XGBE_AN_INCOMPAT_LINK;
577}
578
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500579static void xgbe_an37_isr(struct xgbe_prv_data *pdata)
580{
581 unsigned int reg;
582
583 /* Disable AN interrupts */
584 xgbe_an37_disable_interrupts(pdata);
585
586 /* Save the interrupt(s) that fired */
587 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
588 pdata->an_int = reg & XGBE_AN_CL37_INT_MASK;
589 pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK;
590
591 if (pdata->an_int) {
592 /* Clear the interrupt(s) that fired and process them */
593 reg &= ~XGBE_AN_CL37_INT_MASK;
594 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
595
596 queue_work(pdata->an_workqueue, &pdata->an_irq_work);
597 } else {
598 /* Enable AN interrupts */
599 xgbe_an37_enable_interrupts(pdata);
600 }
601}
602
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500603static void xgbe_an73_isr(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500604{
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600605 /* Disable AN interrupts */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500606 xgbe_an73_disable_interrupts(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500607
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600608 /* Save the interrupt(s) that fired */
609 pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
610
611 if (pdata->an_int) {
612 /* Clear the interrupt(s) that fired and process them */
613 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int);
614
615 queue_work(pdata->an_workqueue, &pdata->an_irq_work);
616 } else {
617 /* Enable AN interrupts */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500618 xgbe_an73_enable_interrupts(pdata);
619 }
620}
621
622static irqreturn_t xgbe_an_isr(int irq, void *data)
623{
624 struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
625
626 netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n");
627
628 switch (pdata->an_mode) {
629 case XGBE_AN_MODE_CL73:
630 xgbe_an73_isr(pdata);
631 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500632 case XGBE_AN_MODE_CL37:
633 case XGBE_AN_MODE_CL37_SGMII:
634 xgbe_an37_isr(pdata);
635 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500636 default:
637 break;
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600638 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500639
640 return IRQ_HANDLED;
641}
642
Lendacky, Thomas47f164d2016-11-10 17:09:55 -0600643static irqreturn_t xgbe_an_combined_isr(int irq, struct xgbe_prv_data *pdata)
644{
645 return xgbe_an_isr(irq, pdata);
646}
647
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500648static void xgbe_an_irq_work(struct work_struct *work)
649{
650 struct xgbe_prv_data *pdata = container_of(work,
651 struct xgbe_prv_data,
652 an_irq_work);
653
654 /* Avoid a race between enabling the IRQ and exiting the work by
655 * waiting for the work to finish and then queueing it
656 */
657 flush_work(&pdata->an_work);
658 queue_work(pdata->an_workqueue, &pdata->an_work);
659}
660
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500661static const char *xgbe_state_as_string(enum xgbe_an state)
662{
663 switch (state) {
664 case XGBE_AN_READY:
665 return "Ready";
666 case XGBE_AN_PAGE_RECEIVED:
667 return "Page-Received";
668 case XGBE_AN_INCOMPAT_LINK:
669 return "Incompatible-Link";
670 case XGBE_AN_COMPLETE:
671 return "Complete";
672 case XGBE_AN_NO_LINK:
673 return "No-Link";
674 case XGBE_AN_ERROR:
675 return "Error";
676 default:
677 return "Undefined";
678 }
679}
680
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500681static void xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
682{
683 enum xgbe_an cur_state = pdata->an_state;
684
685 if (!pdata->an_int)
686 return;
687
688 if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) {
689 pdata->an_state = XGBE_AN_COMPLETE;
690 pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT;
691
692 /* If SGMII is enabled, check the link status */
693 if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) &&
694 !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS))
695 pdata->an_state = XGBE_AN_NO_LINK;
696 }
697
698 netif_dbg(pdata, link, pdata->netdev, "CL37 AN %s\n",
699 xgbe_state_as_string(pdata->an_state));
700
701 cur_state = pdata->an_state;
702
703 switch (pdata->an_state) {
704 case XGBE_AN_READY:
705 break;
706
707 case XGBE_AN_COMPLETE:
708 netif_dbg(pdata, link, pdata->netdev,
709 "Auto negotiation successful\n");
710 break;
711
712 case XGBE_AN_NO_LINK:
713 break;
714
715 default:
716 pdata->an_state = XGBE_AN_ERROR;
717 }
718
719 if (pdata->an_state == XGBE_AN_ERROR) {
720 netdev_err(pdata->netdev,
721 "error during auto-negotiation, state=%u\n",
722 cur_state);
723
724 pdata->an_int = 0;
725 xgbe_an37_clear_interrupts(pdata);
726 }
727
728 if (pdata->an_state >= XGBE_AN_COMPLETE) {
729 pdata->an_result = pdata->an_state;
730 pdata->an_state = XGBE_AN_READY;
731
732 netif_dbg(pdata, link, pdata->netdev, "CL37 AN result: %s\n",
733 xgbe_state_as_string(pdata->an_result));
734 }
735
736 xgbe_an37_enable_interrupts(pdata);
737}
738
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500739static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500740{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500741 enum xgbe_an cur_state = pdata->an_state;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500742
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600743 if (!pdata->an_int)
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500744 return;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500745
746next_int:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500747 if (pdata->an_int & XGBE_AN_CL73_PG_RCV) {
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500748 pdata->an_state = XGBE_AN_PAGE_RECEIVED;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500749 pdata->an_int &= ~XGBE_AN_CL73_PG_RCV;
750 } else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) {
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500751 pdata->an_state = XGBE_AN_INCOMPAT_LINK;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500752 pdata->an_int &= ~XGBE_AN_CL73_INC_LINK;
753 } else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) {
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500754 pdata->an_state = XGBE_AN_COMPLETE;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500755 pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500756 } else {
757 pdata->an_state = XGBE_AN_ERROR;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500758 }
759
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500760again:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500761 netif_dbg(pdata, link, pdata->netdev, "CL73 AN %s\n",
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500762 xgbe_state_as_string(pdata->an_state));
763
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500764 cur_state = pdata->an_state;
765
766 switch (pdata->an_state) {
767 case XGBE_AN_READY:
768 pdata->an_supported = 0;
769 break;
770
771 case XGBE_AN_PAGE_RECEIVED:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500772 pdata->an_state = xgbe_an73_page_received(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500773 pdata->an_supported++;
774 break;
775
776 case XGBE_AN_INCOMPAT_LINK:
777 pdata->an_supported = 0;
778 pdata->parallel_detect = 0;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500779 pdata->an_state = xgbe_an73_incompat_link(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500780 break;
781
782 case XGBE_AN_COMPLETE:
783 pdata->parallel_detect = pdata->an_supported ? 0 : 1;
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500784 netif_dbg(pdata, link, pdata->netdev, "%s successful\n",
785 pdata->an_supported ? "Auto negotiation"
786 : "Parallel detection");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500787 break;
788
789 case XGBE_AN_NO_LINK:
790 break;
791
792 default:
793 pdata->an_state = XGBE_AN_ERROR;
794 }
795
796 if (pdata->an_state == XGBE_AN_NO_LINK) {
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600797 pdata->an_int = 0;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500798 xgbe_an73_clear_interrupts(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500799 } else if (pdata->an_state == XGBE_AN_ERROR) {
800 netdev_err(pdata->netdev,
801 "error during auto-negotiation, state=%u\n",
802 cur_state);
803
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600804 pdata->an_int = 0;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500805 xgbe_an73_clear_interrupts(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500806 }
807
808 if (pdata->an_state >= XGBE_AN_COMPLETE) {
809 pdata->an_result = pdata->an_state;
810 pdata->an_state = XGBE_AN_READY;
811 pdata->kr_state = XGBE_RX_BPA;
812 pdata->kx_state = XGBE_RX_BPA;
813 pdata->an_start = 0;
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500814
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500815 netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n",
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500816 xgbe_state_as_string(pdata->an_result));
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500817 }
818
819 if (cur_state != pdata->an_state)
820 goto again;
821
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600822 if (pdata->an_int)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500823 goto next_int;
824
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500825 xgbe_an73_enable_interrupts(pdata);
826}
827
828static void xgbe_an_state_machine(struct work_struct *work)
829{
830 struct xgbe_prv_data *pdata = container_of(work,
831 struct xgbe_prv_data,
832 an_work);
833
834 mutex_lock(&pdata->an_mutex);
835
836 switch (pdata->an_mode) {
837 case XGBE_AN_MODE_CL73:
838 xgbe_an73_state_machine(pdata);
839 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500840 case XGBE_AN_MODE_CL37:
841 case XGBE_AN_MODE_CL37_SGMII:
842 xgbe_an37_state_machine(pdata);
843 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500844 default:
845 break;
846 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500847
848 mutex_unlock(&pdata->an_mutex);
849}
850
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500851static void xgbe_an37_init(struct xgbe_prv_data *pdata)
852{
853 unsigned int reg;
854
855 /* Set up Advertisement register */
856 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
857 if (pdata->phy.advertising & ADVERTISED_Pause)
858 reg |= 0x100;
859 else
860 reg &= ~0x100;
861
862 if (pdata->phy.advertising & ADVERTISED_Asym_Pause)
863 reg |= 0x80;
864 else
865 reg &= ~0x80;
866
867 /* Full duplex, but not half */
868 reg |= XGBE_AN_CL37_FD_MASK;
869 reg &= ~XGBE_AN_CL37_HD_MASK;
870
871 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg);
872
873 /* Set up the Control register */
874 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
875 reg &= XGBE_AN_CL37_TX_CONFIG_MASK;
876 reg &= XGBE_AN_CL37_PCS_MODE_MASK;
877
878 switch (pdata->an_mode) {
879 case XGBE_AN_MODE_CL37:
880 reg |= XGBE_AN_CL37_PCS_MODE_BASEX;
881 break;
882 case XGBE_AN_MODE_CL37_SGMII:
883 reg |= XGBE_AN_CL37_PCS_MODE_SGMII;
884 break;
885 default:
886 break;
887 }
888
889 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
890
891 netif_dbg(pdata, link, pdata->netdev, "CL37 AN (%s) initialized\n",
892 (pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII");
893}
894
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500895static void xgbe_an73_init(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500896{
897 unsigned int reg;
898
899 /* Set up Advertisement register 3 first */
900 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
901 if (pdata->phy.advertising & ADVERTISED_10000baseR_FEC)
902 reg |= 0xc000;
903 else
904 reg &= ~0xc000;
905
906 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg);
907
908 /* Set up Advertisement register 2 next */
909 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
910 if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
911 reg |= 0x80;
912 else
913 reg &= ~0x80;
914
915 if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) ||
916 (pdata->phy.advertising & ADVERTISED_2500baseX_Full))
917 reg |= 0x20;
918 else
919 reg &= ~0x20;
920
921 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg);
922
923 /* Set up Advertisement register 1 last */
924 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
925 if (pdata->phy.advertising & ADVERTISED_Pause)
926 reg |= 0x400;
927 else
928 reg &= ~0x400;
929
930 if (pdata->phy.advertising & ADVERTISED_Asym_Pause)
931 reg |= 0x800;
932 else
933 reg &= ~0x800;
934
935 /* We don't intend to perform XNP */
936 reg &= ~XGBE_XNP_NP_EXCHANGE;
937
938 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500939
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500940 netif_dbg(pdata, link, pdata->netdev, "CL73 AN initialized\n");
941}
942
943static void xgbe_an_init(struct xgbe_prv_data *pdata)
944{
945 /* Set up advertisement registers based on current settings */
946 pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata);
947 switch (pdata->an_mode) {
948 case XGBE_AN_MODE_CL73:
949 xgbe_an73_init(pdata);
950 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500951 case XGBE_AN_MODE_CL37:
952 case XGBE_AN_MODE_CL37_SGMII:
953 xgbe_an37_init(pdata);
954 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500955 default:
956 break;
957 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500958}
959
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -0500960static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
961{
962 if (pdata->tx_pause && pdata->rx_pause)
963 return "rx/tx";
964 else if (pdata->rx_pause)
965 return "rx";
966 else if (pdata->tx_pause)
967 return "tx";
968 else
969 return "off";
970}
971
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500972static const char *xgbe_phy_speed_string(int speed)
973{
974 switch (speed) {
975 case SPEED_1000:
976 return "1Gbps";
977 case SPEED_2500:
978 return "2.5Gbps";
979 case SPEED_10000:
980 return "10Gbps";
981 case SPEED_UNKNOWN:
982 return "Unknown";
983 default:
984 return "Unsupported";
985 }
986}
987
988static void xgbe_phy_print_status(struct xgbe_prv_data *pdata)
989{
990 if (pdata->phy.link)
991 netdev_info(pdata->netdev,
992 "Link is Up - %s/%s - flow control %s\n",
993 xgbe_phy_speed_string(pdata->phy.speed),
994 pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -0500995 xgbe_phy_fc_string(pdata));
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500996 else
997 netdev_info(pdata->netdev, "Link is Down\n");
998}
999
1000static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
1001{
1002 int new_state = 0;
1003
1004 if (pdata->phy.link) {
1005 /* Flow control support */
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001006 pdata->pause_autoneg = pdata->phy.pause_autoneg;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001007
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001008 if (pdata->tx_pause != pdata->phy.tx_pause) {
1009 new_state = 1;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001010 pdata->hw_if.config_tx_flow_control(pdata);
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001011 pdata->tx_pause = pdata->phy.tx_pause;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001012 }
1013
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001014 if (pdata->rx_pause != pdata->phy.rx_pause) {
1015 new_state = 1;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001016 pdata->hw_if.config_rx_flow_control(pdata);
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001017 pdata->rx_pause = pdata->phy.rx_pause;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001018 }
1019
1020 /* Speed support */
1021 if (pdata->phy_speed != pdata->phy.speed) {
1022 new_state = 1;
1023 pdata->phy_speed = pdata->phy.speed;
1024 }
1025
1026 if (pdata->phy_link != pdata->phy.link) {
1027 new_state = 1;
1028 pdata->phy_link = pdata->phy.link;
1029 }
1030 } else if (pdata->phy_link) {
1031 new_state = 1;
1032 pdata->phy_link = 0;
1033 pdata->phy_speed = SPEED_UNKNOWN;
1034 }
1035
1036 if (new_state && netif_msg_link(pdata))
1037 xgbe_phy_print_status(pdata);
1038}
1039
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001040static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
1041{
1042 return pdata->phy_if.phy_impl.valid_speed(pdata, speed);
1043}
1044
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001045static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
1046{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001047 enum xgbe_mode mode;
1048
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001049 netif_dbg(pdata, link, pdata->netdev, "fixed PHY configuration\n");
1050
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001051 /* Disable auto-negotiation */
Lendacky, Thomasa64def42016-11-03 13:18:38 -05001052 xgbe_an_disable(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001053
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001054 /* Set specified mode for specified speed */
1055 mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed);
1056 switch (mode) {
1057 case XGBE_MODE_KX_1000:
1058 case XGBE_MODE_KX_2500:
1059 case XGBE_MODE_KR:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001060 break;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001061 case XGBE_MODE_UNKNOWN:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001062 default:
1063 return -EINVAL;
1064 }
1065
1066 /* Validate duplex mode */
1067 if (pdata->phy.duplex != DUPLEX_FULL)
1068 return -EINVAL;
1069
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001070 xgbe_set_mode(pdata, mode);
1071
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001072 return 0;
1073}
1074
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001075static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
1076{
1077 set_bit(XGBE_LINK_INIT, &pdata->dev_state);
1078 pdata->link_check = jiffies;
1079
1080 if (pdata->phy.autoneg != AUTONEG_ENABLE)
1081 return xgbe_phy_config_fixed(pdata);
1082
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001083 netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n");
1084
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001085 /* Disable auto-negotiation interrupt */
1086 disable_irq(pdata->an_irq);
1087
1088 /* Start auto-negotiation in a supported mode */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001089 if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001090 xgbe_set_mode(pdata, XGBE_MODE_KR);
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001091 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
1092 xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
1093 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
1094 xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001095 } else {
1096 enable_irq(pdata->an_irq);
1097 return -EINVAL;
1098 }
1099
1100 /* Disable and stop any in progress auto-negotiation */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001101 xgbe_an_disable_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001102
1103 /* Clear any auto-negotitation interrupts */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001104 xgbe_an_clear_interrupts_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001105
1106 pdata->an_result = XGBE_AN_READY;
1107 pdata->an_state = XGBE_AN_READY;
1108 pdata->kr_state = XGBE_RX_BPA;
1109 pdata->kx_state = XGBE_RX_BPA;
1110
1111 /* Re-enable auto-negotiation interrupt */
1112 enable_irq(pdata->an_irq);
1113
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001114 xgbe_an_init(pdata);
Lendacky, Thomasa64def42016-11-03 13:18:38 -05001115 xgbe_an_restart(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001116
1117 return 0;
1118}
1119
1120static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
1121{
1122 int ret;
1123
1124 mutex_lock(&pdata->an_mutex);
1125
1126 ret = __xgbe_phy_config_aneg(pdata);
1127 if (ret)
1128 set_bit(XGBE_LINK_ERR, &pdata->dev_state);
1129 else
1130 clear_bit(XGBE_LINK_ERR, &pdata->dev_state);
1131
1132 mutex_unlock(&pdata->an_mutex);
1133
1134 return ret;
1135}
1136
1137static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
1138{
1139 return (pdata->an_result == XGBE_AN_COMPLETE);
1140}
1141
1142static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
1143{
1144 unsigned long link_timeout;
1145
1146 link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001147 if (time_after(jiffies, link_timeout)) {
1148 netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001149 xgbe_phy_config_aneg(pdata);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001150 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001151}
1152
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001153static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001154{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001155 return pdata->phy_if.phy_impl.an_outcome(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001156}
1157
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001158static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001159{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001160 enum xgbe_mode mode;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001161
1162 pdata->phy.lp_advertising = 0;
1163
1164 if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001165 mode = xgbe_cur_mode(pdata);
1166 else
1167 mode = xgbe_phy_status_aneg(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001168
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001169 switch (mode) {
1170 case XGBE_MODE_KX_1000:
1171 pdata->phy.speed = SPEED_1000;
1172 break;
1173 case XGBE_MODE_KX_2500:
1174 pdata->phy.speed = SPEED_2500;
1175 break;
1176 case XGBE_MODE_KR:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001177 pdata->phy.speed = SPEED_10000;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001178 break;
1179 case XGBE_MODE_UNKNOWN:
1180 default:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001181 pdata->phy.speed = SPEED_UNKNOWN;
1182 }
1183
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001184 pdata->phy.duplex = DUPLEX_FULL;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001185
1186 xgbe_set_mode(pdata, mode);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001187}
1188
1189static void xgbe_phy_status(struct xgbe_prv_data *pdata)
1190{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001191 unsigned int link_aneg;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001192
1193 if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
Lendacky, Thomas50789845c2015-09-30 08:53:22 -05001194 netif_carrier_off(pdata->netdev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001195
1196 pdata->phy.link = 0;
1197 goto adjust_link;
1198 }
1199
1200 link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE);
1201
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001202 pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001203 if (pdata->phy.link) {
1204 if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
1205 xgbe_check_link_timeout(pdata);
1206 return;
1207 }
1208
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001209 xgbe_phy_status_result(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001210
1211 if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
1212 clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
1213
Lendacky, Thomas50789845c2015-09-30 08:53:22 -05001214 netif_carrier_on(pdata->netdev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001215 } else {
1216 if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
1217 xgbe_check_link_timeout(pdata);
1218
1219 if (link_aneg)
1220 return;
1221 }
1222
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001223 xgbe_phy_status_result(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001224
Lendacky, Thomas50789845c2015-09-30 08:53:22 -05001225 netif_carrier_off(pdata->netdev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001226 }
1227
1228adjust_link:
1229 xgbe_phy_adjust_link(pdata);
1230}
1231
1232static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
1233{
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001234 netif_dbg(pdata, link, pdata->netdev, "stopping PHY\n");
1235
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001236 if (!pdata->phy_started)
1237 return;
1238
1239 /* Indicate the PHY is down */
1240 pdata->phy_started = 0;
1241
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001242 /* Disable auto-negotiation */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001243 xgbe_an_disable_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001244
Lendacky, Thomas47f164d2016-11-10 17:09:55 -06001245 if (pdata->dev_irq != pdata->an_irq)
1246 devm_free_irq(pdata->dev, pdata->an_irq, pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001247
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001248 pdata->phy_if.phy_impl.stop(pdata);
1249
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001250 pdata->phy.link = 0;
Lendacky, Thomas50789845c2015-09-30 08:53:22 -05001251 netif_carrier_off(pdata->netdev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001252
1253 xgbe_phy_adjust_link(pdata);
1254}
1255
1256static int xgbe_phy_start(struct xgbe_prv_data *pdata)
1257{
1258 struct net_device *netdev = pdata->netdev;
1259 int ret;
1260
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001261 netif_dbg(pdata, link, pdata->netdev, "starting PHY\n");
1262
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001263 ret = pdata->phy_if.phy_impl.start(pdata);
1264 if (ret)
1265 return ret;
1266
Lendacky, Thomas47f164d2016-11-10 17:09:55 -06001267 /* If we have a separate AN irq, enable it */
1268 if (pdata->dev_irq != pdata->an_irq) {
1269 ret = devm_request_irq(pdata->dev, pdata->an_irq,
1270 xgbe_an_isr, 0, pdata->an_name,
1271 pdata);
1272 if (ret) {
1273 netdev_err(netdev, "phy irq request failed\n");
1274 goto err_stop;
1275 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001276 }
1277
1278 /* Set initial mode - call the mode setting routines
1279 * directly to insure we are properly configured
1280 */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001281 if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
1282 xgbe_kr_mode(pdata);
1283 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
1284 xgbe_kx_2500_mode(pdata);
1285 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
1286 xgbe_kx_1000_mode(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001287 } else {
1288 ret = -EINVAL;
1289 goto err_irq;
1290 }
1291
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001292 /* Indicate the PHY is up and running */
1293 pdata->phy_started = 1;
1294
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001295 xgbe_an_init(pdata);
Lendacky, Thomasa64def42016-11-03 13:18:38 -05001296 xgbe_an_enable_interrupts(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001297
1298 return xgbe_phy_config_aneg(pdata);
1299
1300err_irq:
Lendacky, Thomas47f164d2016-11-10 17:09:55 -06001301 if (pdata->dev_irq != pdata->an_irq)
1302 devm_free_irq(pdata->dev, pdata->an_irq, pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001303
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001304err_stop:
1305 pdata->phy_if.phy_impl.stop(pdata);
1306
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001307 return ret;
1308}
1309
1310static int xgbe_phy_reset(struct xgbe_prv_data *pdata)
1311{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001312 int ret;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001313
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001314 ret = pdata->phy_if.phy_impl.reset(pdata);
1315 if (ret)
1316 return ret;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001317
1318 /* Disable auto-negotiation for now */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001319 xgbe_an_disable_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001320
1321 /* Clear auto-negotiation interrupts */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001322 xgbe_an_clear_interrupts_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001323
1324 return 0;
1325}
1326
1327static void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001328{
1329 struct device *dev = pdata->dev;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001330
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001331 dev_dbg(dev, "\n************* PHY Reg dump **********************\n");
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001332
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001333 dev_dbg(dev, "PCS Control Reg (%#06x) = %#06x\n", MDIO_CTRL1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001334 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001335 dev_dbg(dev, "PCS Status Reg (%#06x) = %#06x\n", MDIO_STAT1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001336 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001337 dev_dbg(dev, "Phy Id (PHYS ID 1 %#06x)= %#06x\n", MDIO_DEVID1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001338 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001339 dev_dbg(dev, "Phy Id (PHYS ID 2 %#06x)= %#06x\n", MDIO_DEVID2,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001340 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID2));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001341 dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001342 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001343 dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS2,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001344 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS2));
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001345
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001346 dev_dbg(dev, "Auto-Neg Control Reg (%#06x) = %#06x\n", MDIO_CTRL1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001347 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001348 dev_dbg(dev, "Auto-Neg Status Reg (%#06x) = %#06x\n", MDIO_STAT1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001349 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_STAT1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001350 dev_dbg(dev, "Auto-Neg Ad Reg 1 (%#06x) = %#06x\n",
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001351 MDIO_AN_ADVERTISE,
1352 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001353 dev_dbg(dev, "Auto-Neg Ad Reg 2 (%#06x) = %#06x\n",
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001354 MDIO_AN_ADVERTISE + 1,
1355 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001356 dev_dbg(dev, "Auto-Neg Ad Reg 3 (%#06x) = %#06x\n",
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001357 MDIO_AN_ADVERTISE + 2,
1358 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001359 dev_dbg(dev, "Auto-Neg Completion Reg (%#06x) = %#06x\n",
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001360 MDIO_AN_COMP_STAT,
1361 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_COMP_STAT));
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001362
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001363 dev_dbg(dev, "\n*************************************************\n");
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001364}
1365
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001366static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001367{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001368 if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
1369 return SPEED_10000;
1370 else if (pdata->phy.advertising & ADVERTISED_2500baseX_Full)
1371 return SPEED_2500;
1372 else if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full)
1373 return SPEED_1000;
1374
1375 return SPEED_UNKNOWN;
1376}
1377
1378static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
1379{
1380 xgbe_phy_stop(pdata);
1381
1382 pdata->phy_if.phy_impl.exit(pdata);
1383}
1384
1385static int xgbe_phy_init(struct xgbe_prv_data *pdata)
1386{
1387 int ret;
1388
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001389 mutex_init(&pdata->an_mutex);
1390 INIT_WORK(&pdata->an_irq_work, xgbe_an_irq_work);
1391 INIT_WORK(&pdata->an_work, xgbe_an_state_machine);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001392 pdata->mdio_mmd = MDIO_MMD_PCS;
1393
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001394 /* Check for FEC support */
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001395 pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD,
1396 MDIO_PMA_10GBR_FECABLE);
1397 pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE |
1398 MDIO_PMA_10GBR_FECABLE_ERRABLE);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001399
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001400 /* Setup the phy (including supported features) */
1401 ret = pdata->phy_if.phy_impl.init(pdata);
1402 if (ret)
1403 return ret;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001404 pdata->phy.advertising = pdata->phy.supported;
1405
1406 pdata->phy.address = 0;
1407
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001408 if (pdata->phy.advertising & ADVERTISED_Autoneg) {
1409 pdata->phy.autoneg = AUTONEG_ENABLE;
1410 pdata->phy.speed = SPEED_UNKNOWN;
1411 pdata->phy.duplex = DUPLEX_UNKNOWN;
1412 } else {
1413 pdata->phy.autoneg = AUTONEG_DISABLE;
1414 pdata->phy.speed = xgbe_phy_best_advertised_speed(pdata);
1415 pdata->phy.duplex = DUPLEX_FULL;
1416 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001417
1418 pdata->phy.link = 0;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001419
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001420 pdata->phy.pause_autoneg = pdata->pause_autoneg;
1421 pdata->phy.tx_pause = pdata->tx_pause;
1422 pdata->phy.rx_pause = pdata->rx_pause;
1423
1424 /* Fix up Flow Control advertising */
1425 pdata->phy.advertising &= ~ADVERTISED_Pause;
1426 pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
1427
1428 if (pdata->rx_pause) {
1429 pdata->phy.advertising |= ADVERTISED_Pause;
1430 pdata->phy.advertising |= ADVERTISED_Asym_Pause;
1431 }
1432
1433 if (pdata->tx_pause)
1434 pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
1435
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001436 if (netif_msg_drv(pdata))
1437 xgbe_dump_phy_registers(pdata);
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001438
1439 return 0;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001440}
1441
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001442void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001443{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001444 phy_if->phy_init = xgbe_phy_init;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001445 phy_if->phy_exit = xgbe_phy_exit;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001446
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001447 phy_if->phy_reset = xgbe_phy_reset;
1448 phy_if->phy_start = xgbe_phy_start;
1449 phy_if->phy_stop = xgbe_phy_stop;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001450
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001451 phy_if->phy_status = xgbe_phy_status;
1452 phy_if->phy_config_aneg = xgbe_phy_config_aneg;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001453
1454 phy_if->phy_valid_speed = xgbe_phy_valid_speed;
Lendacky, Thomas47f164d2016-11-10 17:09:55 -06001455
1456 phy_if->an_isr = xgbe_an_combined_isr;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001457}