diff options
Diffstat (limited to 'drivers/net/phy/amd-xgbe-phy.c')
-rw-r--r-- | drivers/net/phy/amd-xgbe-phy.c | 981 |
1 files changed, 634 insertions, 347 deletions
diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 903dc3dc9ea7..9e3af54c9010 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <linux/interrupt.h> | 60 | #include <linux/interrupt.h> |
61 | #include <linux/init.h> | 61 | #include <linux/init.h> |
62 | #include <linux/delay.h> | 62 | #include <linux/delay.h> |
63 | #include <linux/workqueue.h> | ||
63 | #include <linux/netdevice.h> | 64 | #include <linux/netdevice.h> |
64 | #include <linux/etherdevice.h> | 65 | #include <linux/etherdevice.h> |
65 | #include <linux/skbuff.h> | 66 | #include <linux/skbuff.h> |
@@ -74,6 +75,9 @@ | |||
74 | #include <linux/of_platform.h> | 75 | #include <linux/of_platform.h> |
75 | #include <linux/of_device.h> | 76 | #include <linux/of_device.h> |
76 | #include <linux/uaccess.h> | 77 | #include <linux/uaccess.h> |
78 | #include <linux/bitops.h> | ||
79 | #include <linux/property.h> | ||
80 | #include <linux/acpi.h> | ||
77 | 81 | ||
78 | MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>"); | 82 | MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>"); |
79 | MODULE_LICENSE("Dual BSD/GPL"); | 83 | MODULE_LICENSE("Dual BSD/GPL"); |
@@ -84,22 +88,43 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); | |||
84 | #define XGBE_PHY_MASK 0xfffffff0 | 88 | #define XGBE_PHY_MASK 0xfffffff0 |
85 | 89 | ||
86 | #define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set" | 90 | #define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set" |
91 | #define XGBE_PHY_BLWC_PROPERTY "amd,serdes-blwc" | ||
92 | #define XGBE_PHY_CDR_RATE_PROPERTY "amd,serdes-cdr-rate" | ||
93 | #define XGBE_PHY_PQ_SKEW_PROPERTY "amd,serdes-pq-skew" | ||
94 | #define XGBE_PHY_TX_AMP_PROPERTY "amd,serdes-tx-amp" | ||
95 | |||
96 | #define XGBE_PHY_SPEEDS 3 | ||
97 | #define XGBE_PHY_SPEED_1000 0 | ||
98 | #define XGBE_PHY_SPEED_2500 1 | ||
99 | #define XGBE_PHY_SPEED_10000 2 | ||
87 | 100 | ||
88 | #define XGBE_AN_INT_CMPLT 0x01 | 101 | #define XGBE_AN_INT_CMPLT 0x01 |
89 | #define XGBE_AN_INC_LINK 0x02 | 102 | #define XGBE_AN_INC_LINK 0x02 |
90 | #define XGBE_AN_PG_RCV 0x04 | 103 | #define XGBE_AN_PG_RCV 0x04 |
104 | #define XGBE_AN_INT_MASK 0x07 | ||
91 | 105 | ||
92 | #define XNP_MCF_NULL_MESSAGE 0x001 | 106 | #define XNP_MCF_NULL_MESSAGE 0x001 |
93 | #define XNP_ACK_PROCESSED (1 << 12) | 107 | #define XNP_ACK_PROCESSED BIT(12) |
94 | #define XNP_MP_FORMATTED (1 << 13) | 108 | #define XNP_MP_FORMATTED BIT(13) |
95 | #define XNP_NP_EXCHANGE (1 << 15) | 109 | #define XNP_NP_EXCHANGE BIT(15) |
96 | 110 | ||
97 | #define XGBE_PHY_RATECHANGE_COUNT 500 | 111 | #define XGBE_PHY_RATECHANGE_COUNT 500 |
98 | 112 | ||
113 | #define XGBE_PHY_KR_TRAINING_START 0x01 | ||
114 | #define XGBE_PHY_KR_TRAINING_ENABLE 0x02 | ||
115 | |||
116 | #define XGBE_PHY_FEC_ENABLE 0x01 | ||
117 | #define XGBE_PHY_FEC_FORWARD 0x02 | ||
118 | #define XGBE_PHY_FEC_MASK 0x03 | ||
119 | |||
99 | #ifndef MDIO_PMA_10GBR_PMD_CTRL | 120 | #ifndef MDIO_PMA_10GBR_PMD_CTRL |
100 | #define MDIO_PMA_10GBR_PMD_CTRL 0x0096 | 121 | #define MDIO_PMA_10GBR_PMD_CTRL 0x0096 |
101 | #endif | 122 | #endif |
102 | 123 | ||
124 | #ifndef MDIO_PMA_10GBR_FEC_ABILITY | ||
125 | #define MDIO_PMA_10GBR_FEC_ABILITY 0x00aa | ||
126 | #endif | ||
127 | |||
103 | #ifndef MDIO_PMA_10GBR_FEC_CTRL | 128 | #ifndef MDIO_PMA_10GBR_FEC_CTRL |
104 | #define MDIO_PMA_10GBR_FEC_CTRL 0x00ab | 129 | #define MDIO_PMA_10GBR_FEC_CTRL 0x00ab |
105 | #endif | 130 | #endif |
@@ -108,6 +133,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); | |||
108 | #define MDIO_AN_XNP 0x0016 | 133 | #define MDIO_AN_XNP 0x0016 |
109 | #endif | 134 | #endif |
110 | 135 | ||
136 | #ifndef MDIO_AN_LPX | ||
137 | #define MDIO_AN_LPX 0x0019 | ||
138 | #endif | ||
139 | |||
111 | #ifndef MDIO_AN_INTMASK | 140 | #ifndef MDIO_AN_INTMASK |
112 | #define MDIO_AN_INTMASK 0x8001 | 141 | #define MDIO_AN_INTMASK 0x8001 |
113 | #endif | 142 | #endif |
@@ -116,18 +145,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); | |||
116 | #define MDIO_AN_INT 0x8002 | 145 | #define MDIO_AN_INT 0x8002 |
117 | #endif | 146 | #endif |
118 | 147 | ||
119 | #ifndef MDIO_AN_KR_CTRL | ||
120 | #define MDIO_AN_KR_CTRL 0x8003 | ||
121 | #endif | ||
122 | |||
123 | #ifndef MDIO_CTRL1_SPEED1G | 148 | #ifndef MDIO_CTRL1_SPEED1G |
124 | #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) | 149 | #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) |
125 | #endif | 150 | #endif |
126 | 151 | ||
127 | #ifndef MDIO_KR_CTRL_PDETECT | ||
128 | #define MDIO_KR_CTRL_PDETECT 0x01 | ||
129 | #endif | ||
130 | |||
131 | /* SerDes integration register offsets */ | 152 | /* SerDes integration register offsets */ |
132 | #define SIR0_KR_RT_1 0x002c | 153 | #define SIR0_KR_RT_1 0x002c |
133 | #define SIR0_STATUS 0x0040 | 154 | #define SIR0_STATUS 0x0040 |
@@ -140,10 +161,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); | |||
140 | #define SIR0_STATUS_RX_READY_WIDTH 1 | 161 | #define SIR0_STATUS_RX_READY_WIDTH 1 |
141 | #define SIR0_STATUS_TX_READY_INDEX 8 | 162 | #define SIR0_STATUS_TX_READY_INDEX 8 |
142 | #define SIR0_STATUS_TX_READY_WIDTH 1 | 163 | #define SIR0_STATUS_TX_READY_WIDTH 1 |
164 | #define SIR1_SPEED_CDR_RATE_INDEX 12 | ||
165 | #define SIR1_SPEED_CDR_RATE_WIDTH 4 | ||
143 | #define SIR1_SPEED_DATARATE_INDEX 4 | 166 | #define SIR1_SPEED_DATARATE_INDEX 4 |
144 | #define SIR1_SPEED_DATARATE_WIDTH 2 | 167 | #define SIR1_SPEED_DATARATE_WIDTH 2 |
145 | #define SIR1_SPEED_PI_SPD_SEL_INDEX 12 | ||
146 | #define SIR1_SPEED_PI_SPD_SEL_WIDTH 4 | ||
147 | #define SIR1_SPEED_PLLSEL_INDEX 3 | 168 | #define SIR1_SPEED_PLLSEL_INDEX 3 |
148 | #define SIR1_SPEED_PLLSEL_WIDTH 1 | 169 | #define SIR1_SPEED_PLLSEL_WIDTH 1 |
149 | #define SIR1_SPEED_RATECHANGE_INDEX 6 | 170 | #define SIR1_SPEED_RATECHANGE_INDEX 6 |
@@ -153,20 +174,26 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); | |||
153 | #define SIR1_SPEED_WORDMODE_INDEX 0 | 174 | #define SIR1_SPEED_WORDMODE_INDEX 0 |
154 | #define SIR1_SPEED_WORDMODE_WIDTH 3 | 175 | #define SIR1_SPEED_WORDMODE_WIDTH 3 |
155 | 176 | ||
177 | #define SPEED_10000_BLWC 0 | ||
156 | #define SPEED_10000_CDR 0x7 | 178 | #define SPEED_10000_CDR 0x7 |
157 | #define SPEED_10000_PLL 0x1 | 179 | #define SPEED_10000_PLL 0x1 |
180 | #define SPEED_10000_PQ 0x1e | ||
158 | #define SPEED_10000_RATE 0x0 | 181 | #define SPEED_10000_RATE 0x0 |
159 | #define SPEED_10000_TXAMP 0xa | 182 | #define SPEED_10000_TXAMP 0xa |
160 | #define SPEED_10000_WORD 0x7 | 183 | #define SPEED_10000_WORD 0x7 |
161 | 184 | ||
185 | #define SPEED_2500_BLWC 1 | ||
162 | #define SPEED_2500_CDR 0x2 | 186 | #define SPEED_2500_CDR 0x2 |
163 | #define SPEED_2500_PLL 0x0 | 187 | #define SPEED_2500_PLL 0x0 |
188 | #define SPEED_2500_PQ 0xa | ||
164 | #define SPEED_2500_RATE 0x1 | 189 | #define SPEED_2500_RATE 0x1 |
165 | #define SPEED_2500_TXAMP 0xf | 190 | #define SPEED_2500_TXAMP 0xf |
166 | #define SPEED_2500_WORD 0x1 | 191 | #define SPEED_2500_WORD 0x1 |
167 | 192 | ||
193 | #define SPEED_1000_BLWC 1 | ||
168 | #define SPEED_1000_CDR 0x2 | 194 | #define SPEED_1000_CDR 0x2 |
169 | #define SPEED_1000_PLL 0x0 | 195 | #define SPEED_1000_PLL 0x0 |
196 | #define SPEED_1000_PQ 0xa | ||
170 | #define SPEED_1000_RATE 0x3 | 197 | #define SPEED_1000_RATE 0x3 |
171 | #define SPEED_1000_TXAMP 0xf | 198 | #define SPEED_1000_TXAMP 0xf |
172 | #define SPEED_1000_WORD 0x1 | 199 | #define SPEED_1000_WORD 0x1 |
@@ -181,15 +208,6 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); | |||
181 | #define RXTX_REG114_PQ_REG_INDEX 9 | 208 | #define RXTX_REG114_PQ_REG_INDEX 9 |
182 | #define RXTX_REG114_PQ_REG_WIDTH 7 | 209 | #define RXTX_REG114_PQ_REG_WIDTH 7 |
183 | 210 | ||
184 | #define RXTX_10000_BLWC 0 | ||
185 | #define RXTX_10000_PQ 0x1e | ||
186 | |||
187 | #define RXTX_2500_BLWC 1 | ||
188 | #define RXTX_2500_PQ 0xa | ||
189 | |||
190 | #define RXTX_1000_BLWC 1 | ||
191 | #define RXTX_1000_PQ 0xa | ||
192 | |||
193 | /* Bit setting and getting macros | 211 | /* Bit setting and getting macros |
194 | * The get macro will extract the current bit field value from within | 212 | * The get macro will extract the current bit field value from within |
195 | * the variable | 213 | * the variable |
@@ -291,23 +309,44 @@ do { \ | |||
291 | XRXTX_IOWRITE((_priv), _reg, reg_val); \ | 309 | XRXTX_IOWRITE((_priv), _reg, reg_val); \ |
292 | } while (0) | 310 | } while (0) |
293 | 311 | ||
312 | static const u32 amd_xgbe_phy_serdes_blwc[] = { | ||
313 | SPEED_1000_BLWC, | ||
314 | SPEED_2500_BLWC, | ||
315 | SPEED_10000_BLWC, | ||
316 | }; | ||
317 | |||
318 | static const u32 amd_xgbe_phy_serdes_cdr_rate[] = { | ||
319 | SPEED_1000_CDR, | ||
320 | SPEED_2500_CDR, | ||
321 | SPEED_10000_CDR, | ||
322 | }; | ||
323 | |||
324 | static const u32 amd_xgbe_phy_serdes_pq_skew[] = { | ||
325 | SPEED_1000_PQ, | ||
326 | SPEED_2500_PQ, | ||
327 | SPEED_10000_PQ, | ||
328 | }; | ||
329 | |||
330 | static const u32 amd_xgbe_phy_serdes_tx_amp[] = { | ||
331 | SPEED_1000_TXAMP, | ||
332 | SPEED_2500_TXAMP, | ||
333 | SPEED_10000_TXAMP, | ||
334 | }; | ||
335 | |||
294 | enum amd_xgbe_phy_an { | 336 | enum amd_xgbe_phy_an { |
295 | AMD_XGBE_AN_READY = 0, | 337 | AMD_XGBE_AN_READY = 0, |
296 | AMD_XGBE_AN_START, | ||
297 | AMD_XGBE_AN_EVENT, | ||
298 | AMD_XGBE_AN_PAGE_RECEIVED, | 338 | AMD_XGBE_AN_PAGE_RECEIVED, |
299 | AMD_XGBE_AN_INCOMPAT_LINK, | 339 | AMD_XGBE_AN_INCOMPAT_LINK, |
300 | AMD_XGBE_AN_COMPLETE, | 340 | AMD_XGBE_AN_COMPLETE, |
301 | AMD_XGBE_AN_NO_LINK, | 341 | AMD_XGBE_AN_NO_LINK, |
302 | AMD_XGBE_AN_EXIT, | ||
303 | AMD_XGBE_AN_ERROR, | 342 | AMD_XGBE_AN_ERROR, |
304 | }; | 343 | }; |
305 | 344 | ||
306 | enum amd_xgbe_phy_rx { | 345 | enum amd_xgbe_phy_rx { |
307 | AMD_XGBE_RX_READY = 0, | 346 | AMD_XGBE_RX_BPA = 0, |
308 | AMD_XGBE_RX_BPA, | ||
309 | AMD_XGBE_RX_XNP, | 347 | AMD_XGBE_RX_XNP, |
310 | AMD_XGBE_RX_COMPLETE, | 348 | AMD_XGBE_RX_COMPLETE, |
349 | AMD_XGBE_RX_ERROR, | ||
311 | }; | 350 | }; |
312 | 351 | ||
313 | enum amd_xgbe_phy_mode { | 352 | enum amd_xgbe_phy_mode { |
@@ -316,12 +355,13 @@ enum amd_xgbe_phy_mode { | |||
316 | }; | 355 | }; |
317 | 356 | ||
318 | enum amd_xgbe_phy_speedset { | 357 | enum amd_xgbe_phy_speedset { |
319 | AMD_XGBE_PHY_SPEEDSET_1000_10000, | 358 | AMD_XGBE_PHY_SPEEDSET_1000_10000 = 0, |
320 | AMD_XGBE_PHY_SPEEDSET_2500_10000, | 359 | AMD_XGBE_PHY_SPEEDSET_2500_10000, |
321 | }; | 360 | }; |
322 | 361 | ||
323 | struct amd_xgbe_phy_priv { | 362 | struct amd_xgbe_phy_priv { |
324 | struct platform_device *pdev; | 363 | struct platform_device *pdev; |
364 | struct acpi_device *adev; | ||
325 | struct device *dev; | 365 | struct device *dev; |
326 | 366 | ||
327 | struct phy_device *phydev; | 367 | struct phy_device *phydev; |
@@ -336,10 +376,24 @@ struct amd_xgbe_phy_priv { | |||
336 | void __iomem *sir0_regs; /* SerDes integration registers (1/2) */ | 376 | void __iomem *sir0_regs; /* SerDes integration registers (1/2) */ |
337 | void __iomem *sir1_regs; /* SerDes integration registers (2/2) */ | 377 | void __iomem *sir1_regs; /* SerDes integration registers (2/2) */ |
338 | 378 | ||
339 | /* Maintain link status for re-starting auto-negotiation */ | 379 | int an_irq; |
340 | unsigned int link; | 380 | char an_irq_name[IFNAMSIZ + 32]; |
381 | struct work_struct an_irq_work; | ||
382 | unsigned int an_irq_allocated; | ||
383 | |||
341 | unsigned int speed_set; | 384 | unsigned int speed_set; |
342 | 385 | ||
386 | /* SerDes UEFI configurable settings. | ||
387 | * Switching between modes/speeds requires new values for some | ||
388 | * SerDes settings. The values can be supplied as device | ||
389 | * properties in array format. The first array entry is for | ||
390 | * 1GbE, second for 2.5GbE and third for 10GbE | ||
391 | */ | ||
392 | u32 serdes_blwc[XGBE_PHY_SPEEDS]; | ||
393 | u32 serdes_cdr_rate[XGBE_PHY_SPEEDS]; | ||
394 | u32 serdes_pq_skew[XGBE_PHY_SPEEDS]; | ||
395 | u32 serdes_tx_amp[XGBE_PHY_SPEEDS]; | ||
396 | |||
343 | /* Auto-negotiation state machine support */ | 397 | /* Auto-negotiation state machine support */ |
344 | struct mutex an_mutex; | 398 | struct mutex an_mutex; |
345 | enum amd_xgbe_phy_an an_result; | 399 | enum amd_xgbe_phy_an an_result; |
@@ -348,7 +402,11 @@ struct amd_xgbe_phy_priv { | |||
348 | enum amd_xgbe_phy_rx kx_state; | 402 | enum amd_xgbe_phy_rx kx_state; |
349 | struct work_struct an_work; | 403 | struct work_struct an_work; |
350 | struct workqueue_struct *an_workqueue; | 404 | struct workqueue_struct *an_workqueue; |
405 | unsigned int an_supported; | ||
351 | unsigned int parallel_detect; | 406 | unsigned int parallel_detect; |
407 | unsigned int fec_ability; | ||
408 | |||
409 | unsigned int lpm_ctrl; /* CTRL1 for resume */ | ||
352 | }; | 410 | }; |
353 | 411 | ||
354 | static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) | 412 | static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) |
@@ -359,7 +417,7 @@ static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) | |||
359 | if (ret < 0) | 417 | if (ret < 0) |
360 | return ret; | 418 | return ret; |
361 | 419 | ||
362 | ret |= 0x02; | 420 | ret |= XGBE_PHY_KR_TRAINING_ENABLE; |
363 | phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); | 421 | phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); |
364 | 422 | ||
365 | return 0; | 423 | return 0; |
@@ -373,7 +431,7 @@ static int amd_xgbe_an_disable_kr_training(struct phy_device *phydev) | |||
373 | if (ret < 0) | 431 | if (ret < 0) |
374 | return ret; | 432 | return ret; |
375 | 433 | ||
376 | ret &= ~0x02; | 434 | ret &= ~XGBE_PHY_KR_TRAINING_ENABLE; |
377 | phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); | 435 | phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); |
378 | 436 | ||
379 | return 0; | 437 | return 0; |
@@ -466,12 +524,16 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) | |||
466 | 524 | ||
467 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_10000_RATE); | 525 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_10000_RATE); |
468 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_10000_WORD); | 526 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_10000_WORD); |
469 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_10000_TXAMP); | ||
470 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_10000_PLL); | 527 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_10000_PLL); |
471 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_10000_CDR); | ||
472 | 528 | ||
473 | XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_10000_BLWC); | 529 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, |
474 | XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_10000_PQ); | 530 | priv->serdes_cdr_rate[XGBE_PHY_SPEED_10000]); |
531 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, | ||
532 | priv->serdes_tx_amp[XGBE_PHY_SPEED_10000]); | ||
533 | XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, | ||
534 | priv->serdes_blwc[XGBE_PHY_SPEED_10000]); | ||
535 | XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, | ||
536 | priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]); | ||
475 | 537 | ||
476 | amd_xgbe_phy_serdes_complete_ratechange(phydev); | 538 | amd_xgbe_phy_serdes_complete_ratechange(phydev); |
477 | 539 | ||
@@ -514,12 +576,16 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev) | |||
514 | 576 | ||
515 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_2500_RATE); | 577 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_2500_RATE); |
516 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_2500_WORD); | 578 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_2500_WORD); |
517 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_2500_TXAMP); | ||
518 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_2500_PLL); | 579 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_2500_PLL); |
519 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_2500_CDR); | ||
520 | 580 | ||
521 | XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_2500_BLWC); | 581 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, |
522 | XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_2500_PQ); | 582 | priv->serdes_cdr_rate[XGBE_PHY_SPEED_2500]); |
583 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, | ||
584 | priv->serdes_tx_amp[XGBE_PHY_SPEED_2500]); | ||
585 | XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, | ||
586 | priv->serdes_blwc[XGBE_PHY_SPEED_2500]); | ||
587 | XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, | ||
588 | priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]); | ||
523 | 589 | ||
524 | amd_xgbe_phy_serdes_complete_ratechange(phydev); | 590 | amd_xgbe_phy_serdes_complete_ratechange(phydev); |
525 | 591 | ||
@@ -562,12 +628,16 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev) | |||
562 | 628 | ||
563 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_1000_RATE); | 629 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_1000_RATE); |
564 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_1000_WORD); | 630 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_1000_WORD); |
565 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_1000_TXAMP); | ||
566 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_1000_PLL); | 631 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_1000_PLL); |
567 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_1000_CDR); | ||
568 | 632 | ||
569 | XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_1000_BLWC); | 633 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, |
570 | XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1000_PQ); | 634 | priv->serdes_cdr_rate[XGBE_PHY_SPEED_1000]); |
635 | XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, | ||
636 | priv->serdes_tx_amp[XGBE_PHY_SPEED_1000]); | ||
637 | XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, | ||
638 | priv->serdes_blwc[XGBE_PHY_SPEED_1000]); | ||
639 | XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, | ||
640 | priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]); | ||
571 | 641 | ||
572 | amd_xgbe_phy_serdes_complete_ratechange(phydev); | 642 | amd_xgbe_phy_serdes_complete_ratechange(phydev); |
573 | 643 | ||
@@ -635,6 +705,38 @@ static int amd_xgbe_phy_set_mode(struct phy_device *phydev, | |||
635 | return ret; | 705 | return ret; |
636 | } | 706 | } |
637 | 707 | ||
708 | static int amd_xgbe_phy_set_an(struct phy_device *phydev, bool enable, | ||
709 | bool restart) | ||
710 | { | ||
711 | int ret; | ||
712 | |||
713 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); | ||
714 | if (ret < 0) | ||
715 | return ret; | ||
716 | |||
717 | ret &= ~MDIO_AN_CTRL1_ENABLE; | ||
718 | |||
719 | if (enable) | ||
720 | ret |= MDIO_AN_CTRL1_ENABLE; | ||
721 | |||
722 | if (restart) | ||
723 | ret |= MDIO_AN_CTRL1_RESTART; | ||
724 | |||
725 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static int amd_xgbe_phy_restart_an(struct phy_device *phydev) | ||
731 | { | ||
732 | return amd_xgbe_phy_set_an(phydev, true, true); | ||
733 | } | ||
734 | |||
735 | static int amd_xgbe_phy_disable_an(struct phy_device *phydev) | ||
736 | { | ||
737 | return amd_xgbe_phy_set_an(phydev, false, false); | ||
738 | } | ||
739 | |||
638 | static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, | 740 | static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, |
639 | enum amd_xgbe_phy_rx *state) | 741 | enum amd_xgbe_phy_rx *state) |
640 | { | 742 | { |
@@ -645,7 +747,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, | |||
645 | 747 | ||
646 | /* If we're not in KR mode then we're done */ | 748 | /* If we're not in KR mode then we're done */ |
647 | if (!amd_xgbe_phy_in_kr_mode(phydev)) | 749 | if (!amd_xgbe_phy_in_kr_mode(phydev)) |
648 | return AMD_XGBE_AN_EVENT; | 750 | return AMD_XGBE_AN_PAGE_RECEIVED; |
649 | 751 | ||
650 | /* Enable/Disable FEC */ | 752 | /* Enable/Disable FEC */ |
651 | ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); | 753 | ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); |
@@ -660,10 +762,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, | |||
660 | if (ret < 0) | 762 | if (ret < 0) |
661 | return AMD_XGBE_AN_ERROR; | 763 | return AMD_XGBE_AN_ERROR; |
662 | 764 | ||
765 | ret &= ~XGBE_PHY_FEC_MASK; | ||
663 | if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) | 766 | if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) |
664 | ret |= 0x01; | 767 | ret |= priv->fec_ability; |
665 | else | ||
666 | ret &= ~0x01; | ||
667 | 768 | ||
668 | phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret); | 769 | phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret); |
669 | 770 | ||
@@ -672,14 +773,17 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, | |||
672 | if (ret < 0) | 773 | if (ret < 0) |
673 | return AMD_XGBE_AN_ERROR; | 774 | return AMD_XGBE_AN_ERROR; |
674 | 775 | ||
675 | XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); | 776 | if (ret & XGBE_PHY_KR_TRAINING_ENABLE) { |
777 | XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); | ||
676 | 778 | ||
677 | ret |= 0x01; | 779 | ret |= XGBE_PHY_KR_TRAINING_START; |
678 | phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); | 780 | phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, |
781 | ret); | ||
679 | 782 | ||
680 | XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); | 783 | XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); |
784 | } | ||
681 | 785 | ||
682 | return AMD_XGBE_AN_EVENT; | 786 | return AMD_XGBE_AN_PAGE_RECEIVED; |
683 | } | 787 | } |
684 | 788 | ||
685 | static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, | 789 | static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, |
@@ -696,7 +800,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, | |||
696 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0); | 800 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0); |
697 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP, msg); | 801 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP, msg); |
698 | 802 | ||
699 | return AMD_XGBE_AN_EVENT; | 803 | return AMD_XGBE_AN_PAGE_RECEIVED; |
700 | } | 804 | } |
701 | 805 | ||
702 | static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev, | 806 | static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev, |
@@ -735,11 +839,11 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev, | |||
735 | int ad_reg, lp_reg; | 839 | int ad_reg, lp_reg; |
736 | 840 | ||
737 | /* Check Extended Next Page support */ | 841 | /* Check Extended Next Page support */ |
738 | ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); | 842 | ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP); |
739 | if (ad_reg < 0) | 843 | if (ad_reg < 0) |
740 | return AMD_XGBE_AN_ERROR; | 844 | return AMD_XGBE_AN_ERROR; |
741 | 845 | ||
742 | lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA); | 846 | lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPX); |
743 | if (lp_reg < 0) | 847 | if (lp_reg < 0) |
744 | return AMD_XGBE_AN_ERROR; | 848 | return AMD_XGBE_AN_ERROR; |
745 | 849 | ||
@@ -748,226 +852,255 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev, | |||
748 | amd_xgbe_an_tx_training(phydev, state); | 852 | amd_xgbe_an_tx_training(phydev, state); |
749 | } | 853 | } |
750 | 854 | ||
751 | static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev) | 855 | static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) |
856 | { | ||
857 | struct amd_xgbe_phy_priv *priv = phydev->priv; | ||
858 | enum amd_xgbe_phy_rx *state; | ||
859 | int ret; | ||
860 | |||
861 | state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state | ||
862 | : &priv->kx_state; | ||
863 | |||
864 | switch (*state) { | ||
865 | case AMD_XGBE_RX_BPA: | ||
866 | ret = amd_xgbe_an_rx_bpa(phydev, state); | ||
867 | break; | ||
868 | |||
869 | case AMD_XGBE_RX_XNP: | ||
870 | ret = amd_xgbe_an_rx_xnp(phydev, state); | ||
871 | break; | ||
872 | |||
873 | default: | ||
874 | ret = AMD_XGBE_AN_ERROR; | ||
875 | } | ||
876 | |||
877 | return ret; | ||
878 | } | ||
879 | |||
880 | static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) | ||
752 | { | 881 | { |
753 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 882 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
754 | int ret; | 883 | int ret; |
755 | 884 | ||
756 | /* Be sure we aren't looping trying to negotiate */ | 885 | /* Be sure we aren't looping trying to negotiate */ |
757 | if (amd_xgbe_phy_in_kr_mode(phydev)) { | 886 | if (amd_xgbe_phy_in_kr_mode(phydev)) { |
758 | if (priv->kr_state != AMD_XGBE_RX_READY) | 887 | priv->kr_state = AMD_XGBE_RX_ERROR; |
888 | |||
889 | if (!(phydev->supported & SUPPORTED_1000baseKX_Full) && | ||
890 | !(phydev->supported & SUPPORTED_2500baseX_Full)) | ||
891 | return AMD_XGBE_AN_NO_LINK; | ||
892 | |||
893 | if (priv->kx_state != AMD_XGBE_RX_BPA) | ||
759 | return AMD_XGBE_AN_NO_LINK; | 894 | return AMD_XGBE_AN_NO_LINK; |
760 | priv->kr_state = AMD_XGBE_RX_BPA; | ||
761 | } else { | 895 | } else { |
762 | if (priv->kx_state != AMD_XGBE_RX_READY) | 896 | priv->kx_state = AMD_XGBE_RX_ERROR; |
897 | |||
898 | if (!(phydev->supported & SUPPORTED_10000baseKR_Full)) | ||
899 | return AMD_XGBE_AN_NO_LINK; | ||
900 | |||
901 | if (priv->kr_state != AMD_XGBE_RX_BPA) | ||
763 | return AMD_XGBE_AN_NO_LINK; | 902 | return AMD_XGBE_AN_NO_LINK; |
764 | priv->kx_state = AMD_XGBE_RX_BPA; | ||
765 | } | 903 | } |
766 | 904 | ||
767 | /* Set up Advertisement register 3 first */ | 905 | ret = amd_xgbe_phy_disable_an(phydev); |
768 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); | 906 | if (ret) |
769 | if (ret < 0) | ||
770 | return AMD_XGBE_AN_ERROR; | 907 | return AMD_XGBE_AN_ERROR; |
771 | 908 | ||
772 | if (phydev->supported & SUPPORTED_10000baseR_FEC) | 909 | ret = amd_xgbe_phy_switch_mode(phydev); |
773 | ret |= 0xc000; | 910 | if (ret) |
774 | else | ||
775 | ret &= ~0xc000; | ||
776 | |||
777 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret); | ||
778 | |||
779 | /* Set up Advertisement register 2 next */ | ||
780 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); | ||
781 | if (ret < 0) | ||
782 | return AMD_XGBE_AN_ERROR; | 911 | return AMD_XGBE_AN_ERROR; |
783 | 912 | ||
784 | if (phydev->supported & SUPPORTED_10000baseKR_Full) | 913 | ret = amd_xgbe_phy_restart_an(phydev); |
785 | ret |= 0x80; | 914 | if (ret) |
786 | else | ||
787 | ret &= ~0x80; | ||
788 | |||
789 | if ((phydev->supported & SUPPORTED_1000baseKX_Full) || | ||
790 | (phydev->supported & SUPPORTED_2500baseX_Full)) | ||
791 | ret |= 0x20; | ||
792 | else | ||
793 | ret &= ~0x20; | ||
794 | |||
795 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret); | ||
796 | |||
797 | /* Set up Advertisement register 1 last */ | ||
798 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); | ||
799 | if (ret < 0) | ||
800 | return AMD_XGBE_AN_ERROR; | 915 | return AMD_XGBE_AN_ERROR; |
801 | 916 | ||
802 | if (phydev->supported & SUPPORTED_Pause) | 917 | return AMD_XGBE_AN_INCOMPAT_LINK; |
803 | ret |= 0x400; | 918 | } |
804 | else | ||
805 | ret &= ~0x400; | ||
806 | 919 | ||
807 | if (phydev->supported & SUPPORTED_Asym_Pause) | 920 | static irqreturn_t amd_xgbe_an_isr(int irq, void *data) |
808 | ret |= 0x800; | 921 | { |
809 | else | 922 | struct amd_xgbe_phy_priv *priv = (struct amd_xgbe_phy_priv *)data; |
810 | ret &= ~0x800; | ||
811 | 923 | ||
812 | /* We don't intend to perform XNP */ | 924 | /* Interrupt reason must be read and cleared outside of IRQ context */ |
813 | ret &= ~XNP_NP_EXCHANGE; | 925 | disable_irq_nosync(priv->an_irq); |
814 | 926 | ||
815 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret); | 927 | queue_work(priv->an_workqueue, &priv->an_irq_work); |
816 | 928 | ||
817 | /* Enable and start auto-negotiation */ | 929 | return IRQ_HANDLED; |
818 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); | 930 | } |
819 | 931 | ||
820 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL); | 932 | static void amd_xgbe_an_irq_work(struct work_struct *work) |
821 | if (ret < 0) | 933 | { |
822 | return AMD_XGBE_AN_ERROR; | 934 | struct amd_xgbe_phy_priv *priv = container_of(work, |
935 | struct amd_xgbe_phy_priv, | ||
936 | an_irq_work); | ||
823 | 937 | ||
824 | ret |= MDIO_KR_CTRL_PDETECT; | 938 | /* Avoid a race between enabling the IRQ and exiting the work by |
825 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL, ret); | 939 | * waiting for the work to finish and then queueing it |
940 | */ | ||
941 | flush_work(&priv->an_work); | ||
942 | queue_work(priv->an_workqueue, &priv->an_work); | ||
943 | } | ||
826 | 944 | ||
827 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); | 945 | static void amd_xgbe_an_state_machine(struct work_struct *work) |
828 | if (ret < 0) | 946 | { |
829 | return AMD_XGBE_AN_ERROR; | 947 | struct amd_xgbe_phy_priv *priv = container_of(work, |
948 | struct amd_xgbe_phy_priv, | ||
949 | an_work); | ||
950 | struct phy_device *phydev = priv->phydev; | ||
951 | enum amd_xgbe_phy_an cur_state = priv->an_state; | ||
952 | int int_reg, int_mask; | ||
830 | 953 | ||
831 | ret |= MDIO_AN_CTRL1_ENABLE; | 954 | mutex_lock(&priv->an_mutex); |
832 | ret |= MDIO_AN_CTRL1_RESTART; | ||
833 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); | ||
834 | 955 | ||
835 | return AMD_XGBE_AN_EVENT; | 956 | /* Read the interrupt */ |
836 | } | 957 | int_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT); |
958 | if (!int_reg) | ||
959 | goto out; | ||
837 | 960 | ||
838 | static enum amd_xgbe_phy_an amd_xgbe_an_event(struct phy_device *phydev) | 961 | next_int: |
839 | { | 962 | if (int_reg < 0) { |
840 | enum amd_xgbe_phy_an new_state; | 963 | priv->an_state = AMD_XGBE_AN_ERROR; |
841 | int ret; | 964 | int_mask = XGBE_AN_INT_MASK; |
965 | } else if (int_reg & XGBE_AN_PG_RCV) { | ||
966 | priv->an_state = AMD_XGBE_AN_PAGE_RECEIVED; | ||
967 | int_mask = XGBE_AN_PG_RCV; | ||
968 | } else if (int_reg & XGBE_AN_INC_LINK) { | ||
969 | priv->an_state = AMD_XGBE_AN_INCOMPAT_LINK; | ||
970 | int_mask = XGBE_AN_INC_LINK; | ||
971 | } else if (int_reg & XGBE_AN_INT_CMPLT) { | ||
972 | priv->an_state = AMD_XGBE_AN_COMPLETE; | ||
973 | int_mask = XGBE_AN_INT_CMPLT; | ||
974 | } else { | ||
975 | priv->an_state = AMD_XGBE_AN_ERROR; | ||
976 | int_mask = 0; | ||
977 | } | ||
842 | 978 | ||
843 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT); | 979 | /* Clear the interrupt to be processed */ |
844 | if (ret < 0) | 980 | int_reg &= ~int_mask; |
845 | return AMD_XGBE_AN_ERROR; | 981 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, int_reg); |
846 | 982 | ||
847 | new_state = AMD_XGBE_AN_EVENT; | 983 | priv->an_result = priv->an_state; |
848 | if (ret & XGBE_AN_PG_RCV) | ||
849 | new_state = AMD_XGBE_AN_PAGE_RECEIVED; | ||
850 | else if (ret & XGBE_AN_INC_LINK) | ||
851 | new_state = AMD_XGBE_AN_INCOMPAT_LINK; | ||
852 | else if (ret & XGBE_AN_INT_CMPLT) | ||
853 | new_state = AMD_XGBE_AN_COMPLETE; | ||
854 | 984 | ||
855 | if (new_state != AMD_XGBE_AN_EVENT) | 985 | again: |
856 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); | 986 | cur_state = priv->an_state; |
857 | 987 | ||
858 | return new_state; | 988 | switch (priv->an_state) { |
859 | } | 989 | case AMD_XGBE_AN_READY: |
990 | priv->an_supported = 0; | ||
991 | break; | ||
860 | 992 | ||
861 | static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) | 993 | case AMD_XGBE_AN_PAGE_RECEIVED: |
862 | { | 994 | priv->an_state = amd_xgbe_an_page_received(phydev); |
863 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 995 | priv->an_supported++; |
864 | enum amd_xgbe_phy_rx *state; | 996 | break; |
865 | int ret; | ||
866 | 997 | ||
867 | state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state | 998 | case AMD_XGBE_AN_INCOMPAT_LINK: |
868 | : &priv->kx_state; | 999 | priv->an_supported = 0; |
1000 | priv->parallel_detect = 0; | ||
1001 | priv->an_state = amd_xgbe_an_incompat_link(phydev); | ||
1002 | break; | ||
869 | 1003 | ||
870 | switch (*state) { | 1004 | case AMD_XGBE_AN_COMPLETE: |
871 | case AMD_XGBE_RX_BPA: | 1005 | priv->parallel_detect = priv->an_supported ? 0 : 1; |
872 | ret = amd_xgbe_an_rx_bpa(phydev, state); | 1006 | netdev_dbg(phydev->attached_dev, "%s successful\n", |
1007 | priv->an_supported ? "Auto negotiation" | ||
1008 | : "Parallel detection"); | ||
873 | break; | 1009 | break; |
874 | 1010 | ||
875 | case AMD_XGBE_RX_XNP: | 1011 | case AMD_XGBE_AN_NO_LINK: |
876 | ret = amd_xgbe_an_rx_xnp(phydev, state); | ||
877 | break; | 1012 | break; |
878 | 1013 | ||
879 | default: | 1014 | default: |
880 | ret = AMD_XGBE_AN_ERROR; | 1015 | priv->an_state = AMD_XGBE_AN_ERROR; |
881 | } | 1016 | } |
882 | 1017 | ||
883 | return ret; | 1018 | if (priv->an_state == AMD_XGBE_AN_NO_LINK) { |
884 | } | 1019 | int_reg = 0; |
1020 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); | ||
1021 | } else if (priv->an_state == AMD_XGBE_AN_ERROR) { | ||
1022 | netdev_err(phydev->attached_dev, | ||
1023 | "error during auto-negotiation, state=%u\n", | ||
1024 | cur_state); | ||
885 | 1025 | ||
886 | static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) | 1026 | int_reg = 0; |
887 | { | 1027 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); |
888 | int ret; | 1028 | } |
889 | 1029 | ||
890 | ret = amd_xgbe_phy_switch_mode(phydev); | 1030 | if (priv->an_state >= AMD_XGBE_AN_COMPLETE) { |
891 | if (ret) | 1031 | priv->an_result = priv->an_state; |
892 | return AMD_XGBE_AN_ERROR; | 1032 | priv->an_state = AMD_XGBE_AN_READY; |
1033 | priv->kr_state = AMD_XGBE_RX_BPA; | ||
1034 | priv->kx_state = AMD_XGBE_RX_BPA; | ||
1035 | } | ||
893 | 1036 | ||
894 | return AMD_XGBE_AN_START; | 1037 | if (cur_state != priv->an_state) |
895 | } | 1038 | goto again; |
896 | 1039 | ||
897 | static void amd_xgbe_an_state_machine(struct work_struct *work) | 1040 | if (int_reg) |
898 | { | 1041 | goto next_int; |
899 | struct amd_xgbe_phy_priv *priv = container_of(work, | ||
900 | struct amd_xgbe_phy_priv, | ||
901 | an_work); | ||
902 | struct phy_device *phydev = priv->phydev; | ||
903 | enum amd_xgbe_phy_an cur_state; | ||
904 | int sleep; | ||
905 | unsigned int an_supported = 0; | ||
906 | 1042 | ||
907 | /* Start in KX mode */ | 1043 | out: |
908 | if (amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX)) | 1044 | enable_irq(priv->an_irq); |
909 | priv->an_state = AMD_XGBE_AN_ERROR; | ||
910 | 1045 | ||
911 | while (1) { | 1046 | mutex_unlock(&priv->an_mutex); |
912 | mutex_lock(&priv->an_mutex); | 1047 | } |
913 | 1048 | ||
914 | cur_state = priv->an_state; | 1049 | static int amd_xgbe_an_init(struct phy_device *phydev) |
1050 | { | ||
1051 | int ret; | ||
915 | 1052 | ||
916 | switch (priv->an_state) { | 1053 | /* Set up Advertisement register 3 first */ |
917 | case AMD_XGBE_AN_START: | 1054 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); |
918 | an_supported = 0; | 1055 | if (ret < 0) |
919 | priv->parallel_detect = 0; | 1056 | return ret; |
920 | priv->an_state = amd_xgbe_an_start(phydev); | ||
921 | break; | ||
922 | 1057 | ||
923 | case AMD_XGBE_AN_EVENT: | 1058 | if (phydev->supported & SUPPORTED_10000baseR_FEC) |
924 | priv->an_state = amd_xgbe_an_event(phydev); | 1059 | ret |= 0xc000; |
925 | break; | 1060 | else |
1061 | ret &= ~0xc000; | ||
926 | 1062 | ||
927 | case AMD_XGBE_AN_PAGE_RECEIVED: | 1063 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret); |
928 | priv->an_state = amd_xgbe_an_page_received(phydev); | ||
929 | an_supported++; | ||
930 | break; | ||
931 | 1064 | ||
932 | case AMD_XGBE_AN_INCOMPAT_LINK: | 1065 | /* Set up Advertisement register 2 next */ |
933 | priv->an_state = amd_xgbe_an_incompat_link(phydev); | 1066 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); |
934 | break; | 1067 | if (ret < 0) |
1068 | return ret; | ||
935 | 1069 | ||
936 | case AMD_XGBE_AN_COMPLETE: | 1070 | if (phydev->supported & SUPPORTED_10000baseKR_Full) |
937 | priv->parallel_detect = an_supported ? 0 : 1; | 1071 | ret |= 0x80; |
938 | netdev_info(phydev->attached_dev, "%s successful\n", | 1072 | else |
939 | an_supported ? "Auto negotiation" | 1073 | ret &= ~0x80; |
940 | : "Parallel detection"); | ||
941 | /* fall through */ | ||
942 | 1074 | ||
943 | case AMD_XGBE_AN_NO_LINK: | 1075 | if ((phydev->supported & SUPPORTED_1000baseKX_Full) || |
944 | case AMD_XGBE_AN_EXIT: | 1076 | (phydev->supported & SUPPORTED_2500baseX_Full)) |
945 | goto exit_unlock; | 1077 | ret |= 0x20; |
1078 | else | ||
1079 | ret &= ~0x20; | ||
946 | 1080 | ||
947 | default: | 1081 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret); |
948 | priv->an_state = AMD_XGBE_AN_ERROR; | ||
949 | } | ||
950 | 1082 | ||
951 | if (priv->an_state == AMD_XGBE_AN_ERROR) { | 1083 | /* Set up Advertisement register 1 last */ |
952 | netdev_err(phydev->attached_dev, | 1084 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); |
953 | "error during auto-negotiation, state=%u\n", | 1085 | if (ret < 0) |
954 | cur_state); | 1086 | return ret; |
955 | goto exit_unlock; | ||
956 | } | ||
957 | 1087 | ||
958 | sleep = (priv->an_state == AMD_XGBE_AN_EVENT) ? 1 : 0; | 1088 | if (phydev->supported & SUPPORTED_Pause) |
1089 | ret |= 0x400; | ||
1090 | else | ||
1091 | ret &= ~0x400; | ||
959 | 1092 | ||
960 | mutex_unlock(&priv->an_mutex); | 1093 | if (phydev->supported & SUPPORTED_Asym_Pause) |
1094 | ret |= 0x800; | ||
1095 | else | ||
1096 | ret &= ~0x800; | ||
961 | 1097 | ||
962 | if (sleep) | 1098 | /* We don't intend to perform XNP */ |
963 | usleep_range(20, 50); | 1099 | ret &= ~XNP_NP_EXCHANGE; |
964 | } | ||
965 | 1100 | ||
966 | exit_unlock: | 1101 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret); |
967 | priv->an_result = priv->an_state; | ||
968 | priv->an_state = AMD_XGBE_AN_READY; | ||
969 | 1102 | ||
970 | mutex_unlock(&priv->an_mutex); | 1103 | return 0; |
971 | } | 1104 | } |
972 | 1105 | ||
973 | static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) | 1106 | static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) |
@@ -992,20 +1125,57 @@ static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) | |||
992 | if (ret & MDIO_CTRL1_RESET) | 1125 | if (ret & MDIO_CTRL1_RESET) |
993 | return -ETIMEDOUT; | 1126 | return -ETIMEDOUT; |
994 | 1127 | ||
995 | /* Make sure the XPCS and SerDes are in compatible states */ | 1128 | /* Disable auto-negotiation for now */ |
996 | return amd_xgbe_phy_xgmii_mode(phydev); | 1129 | ret = amd_xgbe_phy_disable_an(phydev); |
1130 | if (ret < 0) | ||
1131 | return ret; | ||
1132 | |||
1133 | /* Clear auto-negotiation interrupts */ | ||
1134 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); | ||
1135 | |||
1136 | return 0; | ||
997 | } | 1137 | } |
998 | 1138 | ||
999 | static int amd_xgbe_phy_config_init(struct phy_device *phydev) | 1139 | static int amd_xgbe_phy_config_init(struct phy_device *phydev) |
1000 | { | 1140 | { |
1001 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 1141 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
1142 | struct net_device *netdev = phydev->attached_dev; | ||
1143 | int ret; | ||
1144 | |||
1145 | if (!priv->an_irq_allocated) { | ||
1146 | /* Allocate the auto-negotiation workqueue and interrupt */ | ||
1147 | snprintf(priv->an_irq_name, sizeof(priv->an_irq_name) - 1, | ||
1148 | "%s-pcs", netdev_name(netdev)); | ||
1149 | |||
1150 | priv->an_workqueue = | ||
1151 | create_singlethread_workqueue(priv->an_irq_name); | ||
1152 | if (!priv->an_workqueue) { | ||
1153 | netdev_err(netdev, "phy workqueue creation failed\n"); | ||
1154 | return -ENOMEM; | ||
1155 | } | ||
1156 | |||
1157 | ret = devm_request_irq(priv->dev, priv->an_irq, | ||
1158 | amd_xgbe_an_isr, 0, priv->an_irq_name, | ||
1159 | priv); | ||
1160 | if (ret) { | ||
1161 | netdev_err(netdev, "phy irq request failed\n"); | ||
1162 | destroy_workqueue(priv->an_workqueue); | ||
1163 | return ret; | ||
1164 | } | ||
1165 | |||
1166 | priv->an_irq_allocated = 1; | ||
1167 | } | ||
1168 | |||
1169 | ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_ABILITY); | ||
1170 | if (ret < 0) | ||
1171 | return ret; | ||
1172 | priv->fec_ability = ret & XGBE_PHY_FEC_MASK; | ||
1002 | 1173 | ||
1003 | /* Initialize supported features */ | 1174 | /* Initialize supported features */ |
1004 | phydev->supported = SUPPORTED_Autoneg; | 1175 | phydev->supported = SUPPORTED_Autoneg; |
1005 | phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; | 1176 | phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; |
1006 | phydev->supported |= SUPPORTED_Backplane; | 1177 | phydev->supported |= SUPPORTED_Backplane; |
1007 | phydev->supported |= SUPPORTED_10000baseKR_Full | | 1178 | phydev->supported |= SUPPORTED_10000baseKR_Full; |
1008 | SUPPORTED_10000baseR_FEC; | ||
1009 | switch (priv->speed_set) { | 1179 | switch (priv->speed_set) { |
1010 | case AMD_XGBE_PHY_SPEEDSET_1000_10000: | 1180 | case AMD_XGBE_PHY_SPEEDSET_1000_10000: |
1011 | phydev->supported |= SUPPORTED_1000baseKX_Full; | 1181 | phydev->supported |= SUPPORTED_1000baseKX_Full; |
@@ -1014,11 +1184,33 @@ static int amd_xgbe_phy_config_init(struct phy_device *phydev) | |||
1014 | phydev->supported |= SUPPORTED_2500baseX_Full; | 1184 | phydev->supported |= SUPPORTED_2500baseX_Full; |
1015 | break; | 1185 | break; |
1016 | } | 1186 | } |
1187 | |||
1188 | if (priv->fec_ability & XGBE_PHY_FEC_ENABLE) | ||
1189 | phydev->supported |= SUPPORTED_10000baseR_FEC; | ||
1190 | |||
1017 | phydev->advertising = phydev->supported; | 1191 | phydev->advertising = phydev->supported; |
1018 | 1192 | ||
1019 | /* Turn off and clear interrupts */ | 1193 | /* Set initial mode - call the mode setting routines |
1020 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); | 1194 | * directly to insure we are properly configured |
1021 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); | 1195 | */ |
1196 | if (phydev->supported & SUPPORTED_10000baseKR_Full) | ||
1197 | ret = amd_xgbe_phy_xgmii_mode(phydev); | ||
1198 | else if (phydev->supported & SUPPORTED_1000baseKX_Full) | ||
1199 | ret = amd_xgbe_phy_gmii_mode(phydev); | ||
1200 | else if (phydev->supported & SUPPORTED_2500baseX_Full) | ||
1201 | ret = amd_xgbe_phy_gmii_2500_mode(phydev); | ||
1202 | else | ||
1203 | ret = -EINVAL; | ||
1204 | if (ret < 0) | ||
1205 | return ret; | ||
1206 | |||
1207 | /* Set up advertisement registers based on current settings */ | ||
1208 | ret = amd_xgbe_an_init(phydev); | ||
1209 | if (ret) | ||
1210 | return ret; | ||
1211 | |||
1212 | /* Enable auto-negotiation interrupts */ | ||
1213 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07); | ||
1022 | 1214 | ||
1023 | return 0; | 1215 | return 0; |
1024 | } | 1216 | } |
@@ -1028,25 +1220,19 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev) | |||
1028 | int ret; | 1220 | int ret; |
1029 | 1221 | ||
1030 | /* Disable auto-negotiation */ | 1222 | /* Disable auto-negotiation */ |
1031 | ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); | 1223 | ret = amd_xgbe_phy_disable_an(phydev); |
1032 | if (ret < 0) | 1224 | if (ret < 0) |
1033 | return ret; | 1225 | return ret; |
1034 | 1226 | ||
1035 | ret &= ~MDIO_AN_CTRL1_ENABLE; | ||
1036 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); | ||
1037 | |||
1038 | /* Validate/Set specified speed */ | 1227 | /* Validate/Set specified speed */ |
1039 | switch (phydev->speed) { | 1228 | switch (phydev->speed) { |
1040 | case SPEED_10000: | 1229 | case SPEED_10000: |
1041 | ret = amd_xgbe_phy_xgmii_mode(phydev); | 1230 | ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR); |
1042 | break; | 1231 | break; |
1043 | 1232 | ||
1044 | case SPEED_2500: | 1233 | case SPEED_2500: |
1045 | ret = amd_xgbe_phy_gmii_2500_mode(phydev); | ||
1046 | break; | ||
1047 | |||
1048 | case SPEED_1000: | 1234 | case SPEED_1000: |
1049 | ret = amd_xgbe_phy_gmii_mode(phydev); | 1235 | ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX); |
1050 | break; | 1236 | break; |
1051 | 1237 | ||
1052 | default: | 1238 | default: |
@@ -1066,10 +1252,11 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev) | |||
1066 | return 0; | 1252 | return 0; |
1067 | } | 1253 | } |
1068 | 1254 | ||
1069 | static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) | 1255 | static int __amd_xgbe_phy_config_aneg(struct phy_device *phydev) |
1070 | { | 1256 | { |
1071 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 1257 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
1072 | u32 mmd_mask = phydev->c45_ids.devices_in_package; | 1258 | u32 mmd_mask = phydev->c45_ids.devices_in_package; |
1259 | int ret; | ||
1073 | 1260 | ||
1074 | if (phydev->autoneg != AUTONEG_ENABLE) | 1261 | if (phydev->autoneg != AUTONEG_ENABLE) |
1075 | return amd_xgbe_phy_setup_forced(phydev); | 1262 | return amd_xgbe_phy_setup_forced(phydev); |
@@ -1078,56 +1265,79 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) | |||
1078 | if (!(mmd_mask & MDIO_DEVS_AN)) | 1265 | if (!(mmd_mask & MDIO_DEVS_AN)) |
1079 | return -EINVAL; | 1266 | return -EINVAL; |
1080 | 1267 | ||
1081 | /* Start/Restart the auto-negotiation state machine */ | 1268 | /* Disable auto-negotiation interrupt */ |
1082 | mutex_lock(&priv->an_mutex); | 1269 | disable_irq(priv->an_irq); |
1270 | |||
1271 | /* Start auto-negotiation in a supported mode */ | ||
1272 | if (phydev->supported & SUPPORTED_10000baseKR_Full) | ||
1273 | ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR); | ||
1274 | else if ((phydev->supported & SUPPORTED_1000baseKX_Full) || | ||
1275 | (phydev->supported & SUPPORTED_2500baseX_Full)) | ||
1276 | ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX); | ||
1277 | else | ||
1278 | ret = -EINVAL; | ||
1279 | if (ret < 0) { | ||
1280 | enable_irq(priv->an_irq); | ||
1281 | return ret; | ||
1282 | } | ||
1283 | |||
1284 | /* Disable and stop any in progress auto-negotiation */ | ||
1285 | ret = amd_xgbe_phy_disable_an(phydev); | ||
1286 | if (ret < 0) | ||
1287 | return ret; | ||
1288 | |||
1289 | /* Clear any auto-negotitation interrupts */ | ||
1290 | phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); | ||
1291 | |||
1083 | priv->an_result = AMD_XGBE_AN_READY; | 1292 | priv->an_result = AMD_XGBE_AN_READY; |
1084 | priv->an_state = AMD_XGBE_AN_START; | 1293 | priv->an_state = AMD_XGBE_AN_READY; |
1085 | priv->kr_state = AMD_XGBE_RX_READY; | 1294 | priv->kr_state = AMD_XGBE_RX_BPA; |
1086 | priv->kx_state = AMD_XGBE_RX_READY; | 1295 | priv->kx_state = AMD_XGBE_RX_BPA; |
1087 | mutex_unlock(&priv->an_mutex); | ||
1088 | 1296 | ||
1089 | queue_work(priv->an_workqueue, &priv->an_work); | 1297 | /* Re-enable auto-negotiation interrupt */ |
1298 | enable_irq(priv->an_irq); | ||
1090 | 1299 | ||
1091 | return 0; | 1300 | /* Set up advertisement registers based on current settings */ |
1301 | ret = amd_xgbe_an_init(phydev); | ||
1302 | if (ret) | ||
1303 | return ret; | ||
1304 | |||
1305 | /* Enable and start auto-negotiation */ | ||
1306 | return amd_xgbe_phy_restart_an(phydev); | ||
1092 | } | 1307 | } |
1093 | 1308 | ||
1094 | static int amd_xgbe_phy_aneg_done(struct phy_device *phydev) | 1309 | static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) |
1095 | { | 1310 | { |
1096 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 1311 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
1097 | enum amd_xgbe_phy_an state; | 1312 | int ret; |
1098 | 1313 | ||
1099 | mutex_lock(&priv->an_mutex); | 1314 | mutex_lock(&priv->an_mutex); |
1100 | state = priv->an_result; | 1315 | |
1316 | ret = __amd_xgbe_phy_config_aneg(phydev); | ||
1317 | |||
1101 | mutex_unlock(&priv->an_mutex); | 1318 | mutex_unlock(&priv->an_mutex); |
1102 | 1319 | ||
1103 | return (state == AMD_XGBE_AN_COMPLETE); | 1320 | return ret; |
1321 | } | ||
1322 | |||
1323 | static int amd_xgbe_phy_aneg_done(struct phy_device *phydev) | ||
1324 | { | ||
1325 | struct amd_xgbe_phy_priv *priv = phydev->priv; | ||
1326 | |||
1327 | return (priv->an_result == AMD_XGBE_AN_COMPLETE); | ||
1104 | } | 1328 | } |
1105 | 1329 | ||
1106 | static int amd_xgbe_phy_update_link(struct phy_device *phydev) | 1330 | static int amd_xgbe_phy_update_link(struct phy_device *phydev) |
1107 | { | 1331 | { |
1108 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 1332 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
1109 | enum amd_xgbe_phy_an state; | ||
1110 | unsigned int check_again, autoneg; | ||
1111 | int ret; | 1333 | int ret; |
1112 | 1334 | ||
1113 | /* If we're doing auto-negotiation don't report link down */ | 1335 | /* If we're doing auto-negotiation don't report link down */ |
1114 | mutex_lock(&priv->an_mutex); | 1336 | if (priv->an_state != AMD_XGBE_AN_READY) { |
1115 | state = priv->an_state; | ||
1116 | mutex_unlock(&priv->an_mutex); | ||
1117 | |||
1118 | if (state != AMD_XGBE_AN_READY) { | ||
1119 | phydev->link = 1; | 1337 | phydev->link = 1; |
1120 | return 0; | 1338 | return 0; |
1121 | } | 1339 | } |
1122 | 1340 | ||
1123 | /* Since the device can be in the wrong mode when a link is | ||
1124 | * (re-)established (cable connected after the interface is | ||
1125 | * up, etc.), the link status may report no link. If there | ||
1126 | * is no link, try switching modes and checking the status | ||
1127 | * again if auto negotiation is enabled. | ||
1128 | */ | ||
1129 | check_again = (phydev->autoneg == AUTONEG_ENABLE) ? 1 : 0; | ||
1130 | again: | ||
1131 | /* Link status is latched low, so read once to clear | 1341 | /* Link status is latched low, so read once to clear |
1132 | * and then read again to get current state | 1342 | * and then read again to get current state |
1133 | */ | 1343 | */ |
@@ -1141,25 +1351,6 @@ again: | |||
1141 | 1351 | ||
1142 | phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0; | 1352 | phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0; |
1143 | 1353 | ||
1144 | if (!phydev->link) { | ||
1145 | if (check_again) { | ||
1146 | ret = amd_xgbe_phy_switch_mode(phydev); | ||
1147 | if (ret < 0) | ||
1148 | return ret; | ||
1149 | check_again = 0; | ||
1150 | goto again; | ||
1151 | } | ||
1152 | } | ||
1153 | |||
1154 | autoneg = (phydev->link && !priv->link) ? 1 : 0; | ||
1155 | priv->link = phydev->link; | ||
1156 | if (autoneg) { | ||
1157 | /* Link is (back) up, re-start auto-negotiation */ | ||
1158 | ret = amd_xgbe_phy_config_aneg(phydev); | ||
1159 | if (ret < 0) | ||
1160 | return ret; | ||
1161 | } | ||
1162 | |||
1163 | return 0; | 1354 | return 0; |
1164 | } | 1355 | } |
1165 | 1356 | ||
@@ -1249,6 +1440,7 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev) | |||
1249 | 1440 | ||
1250 | static int amd_xgbe_phy_suspend(struct phy_device *phydev) | 1441 | static int amd_xgbe_phy_suspend(struct phy_device *phydev) |
1251 | { | 1442 | { |
1443 | struct amd_xgbe_phy_priv *priv = phydev->priv; | ||
1252 | int ret; | 1444 | int ret; |
1253 | 1445 | ||
1254 | mutex_lock(&phydev->lock); | 1446 | mutex_lock(&phydev->lock); |
@@ -1257,6 +1449,8 @@ static int amd_xgbe_phy_suspend(struct phy_device *phydev) | |||
1257 | if (ret < 0) | 1449 | if (ret < 0) |
1258 | goto unlock; | 1450 | goto unlock; |
1259 | 1451 | ||
1452 | priv->lpm_ctrl = ret; | ||
1453 | |||
1260 | ret |= MDIO_CTRL1_LPOWER; | 1454 | ret |= MDIO_CTRL1_LPOWER; |
1261 | phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); | 1455 | phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); |
1262 | 1456 | ||
@@ -1270,69 +1464,106 @@ unlock: | |||
1270 | 1464 | ||
1271 | static int amd_xgbe_phy_resume(struct phy_device *phydev) | 1465 | static int amd_xgbe_phy_resume(struct phy_device *phydev) |
1272 | { | 1466 | { |
1273 | int ret; | 1467 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
1274 | 1468 | ||
1275 | mutex_lock(&phydev->lock); | 1469 | mutex_lock(&phydev->lock); |
1276 | 1470 | ||
1277 | ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); | 1471 | priv->lpm_ctrl &= ~MDIO_CTRL1_LPOWER; |
1278 | if (ret < 0) | 1472 | phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, priv->lpm_ctrl); |
1279 | goto unlock; | ||
1280 | 1473 | ||
1281 | ret &= ~MDIO_CTRL1_LPOWER; | 1474 | mutex_unlock(&phydev->lock); |
1282 | phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); | ||
1283 | 1475 | ||
1284 | ret = 0; | 1476 | return 0; |
1477 | } | ||
1285 | 1478 | ||
1286 | unlock: | 1479 | static unsigned int amd_xgbe_phy_resource_count(struct platform_device *pdev, |
1287 | mutex_unlock(&phydev->lock); | 1480 | unsigned int type) |
1481 | { | ||
1482 | unsigned int count; | ||
1483 | int i; | ||
1288 | 1484 | ||
1289 | return ret; | 1485 | for (i = 0, count = 0; i < pdev->num_resources; i++) { |
1486 | struct resource *r = &pdev->resource[i]; | ||
1487 | |||
1488 | if (type == resource_type(r)) | ||
1489 | count++; | ||
1490 | } | ||
1491 | |||
1492 | return count; | ||
1290 | } | 1493 | } |
1291 | 1494 | ||
1292 | static int amd_xgbe_phy_probe(struct phy_device *phydev) | 1495 | static int amd_xgbe_phy_probe(struct phy_device *phydev) |
1293 | { | 1496 | { |
1294 | struct amd_xgbe_phy_priv *priv; | 1497 | struct amd_xgbe_phy_priv *priv; |
1295 | struct platform_device *pdev; | 1498 | struct platform_device *phy_pdev; |
1296 | struct device *dev; | 1499 | struct device *dev, *phy_dev; |
1297 | char *wq_name; | 1500 | unsigned int phy_resnum, phy_irqnum; |
1298 | const __be32 *property; | ||
1299 | unsigned int speed_set; | ||
1300 | int ret; | 1501 | int ret; |
1301 | 1502 | ||
1302 | if (!phydev->dev.of_node) | 1503 | if (!phydev->bus || !phydev->bus->parent) |
1303 | return -EINVAL; | 1504 | return -EINVAL; |
1304 | 1505 | ||
1305 | pdev = of_find_device_by_node(phydev->dev.of_node); | 1506 | dev = phydev->bus->parent; |
1306 | if (!pdev) | ||
1307 | return -EINVAL; | ||
1308 | dev = &pdev->dev; | ||
1309 | |||
1310 | wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name); | ||
1311 | if (!wq_name) { | ||
1312 | ret = -ENOMEM; | ||
1313 | goto err_pdev; | ||
1314 | } | ||
1315 | 1507 | ||
1316 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 1508 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
1317 | if (!priv) { | 1509 | if (!priv) |
1318 | ret = -ENOMEM; | 1510 | return -ENOMEM; |
1319 | goto err_name; | ||
1320 | } | ||
1321 | 1511 | ||
1322 | priv->pdev = pdev; | 1512 | priv->pdev = to_platform_device(dev); |
1513 | priv->adev = ACPI_COMPANION(dev); | ||
1323 | priv->dev = dev; | 1514 | priv->dev = dev; |
1324 | priv->phydev = phydev; | 1515 | priv->phydev = phydev; |
1516 | mutex_init(&priv->an_mutex); | ||
1517 | INIT_WORK(&priv->an_irq_work, amd_xgbe_an_irq_work); | ||
1518 | INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); | ||
1519 | |||
1520 | if (!priv->adev || acpi_disabled) { | ||
1521 | struct device_node *bus_node; | ||
1522 | struct device_node *phy_node; | ||
1523 | |||
1524 | bus_node = priv->dev->of_node; | ||
1525 | phy_node = of_parse_phandle(bus_node, "phy-handle", 0); | ||
1526 | if (!phy_node) { | ||
1527 | dev_err(dev, "unable to parse phy-handle\n"); | ||
1528 | ret = -EINVAL; | ||
1529 | goto err_priv; | ||
1530 | } | ||
1531 | |||
1532 | phy_pdev = of_find_device_by_node(phy_node); | ||
1533 | of_node_put(phy_node); | ||
1534 | |||
1535 | if (!phy_pdev) { | ||
1536 | dev_err(dev, "unable to obtain phy device\n"); | ||
1537 | ret = -EINVAL; | ||
1538 | goto err_priv; | ||
1539 | } | ||
1540 | |||
1541 | phy_resnum = 0; | ||
1542 | phy_irqnum = 0; | ||
1543 | } else { | ||
1544 | /* In ACPI, the XGBE and PHY resources are the grouped | ||
1545 | * together with the PHY resources at the end | ||
1546 | */ | ||
1547 | phy_pdev = priv->pdev; | ||
1548 | phy_resnum = amd_xgbe_phy_resource_count(phy_pdev, | ||
1549 | IORESOURCE_MEM) - 3; | ||
1550 | phy_irqnum = amd_xgbe_phy_resource_count(phy_pdev, | ||
1551 | IORESOURCE_IRQ) - 1; | ||
1552 | } | ||
1553 | phy_dev = &phy_pdev->dev; | ||
1325 | 1554 | ||
1326 | /* Get the device mmio areas */ | 1555 | /* Get the device mmio areas */ |
1327 | priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1556 | priv->rxtx_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, |
1557 | phy_resnum++); | ||
1328 | priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res); | 1558 | priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res); |
1329 | if (IS_ERR(priv->rxtx_regs)) { | 1559 | if (IS_ERR(priv->rxtx_regs)) { |
1330 | dev_err(dev, "rxtx ioremap failed\n"); | 1560 | dev_err(dev, "rxtx ioremap failed\n"); |
1331 | ret = PTR_ERR(priv->rxtx_regs); | 1561 | ret = PTR_ERR(priv->rxtx_regs); |
1332 | goto err_priv; | 1562 | goto err_put; |
1333 | } | 1563 | } |
1334 | 1564 | ||
1335 | priv->sir0_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 1565 | priv->sir0_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, |
1566 | phy_resnum++); | ||
1336 | priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res); | 1567 | priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res); |
1337 | if (IS_ERR(priv->sir0_regs)) { | 1568 | if (IS_ERR(priv->sir0_regs)) { |
1338 | dev_err(dev, "sir0 ioremap failed\n"); | 1569 | dev_err(dev, "sir0 ioremap failed\n"); |
@@ -1340,7 +1571,8 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) | |||
1340 | goto err_rxtx; | 1571 | goto err_rxtx; |
1341 | } | 1572 | } |
1342 | 1573 | ||
1343 | priv->sir1_res = platform_get_resource(pdev, IORESOURCE_MEM, 2); | 1574 | priv->sir1_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, |
1575 | phy_resnum++); | ||
1344 | priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res); | 1576 | priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res); |
1345 | if (IS_ERR(priv->sir1_regs)) { | 1577 | if (IS_ERR(priv->sir1_regs)) { |
1346 | dev_err(dev, "sir1 ioremap failed\n"); | 1578 | dev_err(dev, "sir1 ioremap failed\n"); |
@@ -1348,40 +1580,98 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) | |||
1348 | goto err_sir0; | 1580 | goto err_sir0; |
1349 | } | 1581 | } |
1350 | 1582 | ||
1583 | /* Get the auto-negotiation interrupt */ | ||
1584 | ret = platform_get_irq(phy_pdev, phy_irqnum); | ||
1585 | if (ret < 0) { | ||
1586 | dev_err(dev, "platform_get_irq failed\n"); | ||
1587 | goto err_sir1; | ||
1588 | } | ||
1589 | priv->an_irq = ret; | ||
1590 | |||
1351 | /* Get the device speed set property */ | 1591 | /* Get the device speed set property */ |
1352 | speed_set = 0; | 1592 | ret = device_property_read_u32(phy_dev, XGBE_PHY_SPEEDSET_PROPERTY, |
1353 | property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY, | 1593 | &priv->speed_set); |
1354 | NULL); | 1594 | if (ret) { |
1355 | if (property) | 1595 | dev_err(dev, "invalid %s property\n", |
1356 | speed_set = be32_to_cpu(*property); | 1596 | XGBE_PHY_SPEEDSET_PROPERTY); |
1357 | 1597 | goto err_sir1; | |
1358 | switch (speed_set) { | 1598 | } |
1359 | case 0: | 1599 | |
1360 | priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000; | 1600 | switch (priv->speed_set) { |
1361 | break; | 1601 | case AMD_XGBE_PHY_SPEEDSET_1000_10000: |
1362 | case 1: | 1602 | case AMD_XGBE_PHY_SPEEDSET_2500_10000: |
1363 | priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000; | ||
1364 | break; | 1603 | break; |
1365 | default: | 1604 | default: |
1366 | dev_err(dev, "invalid amd,speed-set property\n"); | 1605 | dev_err(dev, "invalid %s property\n", |
1606 | XGBE_PHY_SPEEDSET_PROPERTY); | ||
1367 | ret = -EINVAL; | 1607 | ret = -EINVAL; |
1368 | goto err_sir1; | 1608 | goto err_sir1; |
1369 | } | 1609 | } |
1370 | 1610 | ||
1371 | priv->link = 1; | 1611 | if (device_property_present(phy_dev, XGBE_PHY_BLWC_PROPERTY)) { |
1612 | ret = device_property_read_u32_array(phy_dev, | ||
1613 | XGBE_PHY_BLWC_PROPERTY, | ||
1614 | priv->serdes_blwc, | ||
1615 | XGBE_PHY_SPEEDS); | ||
1616 | if (ret) { | ||
1617 | dev_err(dev, "invalid %s property\n", | ||
1618 | XGBE_PHY_BLWC_PROPERTY); | ||
1619 | goto err_sir1; | ||
1620 | } | ||
1621 | } else { | ||
1622 | memcpy(priv->serdes_blwc, amd_xgbe_phy_serdes_blwc, | ||
1623 | sizeof(priv->serdes_blwc)); | ||
1624 | } | ||
1372 | 1625 | ||
1373 | mutex_init(&priv->an_mutex); | 1626 | if (device_property_present(phy_dev, XGBE_PHY_CDR_RATE_PROPERTY)) { |
1374 | INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); | 1627 | ret = device_property_read_u32_array(phy_dev, |
1375 | priv->an_workqueue = create_singlethread_workqueue(wq_name); | 1628 | XGBE_PHY_CDR_RATE_PROPERTY, |
1376 | if (!priv->an_workqueue) { | 1629 | priv->serdes_cdr_rate, |
1377 | ret = -ENOMEM; | 1630 | XGBE_PHY_SPEEDS); |
1378 | goto err_sir1; | 1631 | if (ret) { |
1632 | dev_err(dev, "invalid %s property\n", | ||
1633 | XGBE_PHY_CDR_RATE_PROPERTY); | ||
1634 | goto err_sir1; | ||
1635 | } | ||
1636 | } else { | ||
1637 | memcpy(priv->serdes_cdr_rate, amd_xgbe_phy_serdes_cdr_rate, | ||
1638 | sizeof(priv->serdes_cdr_rate)); | ||
1639 | } | ||
1640 | |||
1641 | if (device_property_present(phy_dev, XGBE_PHY_PQ_SKEW_PROPERTY)) { | ||
1642 | ret = device_property_read_u32_array(phy_dev, | ||
1643 | XGBE_PHY_PQ_SKEW_PROPERTY, | ||
1644 | priv->serdes_pq_skew, | ||
1645 | XGBE_PHY_SPEEDS); | ||
1646 | if (ret) { | ||
1647 | dev_err(dev, "invalid %s property\n", | ||
1648 | XGBE_PHY_PQ_SKEW_PROPERTY); | ||
1649 | goto err_sir1; | ||
1650 | } | ||
1651 | } else { | ||
1652 | memcpy(priv->serdes_pq_skew, amd_xgbe_phy_serdes_pq_skew, | ||
1653 | sizeof(priv->serdes_pq_skew)); | ||
1654 | } | ||
1655 | |||
1656 | if (device_property_present(phy_dev, XGBE_PHY_TX_AMP_PROPERTY)) { | ||
1657 | ret = device_property_read_u32_array(phy_dev, | ||
1658 | XGBE_PHY_TX_AMP_PROPERTY, | ||
1659 | priv->serdes_tx_amp, | ||
1660 | XGBE_PHY_SPEEDS); | ||
1661 | if (ret) { | ||
1662 | dev_err(dev, "invalid %s property\n", | ||
1663 | XGBE_PHY_TX_AMP_PROPERTY); | ||
1664 | goto err_sir1; | ||
1665 | } | ||
1666 | } else { | ||
1667 | memcpy(priv->serdes_tx_amp, amd_xgbe_phy_serdes_tx_amp, | ||
1668 | sizeof(priv->serdes_tx_amp)); | ||
1379 | } | 1669 | } |
1380 | 1670 | ||
1381 | phydev->priv = priv; | 1671 | phydev->priv = priv; |
1382 | 1672 | ||
1383 | kfree(wq_name); | 1673 | if (!priv->adev || acpi_disabled) |
1384 | of_dev_put(pdev); | 1674 | platform_device_put(phy_pdev); |
1385 | 1675 | ||
1386 | return 0; | 1676 | return 0; |
1387 | 1677 | ||
@@ -1400,15 +1690,13 @@ err_rxtx: | |||
1400 | devm_release_mem_region(dev, priv->rxtx_res->start, | 1690 | devm_release_mem_region(dev, priv->rxtx_res->start, |
1401 | resource_size(priv->rxtx_res)); | 1691 | resource_size(priv->rxtx_res)); |
1402 | 1692 | ||
1693 | err_put: | ||
1694 | if (!priv->adev || acpi_disabled) | ||
1695 | platform_device_put(phy_pdev); | ||
1696 | |||
1403 | err_priv: | 1697 | err_priv: |
1404 | devm_kfree(dev, priv); | 1698 | devm_kfree(dev, priv); |
1405 | 1699 | ||
1406 | err_name: | ||
1407 | kfree(wq_name); | ||
1408 | |||
1409 | err_pdev: | ||
1410 | of_dev_put(pdev); | ||
1411 | |||
1412 | return ret; | 1700 | return ret; |
1413 | } | 1701 | } |
1414 | 1702 | ||
@@ -1417,13 +1705,12 @@ static void amd_xgbe_phy_remove(struct phy_device *phydev) | |||
1417 | struct amd_xgbe_phy_priv *priv = phydev->priv; | 1705 | struct amd_xgbe_phy_priv *priv = phydev->priv; |
1418 | struct device *dev = priv->dev; | 1706 | struct device *dev = priv->dev; |
1419 | 1707 | ||
1420 | /* Stop any in process auto-negotiation */ | 1708 | if (priv->an_irq_allocated) { |
1421 | mutex_lock(&priv->an_mutex); | 1709 | devm_free_irq(dev, priv->an_irq, priv); |
1422 | priv->an_state = AMD_XGBE_AN_EXIT; | ||
1423 | mutex_unlock(&priv->an_mutex); | ||
1424 | 1710 | ||
1425 | flush_workqueue(priv->an_workqueue); | 1711 | flush_workqueue(priv->an_workqueue); |
1426 | destroy_workqueue(priv->an_workqueue); | 1712 | destroy_workqueue(priv->an_workqueue); |
1713 | } | ||
1427 | 1714 | ||
1428 | /* Release resources */ | 1715 | /* Release resources */ |
1429 | devm_iounmap(dev, priv->sir1_regs); | 1716 | devm_iounmap(dev, priv->sir1_regs); |