diff options
author | Sasha Neftin <sasha.neftin@intel.com> | 2018-10-11 03:17:31 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2018-10-17 16:55:18 -0400 |
commit | 5586838fe9ced0980e210b39d635ff3842297448 (patch) | |
tree | 1646f8cca19ced662aac1f065426d27344ec5fa9 /drivers/net/ethernet/intel/igc | |
parent | ab4056126813c889ee6c8fb24ca8f75b84c981ab (diff) |
igc: Add code for PHY support
Add PHY's ID support
Add support for initialization, acquire and release of PHY
Enable register access
Signed-off-by: Sasha Neftin <sasha.neftin@intel.com>
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/igc')
-rw-r--r-- | drivers/net/ethernet/intel/igc/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc.h | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_base.c | 122 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_base.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_defines.h | 79 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_hw.h | 54 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_mac.c | 45 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_mac.h | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_main.c | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_phy.c | 457 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_phy.h | 20 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_regs.h | 3 |
12 files changed, 820 insertions, 1 deletions
diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 2b5378d96c7b..4387f6ba8e67 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile | |||
@@ -7,4 +7,4 @@ | |||
7 | 7 | ||
8 | obj-$(CONFIG_IGC) += igc.o | 8 | obj-$(CONFIG_IGC) += igc.o |
9 | 9 | ||
10 | igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o | 10 | igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o |
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 6dcf51c112f4..7cfbd83d25e4 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h | |||
@@ -359,6 +359,22 @@ static inline u16 igc_desc_unused(const struct igc_ring *ring) | |||
359 | return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1; | 359 | return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1; |
360 | } | 360 | } |
361 | 361 | ||
362 | static inline s32 igc_get_phy_info(struct igc_hw *hw) | ||
363 | { | ||
364 | if (hw->phy.ops.get_phy_info) | ||
365 | return hw->phy.ops.get_phy_info(hw); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static inline s32 igc_reset_phy(struct igc_hw *hw) | ||
371 | { | ||
372 | if (hw->phy.ops.reset) | ||
373 | return hw->phy.ops.reset(hw); | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
362 | static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring) | 378 | static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring) |
363 | { | 379 | { |
364 | return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index); | 380 | return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index); |
diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c index 2d49814966d3..55faef987479 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.c +++ b/drivers/net/ethernet/intel/igc/igc_base.c | |||
@@ -124,6 +124,22 @@ static s32 igc_reset_hw_base(struct igc_hw *hw) | |||
124 | } | 124 | } |
125 | 125 | ||
126 | /** | 126 | /** |
127 | * igc_get_phy_id_base - Retrieve PHY addr and id | ||
128 | * @hw: pointer to the HW structure | ||
129 | * | ||
130 | * Retrieves the PHY address and ID for both PHY's which do and do not use | ||
131 | * sgmi interface. | ||
132 | */ | ||
133 | static s32 igc_get_phy_id_base(struct igc_hw *hw) | ||
134 | { | ||
135 | s32 ret_val = 0; | ||
136 | |||
137 | ret_val = igc_get_phy_id(hw); | ||
138 | |||
139 | return ret_val; | ||
140 | } | ||
141 | |||
142 | /** | ||
127 | * igc_init_nvm_params_base - Init NVM func ptrs. | 143 | * igc_init_nvm_params_base - Init NVM func ptrs. |
128 | * @hw: pointer to the HW structure | 144 | * @hw: pointer to the HW structure |
129 | */ | 145 | */ |
@@ -187,6 +203,59 @@ static s32 igc_init_mac_params_base(struct igc_hw *hw) | |||
187 | return 0; | 203 | return 0; |
188 | } | 204 | } |
189 | 205 | ||
206 | /** | ||
207 | * igc_init_phy_params_base - Init PHY func ptrs. | ||
208 | * @hw: pointer to the HW structure | ||
209 | */ | ||
210 | static s32 igc_init_phy_params_base(struct igc_hw *hw) | ||
211 | { | ||
212 | struct igc_phy_info *phy = &hw->phy; | ||
213 | s32 ret_val = 0; | ||
214 | u32 ctrl_ext; | ||
215 | |||
216 | if (hw->phy.media_type != igc_media_type_copper) { | ||
217 | phy->type = igc_phy_none; | ||
218 | goto out; | ||
219 | } | ||
220 | |||
221 | phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500; | ||
222 | phy->reset_delay_us = 100; | ||
223 | |||
224 | ctrl_ext = rd32(IGC_CTRL_EXT); | ||
225 | |||
226 | /* set lan id */ | ||
227 | hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >> | ||
228 | IGC_STATUS_FUNC_SHIFT; | ||
229 | |||
230 | /* Make sure the PHY is in a good state. Several people have reported | ||
231 | * firmware leaving the PHY's page select register set to something | ||
232 | * other than the default of zero, which causes the PHY ID read to | ||
233 | * access something other than the intended register. | ||
234 | */ | ||
235 | ret_val = hw->phy.ops.reset(hw); | ||
236 | if (ret_val) { | ||
237 | hw_dbg("Error resetting the PHY.\n"); | ||
238 | goto out; | ||
239 | } | ||
240 | |||
241 | ret_val = igc_get_phy_id_base(hw); | ||
242 | if (ret_val) | ||
243 | return ret_val; | ||
244 | |||
245 | /* Verify phy id and set remaining function pointers */ | ||
246 | switch (phy->id) { | ||
247 | case I225_I_PHY_ID: | ||
248 | phy->type = igc_phy_i225; | ||
249 | break; | ||
250 | default: | ||
251 | ret_val = -IGC_ERR_PHY; | ||
252 | goto out; | ||
253 | } | ||
254 | |||
255 | out: | ||
256 | return ret_val; | ||
257 | } | ||
258 | |||
190 | static s32 igc_get_invariants_base(struct igc_hw *hw) | 259 | static s32 igc_get_invariants_base(struct igc_hw *hw) |
191 | { | 260 | { |
192 | u32 link_mode = 0; | 261 | u32 link_mode = 0; |
@@ -211,6 +280,8 @@ static s32 igc_get_invariants_base(struct igc_hw *hw) | |||
211 | break; | 280 | break; |
212 | } | 281 | } |
213 | 282 | ||
283 | /* setup PHY parameters */ | ||
284 | ret_val = igc_init_phy_params_base(hw); | ||
214 | if (ret_val) | 285 | if (ret_val) |
215 | goto out; | 286 | goto out; |
216 | 287 | ||
@@ -219,6 +290,34 @@ out: | |||
219 | } | 290 | } |
220 | 291 | ||
221 | /** | 292 | /** |
293 | * igc_acquire_phy_base - Acquire rights to access PHY | ||
294 | * @hw: pointer to the HW structure | ||
295 | * | ||
296 | * Acquire access rights to the correct PHY. This is a | ||
297 | * function pointer entry point called by the api module. | ||
298 | */ | ||
299 | static s32 igc_acquire_phy_base(struct igc_hw *hw) | ||
300 | { | ||
301 | u16 mask = IGC_SWFW_PHY0_SM; | ||
302 | |||
303 | return hw->mac.ops.acquire_swfw_sync(hw, mask); | ||
304 | } | ||
305 | |||
306 | /** | ||
307 | * igc_release_phy_base - Release rights to access PHY | ||
308 | * @hw: pointer to the HW structure | ||
309 | * | ||
310 | * A wrapper to release access rights to the correct PHY. This is a | ||
311 | * function pointer entry point called by the api module. | ||
312 | */ | ||
313 | static void igc_release_phy_base(struct igc_hw *hw) | ||
314 | { | ||
315 | u16 mask = IGC_SWFW_PHY0_SM; | ||
316 | |||
317 | hw->mac.ops.release_swfw_sync(hw, mask); | ||
318 | } | ||
319 | |||
320 | /** | ||
222 | * igc_get_link_up_info_base - Get link speed/duplex info | 321 | * igc_get_link_up_info_base - Get link speed/duplex info |
223 | * @hw: pointer to the HW structure | 322 | * @hw: pointer to the HW structure |
224 | * @speed: stores the current speed | 323 | * @speed: stores the current speed |
@@ -290,6 +389,20 @@ static s32 igc_read_mac_addr_base(struct igc_hw *hw) | |||
290 | } | 389 | } |
291 | 390 | ||
292 | /** | 391 | /** |
392 | * igc_power_down_phy_copper_base - Remove link during PHY power down | ||
393 | * @hw: pointer to the HW structure | ||
394 | * | ||
395 | * In the case of a PHY power down to save power, or to turn off link during a | ||
396 | * driver unload, or wake on lan is not enabled, remove the link. | ||
397 | */ | ||
398 | void igc_power_down_phy_copper_base(struct igc_hw *hw) | ||
399 | { | ||
400 | /* If the management interface is not enabled, then power down */ | ||
401 | if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw))) | ||
402 | igc_power_down_phy_copper(hw); | ||
403 | } | ||
404 | |||
405 | /** | ||
293 | * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable | 406 | * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable |
294 | * @hw: pointer to the HW structure | 407 | * @hw: pointer to the HW structure |
295 | * | 408 | * |
@@ -373,7 +486,16 @@ static struct igc_mac_operations igc_mac_ops_base = { | |||
373 | .get_speed_and_duplex = igc_get_link_up_info_base, | 486 | .get_speed_and_duplex = igc_get_link_up_info_base, |
374 | }; | 487 | }; |
375 | 488 | ||
489 | static const struct igc_phy_operations igc_phy_ops_base = { | ||
490 | .acquire = igc_acquire_phy_base, | ||
491 | .release = igc_release_phy_base, | ||
492 | .reset = igc_phy_hw_reset, | ||
493 | .read_reg = igc_read_phy_reg_gpy, | ||
494 | .write_reg = igc_write_phy_reg_gpy, | ||
495 | }; | ||
496 | |||
376 | const struct igc_info igc_base_info = { | 497 | const struct igc_info igc_base_info = { |
377 | .get_invariants = igc_get_invariants_base, | 498 | .get_invariants = igc_get_invariants_base, |
378 | .mac_ops = &igc_mac_ops_base, | 499 | .mac_ops = &igc_mac_ops_base, |
500 | .phy_ops = &igc_phy_ops_base, | ||
379 | }; | 501 | }; |
diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h index 802a0cbd3123..35588fa7b8c5 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.h +++ b/drivers/net/ethernet/intel/igc/igc_base.h | |||
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | /* forward declaration */ | 7 | /* forward declaration */ |
8 | void igc_rx_fifo_flush_base(struct igc_hw *hw); | 8 | void igc_rx_fifo_flush_base(struct igc_hw *hw); |
9 | void igc_power_down_phy_copper_base(struct igc_hw *hw); | ||
9 | 10 | ||
10 | /* Transmit Descriptor - Advanced */ | 11 | /* Transmit Descriptor - Advanced */ |
11 | union igc_adv_tx_desc { | 12 | union igc_adv_tx_desc { |
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index e5736577009a..d271671e6825 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h | |||
@@ -47,11 +47,14 @@ | |||
47 | #define IGC_ERR_MAC_INIT 5 | 47 | #define IGC_ERR_MAC_INIT 5 |
48 | #define IGC_ERR_RESET 9 | 48 | #define IGC_ERR_RESET 9 |
49 | #define IGC_ERR_MASTER_REQUESTS_PENDING 10 | 49 | #define IGC_ERR_MASTER_REQUESTS_PENDING 10 |
50 | #define IGC_ERR_BLK_PHY_RESET 12 | ||
50 | #define IGC_ERR_SWFW_SYNC 13 | 51 | #define IGC_ERR_SWFW_SYNC 13 |
51 | 52 | ||
52 | /* Device Control */ | 53 | /* Device Control */ |
53 | #define IGC_CTRL_RST 0x04000000 /* Global reset */ | 54 | #define IGC_CTRL_RST 0x04000000 /* Global reset */ |
54 | 55 | ||
56 | #define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */ | ||
57 | |||
55 | /* PBA constants */ | 58 | /* PBA constants */ |
56 | #define IGC_PBA_34K 0x0022 | 59 | #define IGC_PBA_34K 0x0022 |
57 | 60 | ||
@@ -123,6 +126,22 @@ | |||
123 | #define HALF_DUPLEX 1 | 126 | #define HALF_DUPLEX 1 |
124 | #define FULL_DUPLEX 2 | 127 | #define FULL_DUPLEX 2 |
125 | 128 | ||
129 | /* 1Gbps and 2.5Gbps half duplex is not supported, nor spec-compliant. */ | ||
130 | #define ADVERTISE_10_HALF 0x0001 | ||
131 | #define ADVERTISE_10_FULL 0x0002 | ||
132 | #define ADVERTISE_100_HALF 0x0004 | ||
133 | #define ADVERTISE_100_FULL 0x0008 | ||
134 | #define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ | ||
135 | #define ADVERTISE_1000_FULL 0x0020 | ||
136 | #define ADVERTISE_2500_HALF 0x0040 /* Not used, just FYI */ | ||
137 | #define ADVERTISE_2500_FULL 0x0080 | ||
138 | |||
139 | #define IGC_ALL_SPEED_DUPLEX_2500 ( \ | ||
140 | ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \ | ||
141 | ADVERTISE_100_FULL | ADVERTISE_1000_FULL | ADVERTISE_2500_FULL) | ||
142 | |||
143 | #define AUTONEG_ADVERTISE_SPEED_DEFAULT_2500 IGC_ALL_SPEED_DUPLEX_2500 | ||
144 | |||
126 | /* Interrupt Cause Read */ | 145 | /* Interrupt Cause Read */ |
127 | #define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */ | 146 | #define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */ |
128 | #define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */ | 147 | #define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */ |
@@ -208,6 +227,7 @@ | |||
208 | 227 | ||
209 | /* Management Control */ | 228 | /* Management Control */ |
210 | #define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ | 229 | #define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ |
230 | #define IGC_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ | ||
211 | 231 | ||
212 | /* Receive Control */ | 232 | /* Receive Control */ |
213 | #define IGC_RCTL_RST 0x00000001 /* Software reset */ | 233 | #define IGC_RCTL_RST 0x00000001 /* Software reset */ |
@@ -256,6 +276,65 @@ | |||
256 | #define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */ | 276 | #define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */ |
257 | #define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */ | 277 | #define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */ |
258 | 278 | ||
279 | /* GPY211 - I225 defines */ | ||
280 | #define GPY_MMD_MASK 0xFFFF0000 | ||
281 | #define GPY_MMD_SHIFT 16 | ||
282 | #define GPY_REG_MASK 0x0000FFFF | ||
283 | |||
284 | #define IGC_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */ | ||
285 | |||
286 | /* MAC definitions */ | ||
287 | #define IGC_FACTPS_MNGCG 0x20000000 | ||
288 | #define IGC_FWSM_MODE_MASK 0xE | ||
289 | #define IGC_FWSM_MODE_SHIFT 1 | ||
290 | |||
291 | /* Management Control */ | ||
292 | #define IGC_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ | ||
293 | #define IGC_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ | ||
294 | |||
295 | /* PHY */ | ||
296 | #define PHY_REVISION_MASK 0xFFFFFFF0 | ||
297 | #define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ | ||
298 | #define IGC_GEN_POLL_TIMEOUT 1920 | ||
299 | |||
300 | /* PHY Control Register */ | ||
301 | #define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ | ||
302 | #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ | ||
303 | #define MII_CR_POWER_DOWN 0x0800 /* Power down */ | ||
304 | #define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ | ||
305 | #define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ | ||
306 | #define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ | ||
307 | #define MII_CR_SPEED_1000 0x0040 | ||
308 | #define MII_CR_SPEED_100 0x2000 | ||
309 | #define MII_CR_SPEED_10 0x0000 | ||
310 | |||
311 | /* PHY Status Register */ | ||
312 | #define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ | ||
313 | #define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ | ||
314 | |||
315 | /* PHY 1000 MII Register/Bit Definitions */ | ||
316 | /* PHY Registers defined by IEEE */ | ||
317 | #define PHY_CONTROL 0x00 /* Control Register */ | ||
318 | #define PHY_STATUS 0x01 /* Status Register */ | ||
319 | #define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ | ||
320 | #define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ | ||
321 | |||
322 | /* Bit definitions for valid PHY IDs. I = Integrated E = External */ | ||
323 | #define I225_I_PHY_ID 0x67C9DC00 | ||
324 | |||
325 | /* MDI Control */ | ||
326 | #define IGC_MDIC_DATA_MASK 0x0000FFFF | ||
327 | #define IGC_MDIC_REG_MASK 0x001F0000 | ||
328 | #define IGC_MDIC_REG_SHIFT 16 | ||
329 | #define IGC_MDIC_PHY_MASK 0x03E00000 | ||
330 | #define IGC_MDIC_PHY_SHIFT 21 | ||
331 | #define IGC_MDIC_OP_WRITE 0x04000000 | ||
332 | #define IGC_MDIC_OP_READ 0x08000000 | ||
333 | #define IGC_MDIC_READY 0x10000000 | ||
334 | #define IGC_MDIC_INT_EN 0x20000000 | ||
335 | #define IGC_MDIC_ERROR 0x40000000 | ||
336 | #define IGC_MDIC_DEST 0x80000000 | ||
337 | |||
259 | #define IGC_N0_QUEUE -1 | 338 | #define IGC_N0_QUEUE -1 |
260 | 339 | ||
261 | #endif /* _IGC_DEFINES_H_ */ | 340 | #endif /* _IGC_DEFINES_H_ */ |
diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index 107d6461924b..65d1446ff0c3 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "igc_regs.h" | 11 | #include "igc_regs.h" |
12 | #include "igc_defines.h" | 12 | #include "igc_defines.h" |
13 | #include "igc_mac.h" | 13 | #include "igc_mac.h" |
14 | #include "igc_phy.h" | ||
14 | #include "igc_nvm.h" | 15 | #include "igc_nvm.h" |
15 | #include "igc_i225.h" | 16 | #include "igc_i225.h" |
16 | #include "igc_base.h" | 17 | #include "igc_base.h" |
@@ -18,6 +19,8 @@ | |||
18 | #define IGC_DEV_ID_I225_LM 0x15F2 | 19 | #define IGC_DEV_ID_I225_LM 0x15F2 |
19 | #define IGC_DEV_ID_I225_V 0x15F3 | 20 | #define IGC_DEV_ID_I225_V 0x15F3 |
20 | 21 | ||
22 | #define IGC_FUNC_0 0 | ||
23 | |||
21 | /* Function pointers for the MAC. */ | 24 | /* Function pointers for the MAC. */ |
22 | struct igc_mac_operations { | 25 | struct igc_mac_operations { |
23 | s32 (*check_for_link)(struct igc_hw *hw); | 26 | s32 (*check_for_link)(struct igc_hw *hw); |
@@ -44,6 +47,12 @@ enum igc_phy_type { | |||
44 | igc_phy_i225, | 47 | igc_phy_i225, |
45 | }; | 48 | }; |
46 | 49 | ||
50 | enum igc_media_type { | ||
51 | igc_media_type_unknown = 0, | ||
52 | igc_media_type_copper = 1, | ||
53 | igc_num_media_types | ||
54 | }; | ||
55 | |||
47 | enum igc_nvm_type { | 56 | enum igc_nvm_type { |
48 | igc_nvm_unknown = 0, | 57 | igc_nvm_unknown = 0, |
49 | igc_nvm_flash_hw, | 58 | igc_nvm_flash_hw, |
@@ -84,6 +93,7 @@ struct igc_mac_info { | |||
84 | 93 | ||
85 | bool adaptive_ifs; | 94 | bool adaptive_ifs; |
86 | bool has_fwsm; | 95 | bool has_fwsm; |
96 | bool asf_firmware_present; | ||
87 | bool arc_subsystem_valid; | 97 | bool arc_subsystem_valid; |
88 | 98 | ||
89 | bool autoneg; | 99 | bool autoneg; |
@@ -101,6 +111,20 @@ struct igc_nvm_operations { | |||
101 | s32 (*valid_led_default)(struct igc_hw *hw, u16 *data); | 111 | s32 (*valid_led_default)(struct igc_hw *hw, u16 *data); |
102 | }; | 112 | }; |
103 | 113 | ||
114 | struct igc_phy_operations { | ||
115 | s32 (*acquire)(struct igc_hw *hw); | ||
116 | s32 (*check_polarity)(struct igc_hw *hw); | ||
117 | s32 (*check_reset_block)(struct igc_hw *hw); | ||
118 | s32 (*force_speed_duplex)(struct igc_hw *hw); | ||
119 | s32 (*get_cfg_done)(struct igc_hw *hw); | ||
120 | s32 (*get_cable_length)(struct igc_hw *hw); | ||
121 | s32 (*get_phy_info)(struct igc_hw *hw); | ||
122 | s32 (*read_reg)(struct igc_hw *hw, u32 address, u16 *data); | ||
123 | void (*release)(struct igc_hw *hw); | ||
124 | s32 (*reset)(struct igc_hw *hw); | ||
125 | s32 (*write_reg)(struct igc_hw *hw, u32 address, u16 data); | ||
126 | }; | ||
127 | |||
104 | struct igc_nvm_info { | 128 | struct igc_nvm_info { |
105 | struct igc_nvm_operations ops; | 129 | struct igc_nvm_operations ops; |
106 | enum igc_nvm_type type; | 130 | enum igc_nvm_type type; |
@@ -115,6 +139,35 @@ struct igc_nvm_info { | |||
115 | u16 page_size; | 139 | u16 page_size; |
116 | }; | 140 | }; |
117 | 141 | ||
142 | struct igc_phy_info { | ||
143 | struct igc_phy_operations ops; | ||
144 | |||
145 | enum igc_phy_type type; | ||
146 | |||
147 | u32 addr; | ||
148 | u32 id; | ||
149 | u32 reset_delay_us; /* in usec */ | ||
150 | u32 revision; | ||
151 | |||
152 | enum igc_media_type media_type; | ||
153 | |||
154 | u16 autoneg_advertised; | ||
155 | u16 autoneg_mask; | ||
156 | u16 cable_length; | ||
157 | u16 max_cable_length; | ||
158 | u16 min_cable_length; | ||
159 | u16 pair_length[4]; | ||
160 | |||
161 | u8 mdix; | ||
162 | |||
163 | bool disable_polarity_correction; | ||
164 | bool is_mdix; | ||
165 | bool polarity_correction; | ||
166 | bool reset_disable; | ||
167 | bool speed_downgraded; | ||
168 | bool autoneg_wait_to_complete; | ||
169 | }; | ||
170 | |||
118 | struct igc_bus_info { | 171 | struct igc_bus_info { |
119 | u16 func; | 172 | u16 func; |
120 | u16 pci_cmd_word; | 173 | u16 pci_cmd_word; |
@@ -155,6 +208,7 @@ struct igc_hw { | |||
155 | struct igc_mac_info mac; | 208 | struct igc_mac_info mac; |
156 | struct igc_fc_info fc; | 209 | struct igc_fc_info fc; |
157 | struct igc_nvm_info nvm; | 210 | struct igc_nvm_info nvm; |
211 | struct igc_phy_info phy; | ||
158 | 212 | ||
159 | struct igc_bus_info bus; | 213 | struct igc_bus_info bus; |
160 | 214 | ||
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 249ac03b05d8..fce7f7f5aa46 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c | |||
@@ -338,6 +338,7 @@ s32 igc_check_for_copper_link(struct igc_hw *hw) | |||
338 | * link. If so, then we want to get the current speed/duplex | 338 | * link. If so, then we want to get the current speed/duplex |
339 | * of the PHY. | 339 | * of the PHY. |
340 | */ | 340 | */ |
341 | ret_val = igc_phy_has_link(hw, 1, 0, &link); | ||
341 | if (ret_val) | 342 | if (ret_val) |
342 | goto out; | 343 | goto out; |
343 | 344 | ||
@@ -349,6 +350,7 @@ s32 igc_check_for_copper_link(struct igc_hw *hw) | |||
349 | /* Check if there was DownShift, must be checked | 350 | /* Check if there was DownShift, must be checked |
350 | * immediately after link-up | 351 | * immediately after link-up |
351 | */ | 352 | */ |
353 | igc_check_downshift(hw); | ||
352 | 354 | ||
353 | /* If we are forcing speed/duplex, then we simply return since | 355 | /* If we are forcing speed/duplex, then we simply return since |
354 | * we have already determined whether we have link or not. | 356 | * we have already determined whether we have link or not. |
@@ -488,3 +490,46 @@ void igc_put_hw_semaphore(struct igc_hw *hw) | |||
488 | 490 | ||
489 | wr32(IGC_SWSM, swsm); | 491 | wr32(IGC_SWSM, swsm); |
490 | } | 492 | } |
493 | |||
494 | /** | ||
495 | * igc_enable_mng_pass_thru - Enable processing of ARP's | ||
496 | * @hw: pointer to the HW structure | ||
497 | * | ||
498 | * Verifies the hardware needs to leave interface enabled so that frames can | ||
499 | * be directed to and from the management interface. | ||
500 | */ | ||
501 | bool igc_enable_mng_pass_thru(struct igc_hw *hw) | ||
502 | { | ||
503 | bool ret_val = false; | ||
504 | u32 fwsm, factps; | ||
505 | u32 manc; | ||
506 | |||
507 | if (!hw->mac.asf_firmware_present) | ||
508 | goto out; | ||
509 | |||
510 | manc = rd32(IGC_MANC); | ||
511 | |||
512 | if (!(manc & IGC_MANC_RCV_TCO_EN)) | ||
513 | goto out; | ||
514 | |||
515 | if (hw->mac.arc_subsystem_valid) { | ||
516 | fwsm = rd32(IGC_FWSM); | ||
517 | factps = rd32(IGC_FACTPS); | ||
518 | |||
519 | if (!(factps & IGC_FACTPS_MNGCG) && | ||
520 | ((fwsm & IGC_FWSM_MODE_MASK) == | ||
521 | (igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) { | ||
522 | ret_val = true; | ||
523 | goto out; | ||
524 | } | ||
525 | } else { | ||
526 | if ((manc & IGC_MANC_SMBUS_EN) && | ||
527 | !(manc & IGC_MANC_ASF_EN)) { | ||
528 | ret_val = true; | ||
529 | goto out; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | out: | ||
534 | return ret_val; | ||
535 | } | ||
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h index 88599661d017..c842cc561123 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.h +++ b/drivers/net/ethernet/intel/igc/igc_mac.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #define _IGC_MAC_H_ | 5 | #define _IGC_MAC_H_ |
6 | 6 | ||
7 | #include "igc_hw.h" | 7 | #include "igc_hw.h" |
8 | #include "igc_phy.h" | ||
8 | #include "igc_defines.h" | 9 | #include "igc_defines.h" |
9 | 10 | ||
10 | #ifndef IGC_REMOVED | 11 | #ifndef IGC_REMOVED |
@@ -25,4 +26,14 @@ void igc_config_collision_dist(struct igc_hw *hw); | |||
25 | s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, | 26 | s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, |
26 | u16 *duplex); | 27 | u16 *duplex); |
27 | 28 | ||
29 | bool igc_enable_mng_pass_thru(struct igc_hw *hw); | ||
30 | |||
31 | enum igc_mng_mode { | ||
32 | igc_mng_mode_none = 0, | ||
33 | igc_mng_mode_asf, | ||
34 | igc_mng_mode_pt, | ||
35 | igc_mng_mode_ipmi, | ||
36 | igc_mng_mode_host_if_only | ||
37 | }; | ||
38 | |||
28 | #endif | 39 | #endif |
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 115fc2a544d7..14f324826604 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c | |||
@@ -78,6 +78,8 @@ static void igc_reset(struct igc_adapter *adapter) | |||
78 | 78 | ||
79 | if (!netif_running(adapter->netdev)) | 79 | if (!netif_running(adapter->netdev)) |
80 | igc_power_down_link(adapter); | 80 | igc_power_down_link(adapter); |
81 | |||
82 | igc_get_phy_info(hw); | ||
81 | } | 83 | } |
82 | 84 | ||
83 | /** | 85 | /** |
@@ -86,6 +88,12 @@ static void igc_reset(struct igc_adapter *adapter) | |||
86 | */ | 88 | */ |
87 | static void igc_power_up_link(struct igc_adapter *adapter) | 89 | static void igc_power_up_link(struct igc_adapter *adapter) |
88 | { | 90 | { |
91 | igc_reset_phy(&adapter->hw); | ||
92 | |||
93 | if (adapter->hw.phy.media_type == igc_media_type_copper) | ||
94 | igc_power_up_phy_copper(&adapter->hw); | ||
95 | |||
96 | igc_setup_link(&adapter->hw); | ||
89 | } | 97 | } |
90 | 98 | ||
91 | /** | 99 | /** |
@@ -94,6 +102,8 @@ static void igc_power_up_link(struct igc_adapter *adapter) | |||
94 | */ | 102 | */ |
95 | static void igc_power_down_link(struct igc_adapter *adapter) | 103 | static void igc_power_down_link(struct igc_adapter *adapter) |
96 | { | 104 | { |
105 | if (adapter->hw.phy.media_type == igc_media_type_copper) | ||
106 | igc_power_down_phy_copper_base(&adapter->hw); | ||
97 | } | 107 | } |
98 | 108 | ||
99 | /** | 109 | /** |
@@ -3377,6 +3387,7 @@ static int igc_probe(struct pci_dev *pdev, | |||
3377 | 3387 | ||
3378 | /* Copy the default MAC and PHY function pointers */ | 3388 | /* Copy the default MAC and PHY function pointers */ |
3379 | memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); | 3389 | memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); |
3390 | memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops)); | ||
3380 | 3391 | ||
3381 | /* Initialize skew-specific constants */ | 3392 | /* Initialize skew-specific constants */ |
3382 | err = ei->get_invariants(hw); | 3393 | err = ei->get_invariants(hw); |
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c new file mode 100644 index 000000000000..88583c1d4970 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_phy.c | |||
@@ -0,0 +1,457 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* Copyright (c) 2018 Intel Corporation */ | ||
3 | |||
4 | #include "igc_phy.h" | ||
5 | |||
6 | /** | ||
7 | * igc_check_reset_block - Check if PHY reset is blocked | ||
8 | * @hw: pointer to the HW structure | ||
9 | * | ||
10 | * Read the PHY management control register and check whether a PHY reset | ||
11 | * is blocked. If a reset is not blocked return 0, otherwise | ||
12 | * return IGC_ERR_BLK_PHY_RESET (12). | ||
13 | */ | ||
14 | s32 igc_check_reset_block(struct igc_hw *hw) | ||
15 | { | ||
16 | u32 manc; | ||
17 | |||
18 | manc = rd32(IGC_MANC); | ||
19 | |||
20 | return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ? | ||
21 | IGC_ERR_BLK_PHY_RESET : 0; | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * igc_get_phy_id - Retrieve the PHY ID and revision | ||
26 | * @hw: pointer to the HW structure | ||
27 | * | ||
28 | * Reads the PHY registers and stores the PHY ID and possibly the PHY | ||
29 | * revision in the hardware structure. | ||
30 | */ | ||
31 | s32 igc_get_phy_id(struct igc_hw *hw) | ||
32 | { | ||
33 | struct igc_phy_info *phy = &hw->phy; | ||
34 | s32 ret_val = 0; | ||
35 | u16 phy_id; | ||
36 | |||
37 | ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); | ||
38 | if (ret_val) | ||
39 | goto out; | ||
40 | |||
41 | phy->id = (u32)(phy_id << 16); | ||
42 | usleep_range(200, 500); | ||
43 | ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); | ||
44 | if (ret_val) | ||
45 | goto out; | ||
46 | |||
47 | phy->id |= (u32)(phy_id & PHY_REVISION_MASK); | ||
48 | phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); | ||
49 | |||
50 | out: | ||
51 | return ret_val; | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * igc_phy_has_link - Polls PHY for link | ||
56 | * @hw: pointer to the HW structure | ||
57 | * @iterations: number of times to poll for link | ||
58 | * @usec_interval: delay between polling attempts | ||
59 | * @success: pointer to whether polling was successful or not | ||
60 | * | ||
61 | * Polls the PHY status register for link, 'iterations' number of times. | ||
62 | */ | ||
63 | s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations, | ||
64 | u32 usec_interval, bool *success) | ||
65 | { | ||
66 | u16 i, phy_status; | ||
67 | s32 ret_val = 0; | ||
68 | |||
69 | for (i = 0; i < iterations; i++) { | ||
70 | /* Some PHYs require the PHY_STATUS register to be read | ||
71 | * twice due to the link bit being sticky. No harm doing | ||
72 | * it across the board. | ||
73 | */ | ||
74 | ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); | ||
75 | if (ret_val && usec_interval > 0) { | ||
76 | /* If the first read fails, another entity may have | ||
77 | * ownership of the resources, wait and try again to | ||
78 | * see if they have relinquished the resources yet. | ||
79 | */ | ||
80 | if (usec_interval >= 1000) | ||
81 | mdelay(usec_interval / 1000); | ||
82 | else | ||
83 | udelay(usec_interval); | ||
84 | } | ||
85 | ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); | ||
86 | if (ret_val) | ||
87 | break; | ||
88 | if (phy_status & MII_SR_LINK_STATUS) | ||
89 | break; | ||
90 | if (usec_interval >= 1000) | ||
91 | mdelay(usec_interval / 1000); | ||
92 | else | ||
93 | udelay(usec_interval); | ||
94 | } | ||
95 | |||
96 | *success = (i < iterations) ? true : false; | ||
97 | |||
98 | return ret_val; | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * igc_power_up_phy_copper - Restore copper link in case of PHY power down | ||
103 | * @hw: pointer to the HW structure | ||
104 | * | ||
105 | * In the case of a PHY power down to save power, or to turn off link during a | ||
106 | * driver unload, restore the link to previous settings. | ||
107 | */ | ||
108 | void igc_power_up_phy_copper(struct igc_hw *hw) | ||
109 | { | ||
110 | u16 mii_reg = 0; | ||
111 | |||
112 | /* The PHY will retain its settings across a power down/up cycle */ | ||
113 | hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); | ||
114 | mii_reg &= ~MII_CR_POWER_DOWN; | ||
115 | hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * igc_power_down_phy_copper - Power down copper PHY | ||
120 | * @hw: pointer to the HW structure | ||
121 | * | ||
122 | * Power down PHY to save power when interface is down and wake on lan | ||
123 | * is not enabled. | ||
124 | */ | ||
125 | void igc_power_down_phy_copper(struct igc_hw *hw) | ||
126 | { | ||
127 | u16 mii_reg = 0; | ||
128 | |||
129 | /* The PHY will retain its settings across a power down/up cycle */ | ||
130 | hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); | ||
131 | mii_reg |= MII_CR_POWER_DOWN; | ||
132 | |||
133 | /* Temporary workaround - should be removed when PHY will implement | ||
134 | * IEEE registers as properly | ||
135 | */ | ||
136 | /* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/ | ||
137 | usleep_range(1000, 2000); | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * igc_check_downshift - Checks whether a downshift in speed occurred | ||
142 | * @hw: pointer to the HW structure | ||
143 | * | ||
144 | * Success returns 0, Failure returns 1 | ||
145 | * | ||
146 | * A downshift is detected by querying the PHY link health. | ||
147 | */ | ||
148 | s32 igc_check_downshift(struct igc_hw *hw) | ||
149 | { | ||
150 | struct igc_phy_info *phy = &hw->phy; | ||
151 | u16 phy_data, offset, mask; | ||
152 | s32 ret_val; | ||
153 | |||
154 | switch (phy->type) { | ||
155 | case igc_phy_i225: | ||
156 | default: | ||
157 | /* speed downshift not supported */ | ||
158 | phy->speed_downgraded = false; | ||
159 | ret_val = 0; | ||
160 | goto out; | ||
161 | } | ||
162 | |||
163 | ret_val = phy->ops.read_reg(hw, offset, &phy_data); | ||
164 | |||
165 | if (!ret_val) | ||
166 | phy->speed_downgraded = (phy_data & mask) ? true : false; | ||
167 | |||
168 | out: | ||
169 | return ret_val; | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * igc_phy_hw_reset - PHY hardware reset | ||
174 | * @hw: pointer to the HW structure | ||
175 | * | ||
176 | * Verify the reset block is not blocking us from resetting. Acquire | ||
177 | * semaphore (if necessary) and read/set/write the device control reset | ||
178 | * bit in the PHY. Wait the appropriate delay time for the device to | ||
179 | * reset and release the semaphore (if necessary). | ||
180 | */ | ||
181 | s32 igc_phy_hw_reset(struct igc_hw *hw) | ||
182 | { | ||
183 | struct igc_phy_info *phy = &hw->phy; | ||
184 | s32 ret_val; | ||
185 | u32 ctrl; | ||
186 | |||
187 | ret_val = igc_check_reset_block(hw); | ||
188 | if (ret_val) { | ||
189 | ret_val = 0; | ||
190 | goto out; | ||
191 | } | ||
192 | |||
193 | ret_val = phy->ops.acquire(hw); | ||
194 | if (ret_val) | ||
195 | goto out; | ||
196 | |||
197 | ctrl = rd32(IGC_CTRL); | ||
198 | wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST); | ||
199 | wrfl(); | ||
200 | |||
201 | udelay(phy->reset_delay_us); | ||
202 | |||
203 | wr32(IGC_CTRL, ctrl); | ||
204 | wrfl(); | ||
205 | |||
206 | usleep_range(1500, 2000); | ||
207 | |||
208 | phy->ops.release(hw); | ||
209 | |||
210 | out: | ||
211 | return ret_val; | ||
212 | } | ||
213 | |||
214 | /** | ||
215 | * igc_read_phy_reg_mdic - Read MDI control register | ||
216 | * @hw: pointer to the HW structure | ||
217 | * @offset: register offset to be read | ||
218 | * @data: pointer to the read data | ||
219 | * | ||
220 | * Reads the MDI control register in the PHY at offset and stores the | ||
221 | * information read to data. | ||
222 | */ | ||
223 | static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data) | ||
224 | { | ||
225 | struct igc_phy_info *phy = &hw->phy; | ||
226 | u32 i, mdic = 0; | ||
227 | s32 ret_val = 0; | ||
228 | |||
229 | if (offset > MAX_PHY_REG_ADDRESS) { | ||
230 | hw_dbg("PHY Address %d is out of range\n", offset); | ||
231 | ret_val = -IGC_ERR_PARAM; | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | /* Set up Op-code, Phy Address, and register offset in the MDI | ||
236 | * Control register. The MAC will take care of interfacing with the | ||
237 | * PHY to retrieve the desired data. | ||
238 | */ | ||
239 | mdic = ((offset << IGC_MDIC_REG_SHIFT) | | ||
240 | (phy->addr << IGC_MDIC_PHY_SHIFT) | | ||
241 | (IGC_MDIC_OP_READ)); | ||
242 | |||
243 | wr32(IGC_MDIC, mdic); | ||
244 | |||
245 | /* Poll the ready bit to see if the MDI read completed | ||
246 | * Increasing the time out as testing showed failures with | ||
247 | * the lower time out | ||
248 | */ | ||
249 | for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) { | ||
250 | usleep_range(500, 1000); | ||
251 | mdic = rd32(IGC_MDIC); | ||
252 | if (mdic & IGC_MDIC_READY) | ||
253 | break; | ||
254 | } | ||
255 | if (!(mdic & IGC_MDIC_READY)) { | ||
256 | hw_dbg("MDI Read did not complete\n"); | ||
257 | ret_val = -IGC_ERR_PHY; | ||
258 | goto out; | ||
259 | } | ||
260 | if (mdic & IGC_MDIC_ERROR) { | ||
261 | hw_dbg("MDI Error\n"); | ||
262 | ret_val = -IGC_ERR_PHY; | ||
263 | goto out; | ||
264 | } | ||
265 | *data = (u16)mdic; | ||
266 | |||
267 | out: | ||
268 | return ret_val; | ||
269 | } | ||
270 | |||
271 | /** | ||
272 | * igc_write_phy_reg_mdic - Write MDI control register | ||
273 | * @hw: pointer to the HW structure | ||
274 | * @offset: register offset to write to | ||
275 | * @data: data to write to register at offset | ||
276 | * | ||
277 | * Writes data to MDI control register in the PHY at offset. | ||
278 | */ | ||
279 | static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data) | ||
280 | { | ||
281 | struct igc_phy_info *phy = &hw->phy; | ||
282 | u32 i, mdic = 0; | ||
283 | s32 ret_val = 0; | ||
284 | |||
285 | if (offset > MAX_PHY_REG_ADDRESS) { | ||
286 | hw_dbg("PHY Address %d is out of range\n", offset); | ||
287 | ret_val = -IGC_ERR_PARAM; | ||
288 | goto out; | ||
289 | } | ||
290 | |||
291 | /* Set up Op-code, Phy Address, and register offset in the MDI | ||
292 | * Control register. The MAC will take care of interfacing with the | ||
293 | * PHY to write the desired data. | ||
294 | */ | ||
295 | mdic = (((u32)data) | | ||
296 | (offset << IGC_MDIC_REG_SHIFT) | | ||
297 | (phy->addr << IGC_MDIC_PHY_SHIFT) | | ||
298 | (IGC_MDIC_OP_WRITE)); | ||
299 | |||
300 | wr32(IGC_MDIC, mdic); | ||
301 | |||
302 | /* Poll the ready bit to see if the MDI read completed | ||
303 | * Increasing the time out as testing showed failures with | ||
304 | * the lower time out | ||
305 | */ | ||
306 | for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) { | ||
307 | usleep_range(500, 1000); | ||
308 | mdic = rd32(IGC_MDIC); | ||
309 | if (mdic & IGC_MDIC_READY) | ||
310 | break; | ||
311 | } | ||
312 | if (!(mdic & IGC_MDIC_READY)) { | ||
313 | hw_dbg("MDI Write did not complete\n"); | ||
314 | ret_val = -IGC_ERR_PHY; | ||
315 | goto out; | ||
316 | } | ||
317 | if (mdic & IGC_MDIC_ERROR) { | ||
318 | hw_dbg("MDI Error\n"); | ||
319 | ret_val = -IGC_ERR_PHY; | ||
320 | goto out; | ||
321 | } | ||
322 | |||
323 | out: | ||
324 | return ret_val; | ||
325 | } | ||
326 | |||
327 | /** | ||
328 | * __igc_access_xmdio_reg - Read/write XMDIO register | ||
329 | * @hw: pointer to the HW structure | ||
330 | * @address: XMDIO address to program | ||
331 | * @dev_addr: device address to program | ||
332 | * @data: pointer to value to read/write from/to the XMDIO address | ||
333 | * @read: boolean flag to indicate read or write | ||
334 | */ | ||
335 | static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address, | ||
336 | u8 dev_addr, u16 *data, bool read) | ||
337 | { | ||
338 | s32 ret_val; | ||
339 | |||
340 | ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr); | ||
341 | if (ret_val) | ||
342 | return ret_val; | ||
343 | |||
344 | ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address); | ||
345 | if (ret_val) | ||
346 | return ret_val; | ||
347 | |||
348 | ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA | | ||
349 | dev_addr); | ||
350 | if (ret_val) | ||
351 | return ret_val; | ||
352 | |||
353 | if (read) | ||
354 | ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data); | ||
355 | else | ||
356 | ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data); | ||
357 | if (ret_val) | ||
358 | return ret_val; | ||
359 | |||
360 | /* Recalibrate the device back to 0 */ | ||
361 | ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0); | ||
362 | if (ret_val) | ||
363 | return ret_val; | ||
364 | |||
365 | return ret_val; | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * igc_read_xmdio_reg - Read XMDIO register | ||
370 | * @hw: pointer to the HW structure | ||
371 | * @addr: XMDIO address to program | ||
372 | * @dev_addr: device address to program | ||
373 | * @data: value to be read from the EMI address | ||
374 | */ | ||
375 | static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr, | ||
376 | u8 dev_addr, u16 *data) | ||
377 | { | ||
378 | return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true); | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * igc_write_xmdio_reg - Write XMDIO register | ||
383 | * @hw: pointer to the HW structure | ||
384 | * @addr: XMDIO address to program | ||
385 | * @dev_addr: device address to program | ||
386 | * @data: value to be written to the XMDIO address | ||
387 | */ | ||
388 | static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr, | ||
389 | u8 dev_addr, u16 data) | ||
390 | { | ||
391 | return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false); | ||
392 | } | ||
393 | |||
394 | /** | ||
395 | * igc_write_phy_reg_gpy - Write GPY PHY register | ||
396 | * @hw: pointer to the HW structure | ||
397 | * @offset: register offset to write to | ||
398 | * @data: data to write at register offset | ||
399 | * | ||
400 | * Acquires semaphore, if necessary, then writes the data to PHY register | ||
401 | * at the offset. Release any acquired semaphores before exiting. | ||
402 | */ | ||
403 | s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data) | ||
404 | { | ||
405 | u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT; | ||
406 | s32 ret_val; | ||
407 | |||
408 | offset = offset & GPY_REG_MASK; | ||
409 | |||
410 | if (!dev_addr) { | ||
411 | ret_val = hw->phy.ops.acquire(hw); | ||
412 | if (ret_val) | ||
413 | return ret_val; | ||
414 | ret_val = igc_write_phy_reg_mdic(hw, offset, data); | ||
415 | if (ret_val) | ||
416 | return ret_val; | ||
417 | hw->phy.ops.release(hw); | ||
418 | } else { | ||
419 | ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr, | ||
420 | data); | ||
421 | } | ||
422 | |||
423 | return ret_val; | ||
424 | } | ||
425 | |||
426 | /** | ||
427 | * igc_read_phy_reg_gpy - Read GPY PHY register | ||
428 | * @hw: pointer to the HW structure | ||
429 | * @offset: lower half is register offset to read to | ||
430 | * upper half is MMD to use. | ||
431 | * @data: data to read at register offset | ||
432 | * | ||
433 | * Acquires semaphore, if necessary, then reads the data in the PHY register | ||
434 | * at the offset. Release any acquired semaphores before exiting. | ||
435 | */ | ||
436 | s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data) | ||
437 | { | ||
438 | u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT; | ||
439 | s32 ret_val; | ||
440 | |||
441 | offset = offset & GPY_REG_MASK; | ||
442 | |||
443 | if (!dev_addr) { | ||
444 | ret_val = hw->phy.ops.acquire(hw); | ||
445 | if (ret_val) | ||
446 | return ret_val; | ||
447 | ret_val = igc_read_phy_reg_mdic(hw, offset, data); | ||
448 | if (ret_val) | ||
449 | return ret_val; | ||
450 | hw->phy.ops.release(hw); | ||
451 | } else { | ||
452 | ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr, | ||
453 | data); | ||
454 | } | ||
455 | |||
456 | return ret_val; | ||
457 | } | ||
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.h b/drivers/net/ethernet/intel/igc/igc_phy.h new file mode 100644 index 000000000000..6a62f381559d --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_phy.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* Copyright (c) 2018 Intel Corporation */ | ||
3 | |||
4 | #ifndef _IGC_PHY_H_ | ||
5 | #define _IGC_PHY_H_ | ||
6 | |||
7 | #include "igc_mac.h" | ||
8 | |||
9 | s32 igc_check_reset_block(struct igc_hw *hw); | ||
10 | s32 igc_phy_hw_reset(struct igc_hw *hw); | ||
11 | s32 igc_get_phy_id(struct igc_hw *hw); | ||
12 | s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations, | ||
13 | u32 usec_interval, bool *success); | ||
14 | s32 igc_check_downshift(struct igc_hw *hw); | ||
15 | void igc_power_up_phy_copper(struct igc_hw *hw); | ||
16 | void igc_power_down_phy_copper(struct igc_hw *hw); | ||
17 | s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data); | ||
18 | s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data); | ||
19 | |||
20 | #endif | ||
diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index b5996e474c3c..a1bd3216c906 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h | |||
@@ -39,6 +39,9 @@ | |||
39 | #define IGC_SWSM 0x05B50 /* SW Semaphore */ | 39 | #define IGC_SWSM 0x05B50 /* SW Semaphore */ |
40 | #define IGC_FWSM 0x05B54 /* FW Semaphore */ | 40 | #define IGC_FWSM 0x05B54 /* FW Semaphore */ |
41 | 41 | ||
42 | /* Function Active and Power State to MNG */ | ||
43 | #define IGC_FACTPS 0x05B30 | ||
44 | |||
42 | /* Interrupt Register Description */ | 45 | /* Interrupt Register Description */ |
43 | #define IGC_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */ | 46 | #define IGC_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */ |
44 | #define IGC_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */ | 47 | #define IGC_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */ |