aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel/igc
diff options
context:
space:
mode:
authorSasha Neftin <sasha.neftin@intel.com>2018-10-11 03:17:31 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2018-10-17 16:55:18 -0400
commit5586838fe9ced0980e210b39d635ff3842297448 (patch)
tree1646f8cca19ced662aac1f065426d27344ec5fa9 /drivers/net/ethernet/intel/igc
parentab4056126813c889ee6c8fb24ca8f75b84c981ab (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/Makefile2
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h16
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.c122
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.h1
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h79
-rw-r--r--drivers/net/ethernet/intel/igc/igc_hw.h54
-rw-r--r--drivers/net/ethernet/intel/igc/igc_mac.c45
-rw-r--r--drivers/net/ethernet/intel/igc/igc_mac.h11
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c11
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.c457
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.h20
-rw-r--r--drivers/net/ethernet/intel/igc/igc_regs.h3
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
8obj-$(CONFIG_IGC) += igc.o 8obj-$(CONFIG_IGC) += igc.o
9 9
10igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o 10igc-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
362static 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
370static 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
362static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring) 378static 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 */
133static 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 */
210static 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
255out:
256 return ret_val;
257}
258
190static s32 igc_get_invariants_base(struct igc_hw *hw) 259static 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 */
299static 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 */
313static 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 */
398void 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
489static 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
376const struct igc_info igc_base_info = { 497const 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 */
8void igc_rx_fifo_flush_base(struct igc_hw *hw); 8void igc_rx_fifo_flush_base(struct igc_hw *hw);
9void igc_power_down_phy_copper_base(struct igc_hw *hw);
9 10
10/* Transmit Descriptor - Advanced */ 11/* Transmit Descriptor - Advanced */
11union igc_adv_tx_desc { 12union 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. */
22struct igc_mac_operations { 25struct 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
50enum igc_media_type {
51 igc_media_type_unknown = 0,
52 igc_media_type_copper = 1,
53 igc_num_media_types
54};
55
47enum igc_nvm_type { 56enum 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
114struct 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
104struct igc_nvm_info { 128struct 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
142struct 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
118struct igc_bus_info { 171struct 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 */
501bool 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
533out:
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);
25s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, 26s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
26 u16 *duplex); 27 u16 *duplex);
27 28
29bool igc_enable_mng_pass_thru(struct igc_hw *hw);
30
31enum 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 */
87static void igc_power_up_link(struct igc_adapter *adapter) 89static 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 */
95static void igc_power_down_link(struct igc_adapter *adapter) 103static 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 */
14s32 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 */
31s32 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
50out:
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 */
63s32 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 */
108void 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 */
125void 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 */
148s32 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
168out:
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 */
181s32 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
210out:
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 */
223static 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
267out:
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 */
279static 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
323out:
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 */
335static 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 */
375static 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 */
388static 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 */
403s32 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 */
436s32 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
9s32 igc_check_reset_block(struct igc_hw *hw);
10s32 igc_phy_hw_reset(struct igc_hw *hw);
11s32 igc_get_phy_id(struct igc_hw *hw);
12s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
13 u32 usec_interval, bool *success);
14s32 igc_check_downshift(struct igc_hw *hw);
15void igc_power_up_phy_copper(struct igc_hw *hw);
16void igc_power_down_phy_copper(struct igc_hw *hw);
17s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data);
18s32 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 */