diff options
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 | 6 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_base.c | 109 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_defines.h | 52 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_hw.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_i225.c | 349 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_i225.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_mac.c | 170 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_mac.h | 6 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_main.c | 20 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_nvm.c | 215 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_nvm.h | 14 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_regs.h | 3 |
13 files changed, 949 insertions, 3 deletions
diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 8b8022ea590a..2b5378d96c7b 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 | 10 | igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o |
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 88ee451e36fd..6dcf51c112f4 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h | |||
| @@ -131,6 +131,10 @@ enum igc_tx_flags { | |||
| 131 | IGC_TX_FLAGS_CSUM = 0x20, | 131 | IGC_TX_FLAGS_CSUM = 0x20, |
| 132 | }; | 132 | }; |
| 133 | 133 | ||
| 134 | enum igc_boards { | ||
| 135 | board_base, | ||
| 136 | }; | ||
| 137 | |||
| 134 | /* The largest size we can write to the descriptor is 65535. In order to | 138 | /* The largest size we can write to the descriptor is 65535. In order to |
| 135 | * maintain a power of two alignment we have to limit ourselves to 32K. | 139 | * maintain a power of two alignment we have to limit ourselves to 32K. |
| 136 | */ | 140 | */ |
| @@ -342,6 +346,8 @@ struct igc_adapter { | |||
| 342 | spinlock_t nfc_lock; | 346 | spinlock_t nfc_lock; |
| 343 | 347 | ||
| 344 | struct igc_mac_addr *mac_table; | 348 | struct igc_mac_addr *mac_table; |
| 349 | |||
| 350 | struct igc_info ei; | ||
| 345 | }; | 351 | }; |
| 346 | 352 | ||
| 347 | /* igc_desc_unused - calculate if we have unused descriptors */ | 353 | /* igc_desc_unused - calculate if we have unused descriptors */ |
diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c index 4efb47497e6b..2d49814966d3 100644 --- a/drivers/net/ethernet/intel/igc/igc_base.c +++ b/drivers/net/ethernet/intel/igc/igc_base.c | |||
| @@ -54,6 +54,22 @@ out: | |||
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | /** | 56 | /** |
| 57 | * igc_check_for_link_base - Check for link | ||
| 58 | * @hw: pointer to the HW structure | ||
| 59 | * | ||
| 60 | * If sgmii is enabled, then use the pcs register to determine link, otherwise | ||
| 61 | * use the generic interface for determining link. | ||
| 62 | */ | ||
| 63 | static s32 igc_check_for_link_base(struct igc_hw *hw) | ||
| 64 | { | ||
| 65 | s32 ret_val = 0; | ||
| 66 | |||
| 67 | ret_val = igc_check_for_copper_link(hw); | ||
| 68 | |||
| 69 | return ret_val; | ||
| 70 | } | ||
| 71 | |||
| 72 | /** | ||
| 57 | * igc_reset_hw_base - Reset hardware | 73 | * igc_reset_hw_base - Reset hardware |
| 58 | * @hw: pointer to the HW structure | 74 | * @hw: pointer to the HW structure |
| 59 | * | 75 | * |
| @@ -108,11 +124,50 @@ static s32 igc_reset_hw_base(struct igc_hw *hw) | |||
| 108 | } | 124 | } |
| 109 | 125 | ||
| 110 | /** | 126 | /** |
| 127 | * igc_init_nvm_params_base - Init NVM func ptrs. | ||
| 128 | * @hw: pointer to the HW structure | ||
| 129 | */ | ||
| 130 | static s32 igc_init_nvm_params_base(struct igc_hw *hw) | ||
| 131 | { | ||
| 132 | struct igc_nvm_info *nvm = &hw->nvm; | ||
| 133 | u32 eecd = rd32(IGC_EECD); | ||
| 134 | u16 size; | ||
| 135 | |||
| 136 | size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >> | ||
| 137 | IGC_EECD_SIZE_EX_SHIFT); | ||
| 138 | |||
| 139 | /* Added to a constant, "size" becomes the left-shift value | ||
| 140 | * for setting word_size. | ||
| 141 | */ | ||
| 142 | size += NVM_WORD_SIZE_BASE_SHIFT; | ||
| 143 | |||
| 144 | /* Just in case size is out of range, cap it to the largest | ||
| 145 | * EEPROM size supported | ||
| 146 | */ | ||
| 147 | if (size > 15) | ||
| 148 | size = 15; | ||
| 149 | |||
| 150 | nvm->word_size = BIT(size); | ||
| 151 | nvm->opcode_bits = 8; | ||
| 152 | nvm->delay_usec = 1; | ||
| 153 | |||
| 154 | nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8; | ||
| 155 | nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ? | ||
| 156 | 16 : 8; | ||
| 157 | |||
| 158 | if (nvm->word_size == BIT(15)) | ||
| 159 | nvm->page_size = 128; | ||
| 160 | |||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 164 | /** | ||
| 111 | * igc_init_mac_params_base - Init MAC func ptrs. | 165 | * igc_init_mac_params_base - Init MAC func ptrs. |
| 112 | * @hw: pointer to the HW structure | 166 | * @hw: pointer to the HW structure |
| 113 | */ | 167 | */ |
| 114 | static s32 igc_init_mac_params_base(struct igc_hw *hw) | 168 | static s32 igc_init_mac_params_base(struct igc_hw *hw) |
| 115 | { | 169 | { |
| 170 | struct igc_dev_spec_base *dev_spec = &hw->dev_spec._base; | ||
| 116 | struct igc_mac_info *mac = &hw->mac; | 171 | struct igc_mac_info *mac = &hw->mac; |
| 117 | 172 | ||
| 118 | /* Set mta register count */ | 173 | /* Set mta register count */ |
| @@ -125,6 +180,10 @@ static s32 igc_init_mac_params_base(struct igc_hw *hw) | |||
| 125 | mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225; | 180 | mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225; |
| 126 | mac->ops.release_swfw_sync = igc_release_swfw_sync_i225; | 181 | mac->ops.release_swfw_sync = igc_release_swfw_sync_i225; |
| 127 | 182 | ||
| 183 | /* Allow a single clear of the SW semaphore on I225 */ | ||
| 184 | if (mac->type == igc_i225) | ||
| 185 | dev_spec->clear_semaphore_once = true; | ||
| 186 | |||
| 128 | return 0; | 187 | return 0; |
| 129 | } | 188 | } |
| 130 | 189 | ||
| @@ -142,11 +201,44 @@ static s32 igc_get_invariants_base(struct igc_hw *hw) | |||
| 142 | if (ret_val) | 201 | if (ret_val) |
| 143 | goto out; | 202 | goto out; |
| 144 | 203 | ||
| 204 | /* NVM initialization */ | ||
| 205 | ret_val = igc_init_nvm_params_base(hw); | ||
| 206 | switch (hw->mac.type) { | ||
| 207 | case igc_i225: | ||
| 208 | ret_val = igc_init_nvm_params_i225(hw); | ||
| 209 | break; | ||
| 210 | default: | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | |||
| 214 | if (ret_val) | ||
| 215 | goto out; | ||
| 216 | |||
| 145 | out: | 217 | out: |
| 146 | return ret_val; | 218 | return ret_val; |
| 147 | } | 219 | } |
| 148 | 220 | ||
| 149 | /** | 221 | /** |
| 222 | * igc_get_link_up_info_base - Get link speed/duplex info | ||
| 223 | * @hw: pointer to the HW structure | ||
| 224 | * @speed: stores the current speed | ||
| 225 | * @duplex: stores the current duplex | ||
| 226 | * | ||
| 227 | * This is a wrapper function, if using the serial gigabit media independent | ||
| 228 | * interface, use PCS to retrieve the link speed and duplex information. | ||
| 229 | * Otherwise, use the generic function to get the link speed and duplex info. | ||
| 230 | */ | ||
| 231 | static s32 igc_get_link_up_info_base(struct igc_hw *hw, u16 *speed, | ||
| 232 | u16 *duplex) | ||
| 233 | { | ||
| 234 | s32 ret_val; | ||
| 235 | |||
| 236 | ret_val = igc_get_speed_and_duplex_copper(hw, speed, duplex); | ||
| 237 | |||
| 238 | return ret_val; | ||
| 239 | } | ||
| 240 | |||
| 241 | /** | ||
| 150 | * igc_init_hw_base - Initialize hardware | 242 | * igc_init_hw_base - Initialize hardware |
| 151 | * @hw: pointer to the HW structure | 243 | * @hw: pointer to the HW structure |
| 152 | * | 244 | * |
| @@ -185,6 +277,19 @@ static s32 igc_init_hw_base(struct igc_hw *hw) | |||
| 185 | } | 277 | } |
| 186 | 278 | ||
| 187 | /** | 279 | /** |
| 280 | * igc_read_mac_addr_base - Read device MAC address | ||
| 281 | * @hw: pointer to the HW structure | ||
| 282 | */ | ||
| 283 | static s32 igc_read_mac_addr_base(struct igc_hw *hw) | ||
| 284 | { | ||
| 285 | s32 ret_val = 0; | ||
| 286 | |||
| 287 | ret_val = igc_read_mac_addr(hw); | ||
| 288 | |||
| 289 | return ret_val; | ||
| 290 | } | ||
| 291 | |||
| 292 | /** | ||
| 188 | * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable | 293 | * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable |
| 189 | * @hw: pointer to the HW structure | 294 | * @hw: pointer to the HW structure |
| 190 | * | 295 | * |
| @@ -262,6 +367,10 @@ void igc_rx_fifo_flush_base(struct igc_hw *hw) | |||
| 262 | 367 | ||
| 263 | static struct igc_mac_operations igc_mac_ops_base = { | 368 | static struct igc_mac_operations igc_mac_ops_base = { |
| 264 | .init_hw = igc_init_hw_base, | 369 | .init_hw = igc_init_hw_base, |
| 370 | .check_for_link = igc_check_for_link_base, | ||
| 371 | .rar_set = igc_rar_set, | ||
| 372 | .read_mac_addr = igc_read_mac_addr_base, | ||
| 373 | .get_speed_and_duplex = igc_get_link_up_info_base, | ||
| 265 | }; | 374 | }; |
| 266 | 375 | ||
| 267 | const struct igc_info igc_base_info = { | 376 | const struct igc_info igc_base_info = { |
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 3d6c2cee0ad3..e5736577009a 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h | |||
| @@ -35,6 +35,8 @@ | |||
| 35 | */ | 35 | */ |
| 36 | #define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */ | 36 | #define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */ |
| 37 | #define IGC_RAH_POOL_1 0x00040000 | 37 | #define IGC_RAH_POOL_1 0x00040000 |
| 38 | #define IGC_RAL_MAC_ADDR_LEN 4 | ||
| 39 | #define IGC_RAH_MAC_ADDR_LEN 2 | ||
| 38 | 40 | ||
| 39 | /* Error Codes */ | 41 | /* Error Codes */ |
| 40 | #define IGC_SUCCESS 0 | 42 | #define IGC_SUCCESS 0 |
| @@ -57,9 +59,51 @@ | |||
| 57 | #define IGC_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ | 59 | #define IGC_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ |
| 58 | #define IGC_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ | 60 | #define IGC_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ |
| 59 | 61 | ||
| 62 | /* SWFW_SYNC Definitions */ | ||
| 63 | #define IGC_SWFW_EEP_SM 0x1 | ||
| 64 | #define IGC_SWFW_PHY0_SM 0x2 | ||
| 65 | |||
| 66 | /* NVM Control */ | ||
| 60 | /* Number of milliseconds for NVM auto read done after MAC reset. */ | 67 | /* Number of milliseconds for NVM auto read done after MAC reset. */ |
| 61 | #define AUTO_READ_DONE_TIMEOUT 10 | 68 | #define AUTO_READ_DONE_TIMEOUT 10 |
| 62 | #define IGC_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ | 69 | #define IGC_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ |
| 70 | #define IGC_EECD_REQ 0x00000040 /* NVM Access Request */ | ||
| 71 | #define IGC_EECD_GNT 0x00000080 /* NVM Access Grant */ | ||
| 72 | /* NVM Addressing bits based on type 0=small, 1=large */ | ||
| 73 | #define IGC_EECD_ADDR_BITS 0x00000400 | ||
| 74 | #define IGC_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ | ||
| 75 | #define IGC_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ | ||
| 76 | #define IGC_EECD_SIZE_EX_SHIFT 11 | ||
| 77 | #define IGC_EECD_FLUPD_I225 0x00800000 /* Update FLASH */ | ||
| 78 | #define IGC_EECD_FLUDONE_I225 0x04000000 /* Update FLASH done*/ | ||
| 79 | #define IGC_EECD_FLASH_DETECTED_I225 0x00080000 /* FLASH detected */ | ||
| 80 | #define IGC_FLUDONE_ATTEMPTS 20000 | ||
| 81 | #define IGC_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */ | ||
| 82 | |||
| 83 | /* Offset to data in NVM read/write registers */ | ||
| 84 | #define IGC_NVM_RW_REG_DATA 16 | ||
| 85 | #define IGC_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ | ||
| 86 | #define IGC_NVM_RW_REG_START 1 /* Start operation */ | ||
| 87 | #define IGC_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ | ||
| 88 | #define IGC_NVM_POLL_READ 0 /* Flag for polling for read complete */ | ||
| 89 | |||
| 90 | /* NVM Word Offsets */ | ||
| 91 | #define NVM_CHECKSUM_REG 0x003F | ||
| 92 | |||
| 93 | /* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ | ||
| 94 | #define NVM_SUM 0xBABA | ||
| 95 | |||
| 96 | #define NVM_PBA_OFFSET_0 8 | ||
| 97 | #define NVM_PBA_OFFSET_1 9 | ||
| 98 | #define NVM_RESERVED_WORD 0xFFFF | ||
| 99 | #define NVM_PBA_PTR_GUARD 0xFAFA | ||
| 100 | #define NVM_WORD_SIZE_BASE_SHIFT 6 | ||
| 101 | |||
| 102 | /* Collision related configuration parameters */ | ||
| 103 | #define IGC_COLLISION_THRESHOLD 15 | ||
| 104 | #define IGC_CT_SHIFT 4 | ||
| 105 | #define IGC_COLLISION_DISTANCE 63 | ||
| 106 | #define IGC_COLD_SHIFT 12 | ||
| 63 | 107 | ||
| 64 | /* Device Status */ | 108 | /* Device Status */ |
| 65 | #define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ | 109 | #define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ |
| @@ -70,6 +114,14 @@ | |||
| 70 | #define IGC_STATUS_TXOFF 0x00000010 /* transmission paused */ | 114 | #define IGC_STATUS_TXOFF 0x00000010 /* transmission paused */ |
| 71 | #define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ | 115 | #define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ |
| 72 | #define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ | 116 | #define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ |
| 117 | #define IGC_STATUS_SPEED_2500 0x00400000 /* Speed 2.5Gb/s */ | ||
| 118 | |||
| 119 | #define SPEED_10 10 | ||
| 120 | #define SPEED_100 100 | ||
| 121 | #define SPEED_1000 1000 | ||
| 122 | #define SPEED_2500 2500 | ||
| 123 | #define HALF_DUPLEX 1 | ||
| 124 | #define FULL_DUPLEX 2 | ||
| 73 | 125 | ||
| 74 | /* Interrupt Cause Read */ | 126 | /* Interrupt Cause Read */ |
| 75 | #define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */ | 127 | #define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */ |
diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index e31d85f1ee12..107d6461924b 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_nvm.h" | ||
| 14 | #include "igc_i225.h" | 15 | #include "igc_i225.h" |
| 15 | #include "igc_base.h" | 16 | #include "igc_base.h" |
| 16 | 17 | ||
| @@ -56,6 +57,8 @@ struct igc_info { | |||
| 56 | struct igc_nvm_operations *nvm_ops; | 57 | struct igc_nvm_operations *nvm_ops; |
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| 60 | extern const struct igc_info igc_base_info; | ||
| 61 | |||
| 59 | struct igc_mac_info { | 62 | struct igc_mac_info { |
| 60 | struct igc_mac_operations ops; | 63 | struct igc_mac_operations ops; |
| 61 | 64 | ||
diff --git a/drivers/net/ethernet/intel/igc/igc_i225.c b/drivers/net/ethernet/intel/igc/igc_i225.c index fb1487727d79..c25f555aaf82 100644 --- a/drivers/net/ethernet/intel/igc/igc_i225.c +++ b/drivers/net/ethernet/intel/igc/igc_i225.c | |||
| @@ -9,6 +9,32 @@ | |||
| 9 | * igc_get_hw_semaphore_i225 - Acquire hardware semaphore | 9 | * igc_get_hw_semaphore_i225 - Acquire hardware semaphore |
| 10 | * @hw: pointer to the HW structure | 10 | * @hw: pointer to the HW structure |
| 11 | * | 11 | * |
| 12 | * Acquire the necessary semaphores for exclusive access to the EEPROM. | ||
| 13 | * Set the EEPROM access request bit and wait for EEPROM access grant bit. | ||
| 14 | * Return successful if access grant bit set, else clear the request for | ||
| 15 | * EEPROM access and return -IGC_ERR_NVM (-1). | ||
| 16 | */ | ||
| 17 | static s32 igc_acquire_nvm_i225(struct igc_hw *hw) | ||
| 18 | { | ||
| 19 | return igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM); | ||
| 20 | } | ||
| 21 | |||
| 22 | /** | ||
| 23 | * igc_release_nvm_i225 - Release exclusive access to EEPROM | ||
| 24 | * @hw: pointer to the HW structure | ||
| 25 | * | ||
| 26 | * Stop any current commands to the EEPROM and clear the EEPROM request bit, | ||
| 27 | * then release the semaphores acquired. | ||
| 28 | */ | ||
| 29 | static void igc_release_nvm_i225(struct igc_hw *hw) | ||
| 30 | { | ||
| 31 | igc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM); | ||
| 32 | } | ||
| 33 | |||
| 34 | /** | ||
| 35 | * igc_get_hw_semaphore_i225 - Acquire hardware semaphore | ||
| 36 | * @hw: pointer to the HW structure | ||
| 37 | * | ||
| 12 | * Acquire the HW semaphore to access the PHY or NVM | 38 | * Acquire the HW semaphore to access the PHY or NVM |
| 13 | */ | 39 | */ |
| 14 | static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw) | 40 | static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw) |
| @@ -139,3 +165,326 @@ void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask) | |||
| 139 | 165 | ||
| 140 | igc_put_hw_semaphore(hw); | 166 | igc_put_hw_semaphore(hw); |
| 141 | } | 167 | } |
| 168 | |||
| 169 | /** | ||
| 170 | * igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register | ||
| 171 | * @hw: pointer to the HW structure | ||
| 172 | * @offset: offset of word in the Shadow Ram to read | ||
| 173 | * @words: number of words to read | ||
| 174 | * @data: word read from the Shadow Ram | ||
| 175 | * | ||
| 176 | * Reads a 16 bit word from the Shadow Ram using the EERD register. | ||
| 177 | * Uses necessary synchronization semaphores. | ||
| 178 | */ | ||
| 179 | static s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words, | ||
| 180 | u16 *data) | ||
| 181 | { | ||
| 182 | s32 status = 0; | ||
| 183 | u16 i, count; | ||
| 184 | |||
| 185 | /* We cannot hold synchronization semaphores for too long, | ||
| 186 | * because of forceful takeover procedure. However it is more efficient | ||
| 187 | * to read in bursts than synchronizing access for each word. | ||
| 188 | */ | ||
| 189 | for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) { | ||
| 190 | count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ? | ||
| 191 | IGC_EERD_EEWR_MAX_COUNT : (words - i); | ||
| 192 | |||
| 193 | status = hw->nvm.ops.acquire(hw); | ||
| 194 | if (status) | ||
| 195 | break; | ||
| 196 | |||
| 197 | status = igc_read_nvm_eerd(hw, offset, count, data + i); | ||
| 198 | hw->nvm.ops.release(hw); | ||
| 199 | if (status) | ||
| 200 | break; | ||
| 201 | } | ||
| 202 | |||
| 203 | return status; | ||
| 204 | } | ||
| 205 | |||
| 206 | /** | ||
| 207 | * igc_write_nvm_srwr - Write to Shadow Ram using EEWR | ||
| 208 | * @hw: pointer to the HW structure | ||
| 209 | * @offset: offset within the Shadow Ram to be written to | ||
| 210 | * @words: number of words to write | ||
| 211 | * @data: 16 bit word(s) to be written to the Shadow Ram | ||
| 212 | * | ||
| 213 | * Writes data to Shadow Ram at offset using EEWR register. | ||
| 214 | * | ||
| 215 | * If igc_update_nvm_checksum is not called after this function , the | ||
| 216 | * Shadow Ram will most likely contain an invalid checksum. | ||
| 217 | */ | ||
| 218 | static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words, | ||
| 219 | u16 *data) | ||
| 220 | { | ||
| 221 | struct igc_nvm_info *nvm = &hw->nvm; | ||
| 222 | u32 attempts = 100000; | ||
| 223 | u32 i, k, eewr = 0; | ||
| 224 | s32 ret_val = 0; | ||
| 225 | |||
| 226 | /* A check for invalid values: offset too large, too many words, | ||
| 227 | * too many words for the offset, and not enough words. | ||
| 228 | */ | ||
| 229 | if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) || | ||
| 230 | words == 0) { | ||
| 231 | hw_dbg("nvm parameter(s) out of bounds\n"); | ||
| 232 | ret_val = -IGC_ERR_NVM; | ||
| 233 | goto out; | ||
| 234 | } | ||
| 235 | |||
| 236 | for (i = 0; i < words; i++) { | ||
| 237 | eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) | | ||
| 238 | (data[i] << IGC_NVM_RW_REG_DATA) | | ||
| 239 | IGC_NVM_RW_REG_START; | ||
| 240 | |||
| 241 | wr32(IGC_SRWR, eewr); | ||
| 242 | |||
| 243 | for (k = 0; k < attempts; k++) { | ||
| 244 | if (IGC_NVM_RW_REG_DONE & | ||
| 245 | rd32(IGC_SRWR)) { | ||
| 246 | ret_val = 0; | ||
| 247 | break; | ||
| 248 | } | ||
| 249 | udelay(5); | ||
| 250 | } | ||
| 251 | |||
| 252 | if (ret_val) { | ||
| 253 | hw_dbg("Shadow RAM write EEWR timed out\n"); | ||
| 254 | break; | ||
| 255 | } | ||
| 256 | } | ||
| 257 | |||
| 258 | out: | ||
| 259 | return ret_val; | ||
| 260 | } | ||
| 261 | |||
| 262 | /** | ||
| 263 | * igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR | ||
| 264 | * @hw: pointer to the HW structure | ||
| 265 | * @offset: offset within the Shadow RAM to be written to | ||
| 266 | * @words: number of words to write | ||
| 267 | * @data: 16 bit word(s) to be written to the Shadow RAM | ||
| 268 | * | ||
| 269 | * Writes data to Shadow RAM at offset using EEWR register. | ||
| 270 | * | ||
| 271 | * If igc_update_nvm_checksum is not called after this function , the | ||
| 272 | * data will not be committed to FLASH and also Shadow RAM will most likely | ||
| 273 | * contain an invalid checksum. | ||
| 274 | * | ||
| 275 | * If error code is returned, data and Shadow RAM may be inconsistent - buffer | ||
| 276 | * partially written. | ||
| 277 | */ | ||
| 278 | static s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words, | ||
| 279 | u16 *data) | ||
| 280 | { | ||
| 281 | s32 status = 0; | ||
| 282 | u16 i, count; | ||
| 283 | |||
| 284 | /* We cannot hold synchronization semaphores for too long, | ||
| 285 | * because of forceful takeover procedure. However it is more efficient | ||
| 286 | * to write in bursts than synchronizing access for each word. | ||
| 287 | */ | ||
| 288 | for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) { | ||
| 289 | count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ? | ||
| 290 | IGC_EERD_EEWR_MAX_COUNT : (words - i); | ||
| 291 | |||
| 292 | status = hw->nvm.ops.acquire(hw); | ||
| 293 | if (status) | ||
| 294 | break; | ||
| 295 | |||
| 296 | status = igc_write_nvm_srwr(hw, offset, count, data + i); | ||
| 297 | hw->nvm.ops.release(hw); | ||
| 298 | if (status) | ||
| 299 | break; | ||
| 300 | } | ||
| 301 | |||
| 302 | return status; | ||
| 303 | } | ||
| 304 | |||
| 305 | /** | ||
| 306 | * igc_validate_nvm_checksum_i225 - Validate EEPROM checksum | ||
| 307 | * @hw: pointer to the HW structure | ||
| 308 | * | ||
| 309 | * Calculates the EEPROM checksum by reading/adding each word of the EEPROM | ||
| 310 | * and then verifies that the sum of the EEPROM is equal to 0xBABA. | ||
| 311 | */ | ||
| 312 | static s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw) | ||
| 313 | { | ||
| 314 | s32 (*read_op_ptr)(struct igc_hw *hw, u16 offset, u16 count, | ||
| 315 | u16 *data); | ||
| 316 | s32 status = 0; | ||
| 317 | |||
| 318 | status = hw->nvm.ops.acquire(hw); | ||
| 319 | if (status) | ||
| 320 | goto out; | ||
| 321 | |||
| 322 | /* Replace the read function with semaphore grabbing with | ||
| 323 | * the one that skips this for a while. | ||
| 324 | * We have semaphore taken already here. | ||
| 325 | */ | ||
| 326 | read_op_ptr = hw->nvm.ops.read; | ||
| 327 | hw->nvm.ops.read = igc_read_nvm_eerd; | ||
| 328 | |||
| 329 | status = igc_validate_nvm_checksum(hw); | ||
| 330 | |||
| 331 | /* Revert original read operation. */ | ||
| 332 | hw->nvm.ops.read = read_op_ptr; | ||
| 333 | |||
| 334 | hw->nvm.ops.release(hw); | ||
| 335 | |||
| 336 | out: | ||
| 337 | return status; | ||
| 338 | } | ||
| 339 | |||
| 340 | /** | ||
| 341 | * igc_pool_flash_update_done_i225 - Pool FLUDONE status | ||
| 342 | * @hw: pointer to the HW structure | ||
| 343 | */ | ||
| 344 | static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw) | ||
| 345 | { | ||
| 346 | s32 ret_val = -IGC_ERR_NVM; | ||
| 347 | u32 i, reg; | ||
| 348 | |||
| 349 | for (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) { | ||
| 350 | reg = rd32(IGC_EECD); | ||
| 351 | if (reg & IGC_EECD_FLUDONE_I225) { | ||
| 352 | ret_val = 0; | ||
| 353 | break; | ||
| 354 | } | ||
| 355 | udelay(5); | ||
| 356 | } | ||
| 357 | |||
| 358 | return ret_val; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * igc_update_flash_i225 - Commit EEPROM to the flash | ||
| 363 | * @hw: pointer to the HW structure | ||
| 364 | */ | ||
| 365 | static s32 igc_update_flash_i225(struct igc_hw *hw) | ||
| 366 | { | ||
| 367 | s32 ret_val = 0; | ||
| 368 | u32 flup; | ||
| 369 | |||
| 370 | ret_val = igc_pool_flash_update_done_i225(hw); | ||
| 371 | if (ret_val == -IGC_ERR_NVM) { | ||
| 372 | hw_dbg("Flash update time out\n"); | ||
| 373 | goto out; | ||
| 374 | } | ||
| 375 | |||
| 376 | flup = rd32(IGC_EECD) | IGC_EECD_FLUPD_I225; | ||
| 377 | wr32(IGC_EECD, flup); | ||
| 378 | |||
| 379 | ret_val = igc_pool_flash_update_done_i225(hw); | ||
| 380 | if (ret_val) | ||
| 381 | hw_dbg("Flash update time out\n"); | ||
| 382 | else | ||
| 383 | hw_dbg("Flash update complete\n"); | ||
| 384 | |||
| 385 | out: | ||
| 386 | return ret_val; | ||
| 387 | } | ||
| 388 | |||
| 389 | /** | ||
| 390 | * igc_update_nvm_checksum_i225 - Update EEPROM checksum | ||
| 391 | * @hw: pointer to the HW structure | ||
| 392 | * | ||
| 393 | * Updates the EEPROM checksum by reading/adding each word of the EEPROM | ||
| 394 | * up to the checksum. Then calculates the EEPROM checksum and writes the | ||
| 395 | * value to the EEPROM. Next commit EEPROM data onto the Flash. | ||
| 396 | */ | ||
| 397 | static s32 igc_update_nvm_checksum_i225(struct igc_hw *hw) | ||
| 398 | { | ||
| 399 | u16 checksum = 0; | ||
| 400 | s32 ret_val = 0; | ||
| 401 | u16 i, nvm_data; | ||
| 402 | |||
| 403 | /* Read the first word from the EEPROM. If this times out or fails, do | ||
| 404 | * not continue or we could be in for a very long wait while every | ||
| 405 | * EEPROM read fails | ||
| 406 | */ | ||
| 407 | ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data); | ||
| 408 | if (ret_val) { | ||
| 409 | hw_dbg("EEPROM read failed\n"); | ||
| 410 | goto out; | ||
| 411 | } | ||
| 412 | |||
| 413 | ret_val = hw->nvm.ops.acquire(hw); | ||
| 414 | if (ret_val) | ||
| 415 | goto out; | ||
| 416 | |||
| 417 | /* Do not use hw->nvm.ops.write, hw->nvm.ops.read | ||
| 418 | * because we do not want to take the synchronization | ||
| 419 | * semaphores twice here. | ||
| 420 | */ | ||
| 421 | |||
| 422 | for (i = 0; i < NVM_CHECKSUM_REG; i++) { | ||
| 423 | ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data); | ||
| 424 | if (ret_val) { | ||
| 425 | hw->nvm.ops.release(hw); | ||
| 426 | hw_dbg("NVM Read Error while updating checksum.\n"); | ||
| 427 | goto out; | ||
| 428 | } | ||
| 429 | checksum += nvm_data; | ||
| 430 | } | ||
| 431 | checksum = (u16)NVM_SUM - checksum; | ||
| 432 | ret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1, | ||
| 433 | &checksum); | ||
| 434 | if (ret_val) { | ||
| 435 | hw->nvm.ops.release(hw); | ||
| 436 | hw_dbg("NVM Write Error while updating checksum.\n"); | ||
| 437 | goto out; | ||
| 438 | } | ||
| 439 | |||
| 440 | hw->nvm.ops.release(hw); | ||
| 441 | |||
| 442 | ret_val = igc_update_flash_i225(hw); | ||
| 443 | |||
| 444 | out: | ||
| 445 | return ret_val; | ||
| 446 | } | ||
| 447 | |||
| 448 | /** | ||
| 449 | * igc_get_flash_presence_i225 - Check if flash device is detected | ||
| 450 | * @hw: pointer to the HW structure | ||
| 451 | */ | ||
| 452 | bool igc_get_flash_presence_i225(struct igc_hw *hw) | ||
| 453 | { | ||
| 454 | bool ret_val = false; | ||
| 455 | u32 eec = 0; | ||
| 456 | |||
| 457 | eec = rd32(IGC_EECD); | ||
| 458 | if (eec & IGC_EECD_FLASH_DETECTED_I225) | ||
| 459 | ret_val = true; | ||
| 460 | |||
| 461 | return ret_val; | ||
| 462 | } | ||
| 463 | |||
| 464 | /** | ||
| 465 | * igc_init_nvm_params_i225 - Init NVM func ptrs. | ||
| 466 | * @hw: pointer to the HW structure | ||
| 467 | */ | ||
| 468 | s32 igc_init_nvm_params_i225(struct igc_hw *hw) | ||
| 469 | { | ||
| 470 | struct igc_nvm_info *nvm = &hw->nvm; | ||
| 471 | |||
| 472 | nvm->ops.acquire = igc_acquire_nvm_i225; | ||
| 473 | nvm->ops.release = igc_release_nvm_i225; | ||
| 474 | |||
| 475 | /* NVM Function Pointers */ | ||
| 476 | if (igc_get_flash_presence_i225(hw)) { | ||
| 477 | hw->nvm.type = igc_nvm_flash_hw; | ||
| 478 | nvm->ops.read = igc_read_nvm_srrd_i225; | ||
| 479 | nvm->ops.write = igc_write_nvm_srwr_i225; | ||
| 480 | nvm->ops.validate = igc_validate_nvm_checksum_i225; | ||
| 481 | nvm->ops.update = igc_update_nvm_checksum_i225; | ||
| 482 | } else { | ||
| 483 | hw->nvm.type = igc_nvm_invm; | ||
| 484 | nvm->ops.read = igc_read_nvm_eerd; | ||
| 485 | nvm->ops.write = NULL; | ||
| 486 | nvm->ops.validate = NULL; | ||
| 487 | nvm->ops.update = NULL; | ||
| 488 | } | ||
| 489 | return 0; | ||
| 490 | } | ||
diff --git a/drivers/net/ethernet/intel/igc/igc_i225.h b/drivers/net/ethernet/intel/igc/igc_i225.h index 461cd8c7e352..7b66e1f9c0e6 100644 --- a/drivers/net/ethernet/intel/igc/igc_i225.h +++ b/drivers/net/ethernet/intel/igc/igc_i225.h | |||
| @@ -7,4 +7,7 @@ | |||
| 7 | s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask); | 7 | s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask); |
| 8 | void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask); | 8 | void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask); |
| 9 | 9 | ||
| 10 | s32 igc_init_nvm_params_i225(struct igc_hw *hw); | ||
| 11 | bool igc_get_flash_presence_i225(struct igc_hw *hw); | ||
| 12 | |||
| 10 | #endif | 13 | #endif |
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 90a98ee14550..249ac03b05d8 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c | |||
| @@ -275,6 +275,129 @@ void igc_clear_hw_cntrs_base(struct igc_hw *hw) | |||
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | /** | 277 | /** |
| 278 | * igc_rar_set - Set receive address register | ||
| 279 | * @hw: pointer to the HW structure | ||
| 280 | * @addr: pointer to the receive address | ||
| 281 | * @index: receive address array register | ||
| 282 | * | ||
| 283 | * Sets the receive address array register at index to the address passed | ||
| 284 | * in by addr. | ||
| 285 | */ | ||
| 286 | void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index) | ||
| 287 | { | ||
| 288 | u32 rar_low, rar_high; | ||
| 289 | |||
| 290 | /* HW expects these in little endian so we reverse the byte order | ||
| 291 | * from network order (big endian) to little endian | ||
| 292 | */ | ||
| 293 | rar_low = ((u32)addr[0] | | ||
| 294 | ((u32)addr[1] << 8) | | ||
| 295 | ((u32)addr[2] << 16) | ((u32)addr[3] << 24)); | ||
| 296 | |||
| 297 | rar_high = ((u32)addr[4] | ((u32)addr[5] << 8)); | ||
| 298 | |||
| 299 | /* If MAC address zero, no need to set the AV bit */ | ||
| 300 | if (rar_low || rar_high) | ||
| 301 | rar_high |= IGC_RAH_AV; | ||
| 302 | |||
| 303 | /* Some bridges will combine consecutive 32-bit writes into | ||
| 304 | * a single burst write, which will malfunction on some parts. | ||
| 305 | * The flushes avoid this. | ||
| 306 | */ | ||
| 307 | wr32(IGC_RAL(index), rar_low); | ||
| 308 | wrfl(); | ||
| 309 | wr32(IGC_RAH(index), rar_high); | ||
| 310 | wrfl(); | ||
| 311 | } | ||
| 312 | |||
| 313 | /** | ||
| 314 | * igc_check_for_copper_link - Check for link (Copper) | ||
| 315 | * @hw: pointer to the HW structure | ||
| 316 | * | ||
| 317 | * Checks to see of the link status of the hardware has changed. If a | ||
| 318 | * change in link status has been detected, then we read the PHY registers | ||
| 319 | * to get the current speed/duplex if link exists. | ||
| 320 | */ | ||
| 321 | s32 igc_check_for_copper_link(struct igc_hw *hw) | ||
| 322 | { | ||
| 323 | struct igc_mac_info *mac = &hw->mac; | ||
| 324 | s32 ret_val; | ||
| 325 | bool link; | ||
| 326 | |||
| 327 | /* We only want to go out to the PHY registers to see if Auto-Neg | ||
| 328 | * has completed and/or if our link status has changed. The | ||
| 329 | * get_link_status flag is set upon receiving a Link Status | ||
| 330 | * Change or Rx Sequence Error interrupt. | ||
| 331 | */ | ||
| 332 | if (!mac->get_link_status) { | ||
| 333 | ret_val = 0; | ||
| 334 | goto out; | ||
| 335 | } | ||
| 336 | |||
| 337 | /* First we want to see if the MII Status Register reports | ||
| 338 | * link. If so, then we want to get the current speed/duplex | ||
| 339 | * of the PHY. | ||
| 340 | */ | ||
| 341 | if (ret_val) | ||
| 342 | goto out; | ||
| 343 | |||
| 344 | if (!link) | ||
| 345 | goto out; /* No link detected */ | ||
| 346 | |||
| 347 | mac->get_link_status = false; | ||
| 348 | |||
| 349 | /* Check if there was DownShift, must be checked | ||
| 350 | * immediately after link-up | ||
| 351 | */ | ||
| 352 | |||
| 353 | /* If we are forcing speed/duplex, then we simply return since | ||
| 354 | * we have already determined whether we have link or not. | ||
| 355 | */ | ||
| 356 | if (!mac->autoneg) { | ||
| 357 | ret_val = -IGC_ERR_CONFIG; | ||
| 358 | goto out; | ||
| 359 | } | ||
| 360 | |||
| 361 | /* Auto-Neg is enabled. Auto Speed Detection takes care | ||
| 362 | * of MAC speed/duplex configuration. So we only need to | ||
| 363 | * configure Collision Distance in the MAC. | ||
| 364 | */ | ||
| 365 | igc_config_collision_dist(hw); | ||
| 366 | |||
| 367 | /* Configure Flow Control now that Auto-Neg has completed. | ||
| 368 | * First, we need to restore the desired flow control | ||
| 369 | * settings because we may have had to re-autoneg with a | ||
| 370 | * different link partner. | ||
| 371 | */ | ||
| 372 | if (ret_val) | ||
| 373 | hw_dbg("Error configuring flow control\n"); | ||
| 374 | |||
| 375 | out: | ||
| 376 | return ret_val; | ||
| 377 | } | ||
| 378 | |||
| 379 | /** | ||
| 380 | * igc_config_collision_dist - Configure collision distance | ||
| 381 | * @hw: pointer to the HW structure | ||
| 382 | * | ||
| 383 | * Configures the collision distance to the default value and is used | ||
| 384 | * during link setup. Currently no func pointer exists and all | ||
| 385 | * implementations are handled in the generic version of this function. | ||
| 386 | */ | ||
| 387 | void igc_config_collision_dist(struct igc_hw *hw) | ||
| 388 | { | ||
| 389 | u32 tctl; | ||
| 390 | |||
| 391 | tctl = rd32(IGC_TCTL); | ||
| 392 | |||
| 393 | tctl &= ~IGC_TCTL_COLD; | ||
| 394 | tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT; | ||
| 395 | |||
| 396 | wr32(IGC_TCTL, tctl); | ||
| 397 | wrfl(); | ||
| 398 | } | ||
| 399 | |||
| 400 | /** | ||
| 278 | * igc_get_auto_rd_done - Check for auto read completion | 401 | * igc_get_auto_rd_done - Check for auto read completion |
| 279 | * @hw: pointer to the HW structure | 402 | * @hw: pointer to the HW structure |
| 280 | * | 403 | * |
| @@ -303,6 +426,53 @@ out: | |||
| 303 | } | 426 | } |
| 304 | 427 | ||
| 305 | /** | 428 | /** |
| 429 | * igc_get_speed_and_duplex_copper - Retrieve current speed/duplex | ||
| 430 | * @hw: pointer to the HW structure | ||
| 431 | * @speed: stores the current speed | ||
| 432 | * @duplex: stores the current duplex | ||
| 433 | * | ||
| 434 | * Read the status register for the current speed/duplex and store the current | ||
| 435 | * speed and duplex for copper connections. | ||
| 436 | */ | ||
| 437 | s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, | ||
| 438 | u16 *duplex) | ||
| 439 | { | ||
| 440 | u32 status; | ||
| 441 | |||
| 442 | status = rd32(IGC_STATUS); | ||
| 443 | if (status & IGC_STATUS_SPEED_1000) { | ||
| 444 | /* For I225, STATUS will indicate 1G speed in both 1 Gbps | ||
| 445 | * and 2.5 Gbps link modes. An additional bit is used | ||
| 446 | * to differentiate between 1 Gbps and 2.5 Gbps. | ||
| 447 | */ | ||
| 448 | if (hw->mac.type == igc_i225 && | ||
| 449 | (status & IGC_STATUS_SPEED_2500)) { | ||
| 450 | *speed = SPEED_2500; | ||
| 451 | hw_dbg("2500 Mbs, "); | ||
| 452 | } else { | ||
| 453 | *speed = SPEED_1000; | ||
| 454 | hw_dbg("1000 Mbs, "); | ||
| 455 | } | ||
| 456 | } else if (status & IGC_STATUS_SPEED_100) { | ||
| 457 | *speed = SPEED_100; | ||
| 458 | hw_dbg("100 Mbs, "); | ||
| 459 | } else { | ||
| 460 | *speed = SPEED_10; | ||
| 461 | hw_dbg("10 Mbs, "); | ||
| 462 | } | ||
| 463 | |||
| 464 | if (status & IGC_STATUS_FD) { | ||
| 465 | *duplex = FULL_DUPLEX; | ||
| 466 | hw_dbg("Full Duplex\n"); | ||
| 467 | } else { | ||
| 468 | *duplex = HALF_DUPLEX; | ||
| 469 | hw_dbg("Half Duplex\n"); | ||
| 470 | } | ||
| 471 | |||
| 472 | return 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | /** | ||
| 306 | * igc_put_hw_semaphore - Release hardware semaphore | 476 | * igc_put_hw_semaphore - Release hardware semaphore |
| 307 | * @hw: pointer to the HW structure | 477 | * @hw: pointer to the HW structure |
| 308 | * | 478 | * |
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h index 88bdb8dd6f3f..88599661d017 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.h +++ b/drivers/net/ethernet/intel/igc/igc_mac.h | |||
| @@ -13,10 +13,16 @@ | |||
| 13 | 13 | ||
| 14 | /* forward declaration */ | 14 | /* forward declaration */ |
| 15 | s32 igc_disable_pcie_master(struct igc_hw *hw); | 15 | s32 igc_disable_pcie_master(struct igc_hw *hw); |
| 16 | s32 igc_check_for_copper_link(struct igc_hw *hw); | ||
| 16 | void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count); | 17 | void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count); |
| 17 | s32 igc_setup_link(struct igc_hw *hw); | 18 | s32 igc_setup_link(struct igc_hw *hw); |
| 18 | void igc_clear_hw_cntrs_base(struct igc_hw *hw); | 19 | void igc_clear_hw_cntrs_base(struct igc_hw *hw); |
| 19 | s32 igc_get_auto_rd_done(struct igc_hw *hw); | 20 | s32 igc_get_auto_rd_done(struct igc_hw *hw); |
| 20 | void igc_put_hw_semaphore(struct igc_hw *hw); | 21 | void igc_put_hw_semaphore(struct igc_hw *hw); |
| 22 | void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index); | ||
| 23 | void igc_config_collision_dist(struct igc_hw *hw); | ||
| 24 | |||
| 25 | s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, | ||
| 26 | u16 *duplex); | ||
| 21 | 27 | ||
| 22 | #endif | 28 | #endif |
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index f2ad49fcd39b..115fc2a544d7 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c | |||
| @@ -27,9 +27,13 @@ static const char igc_driver_string[] = DRV_SUMMARY; | |||
| 27 | static const char igc_copyright[] = | 27 | static const char igc_copyright[] = |
| 28 | "Copyright(c) 2018 Intel Corporation."; | 28 | "Copyright(c) 2018 Intel Corporation."; |
| 29 | 29 | ||
| 30 | static const struct igc_info *igc_info_tbl[] = { | ||
| 31 | [board_base] = &igc_base_info, | ||
| 32 | }; | ||
| 33 | |||
| 30 | static const struct pci_device_id igc_pci_tbl[] = { | 34 | static const struct pci_device_id igc_pci_tbl[] = { |
| 31 | { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM) }, | 35 | { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_LM), board_base }, |
| 32 | { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V) }, | 36 | { PCI_VDEVICE(INTEL, IGC_DEV_ID_I225_V), board_base }, |
| 33 | /* required last entry */ | 37 | /* required last entry */ |
| 34 | {0, } | 38 | {0, } |
| 35 | }; | 39 | }; |
| @@ -3289,6 +3293,7 @@ static int igc_probe(struct pci_dev *pdev, | |||
| 3289 | struct igc_adapter *adapter; | 3293 | struct igc_adapter *adapter; |
| 3290 | struct net_device *netdev; | 3294 | struct net_device *netdev; |
| 3291 | struct igc_hw *hw; | 3295 | struct igc_hw *hw; |
| 3296 | const struct igc_info *ei = igc_info_tbl[ent->driver_data]; | ||
| 3292 | int err, pci_using_dac; | 3297 | int err, pci_using_dac; |
| 3293 | 3298 | ||
| 3294 | err = pci_enable_device_mem(pdev); | 3299 | err = pci_enable_device_mem(pdev); |
| @@ -3370,6 +3375,14 @@ static int igc_probe(struct pci_dev *pdev, | |||
| 3370 | hw->subsystem_vendor_id = pdev->subsystem_vendor; | 3375 | hw->subsystem_vendor_id = pdev->subsystem_vendor; |
| 3371 | hw->subsystem_device_id = pdev->subsystem_device; | 3376 | hw->subsystem_device_id = pdev->subsystem_device; |
| 3372 | 3377 | ||
| 3378 | /* Copy the default MAC and PHY function pointers */ | ||
| 3379 | memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); | ||
| 3380 | |||
| 3381 | /* Initialize skew-specific constants */ | ||
| 3382 | err = ei->get_invariants(hw); | ||
| 3383 | if (err) | ||
| 3384 | goto err_sw_init; | ||
| 3385 | |||
| 3373 | /* setup the private structure */ | 3386 | /* setup the private structure */ |
| 3374 | err = igc_sw_init(adapter); | 3387 | err = igc_sw_init(adapter); |
| 3375 | if (err) | 3388 | if (err) |
| @@ -3403,6 +3416,9 @@ static int igc_probe(struct pci_dev *pdev, | |||
| 3403 | /* carrier off reporting is important to ethtool even BEFORE open */ | 3416 | /* carrier off reporting is important to ethtool even BEFORE open */ |
| 3404 | netif_carrier_off(netdev); | 3417 | netif_carrier_off(netdev); |
| 3405 | 3418 | ||
| 3419 | /* Check if Media Autosense is enabled */ | ||
| 3420 | adapter->ei = *ei; | ||
| 3421 | |||
| 3406 | /* print pcie link status and MAC address */ | 3422 | /* print pcie link status and MAC address */ |
| 3407 | pcie_print_link_status(pdev); | 3423 | pcie_print_link_status(pdev); |
| 3408 | netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr); | 3424 | netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr); |
diff --git a/drivers/net/ethernet/intel/igc/igc_nvm.c b/drivers/net/ethernet/intel/igc/igc_nvm.c new file mode 100644 index 000000000000..58f81aba0144 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_nvm.c | |||
| @@ -0,0 +1,215 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Copyright (c) 2018 Intel Corporation */ | ||
| 3 | |||
| 4 | #include "igc_mac.h" | ||
| 5 | #include "igc_nvm.h" | ||
| 6 | |||
| 7 | /** | ||
| 8 | * igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion | ||
| 9 | * @hw: pointer to the HW structure | ||
| 10 | * @ee_reg: EEPROM flag for polling | ||
| 11 | * | ||
| 12 | * Polls the EEPROM status bit for either read or write completion based | ||
| 13 | * upon the value of 'ee_reg'. | ||
| 14 | */ | ||
| 15 | static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg) | ||
| 16 | { | ||
| 17 | s32 ret_val = -IGC_ERR_NVM; | ||
| 18 | u32 attempts = 100000; | ||
| 19 | u32 i, reg = 0; | ||
| 20 | |||
| 21 | for (i = 0; i < attempts; i++) { | ||
| 22 | if (ee_reg == IGC_NVM_POLL_READ) | ||
| 23 | reg = rd32(IGC_EERD); | ||
| 24 | else | ||
| 25 | reg = rd32(IGC_EEWR); | ||
| 26 | |||
| 27 | if (reg & IGC_NVM_RW_REG_DONE) { | ||
| 28 | ret_val = 0; | ||
| 29 | break; | ||
| 30 | } | ||
| 31 | |||
| 32 | udelay(5); | ||
| 33 | } | ||
| 34 | |||
| 35 | return ret_val; | ||
| 36 | } | ||
| 37 | |||
| 38 | /** | ||
| 39 | * igc_acquire_nvm - Generic request for access to EEPROM | ||
| 40 | * @hw: pointer to the HW structure | ||
| 41 | * | ||
| 42 | * Set the EEPROM access request bit and wait for EEPROM access grant bit. | ||
| 43 | * Return successful if access grant bit set, else clear the request for | ||
| 44 | * EEPROM access and return -IGC_ERR_NVM (-1). | ||
| 45 | */ | ||
| 46 | s32 igc_acquire_nvm(struct igc_hw *hw) | ||
| 47 | { | ||
| 48 | s32 timeout = IGC_NVM_GRANT_ATTEMPTS; | ||
| 49 | u32 eecd = rd32(IGC_EECD); | ||
| 50 | s32 ret_val = 0; | ||
| 51 | |||
| 52 | wr32(IGC_EECD, eecd | IGC_EECD_REQ); | ||
| 53 | eecd = rd32(IGC_EECD); | ||
| 54 | |||
| 55 | while (timeout) { | ||
| 56 | if (eecd & IGC_EECD_GNT) | ||
| 57 | break; | ||
| 58 | udelay(5); | ||
| 59 | eecd = rd32(IGC_EECD); | ||
| 60 | timeout--; | ||
| 61 | } | ||
| 62 | |||
| 63 | if (!timeout) { | ||
| 64 | eecd &= ~IGC_EECD_REQ; | ||
| 65 | wr32(IGC_EECD, eecd); | ||
| 66 | hw_dbg("Could not acquire NVM grant\n"); | ||
| 67 | ret_val = -IGC_ERR_NVM; | ||
| 68 | } | ||
| 69 | |||
| 70 | return ret_val; | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * igc_release_nvm - Release exclusive access to EEPROM | ||
| 75 | * @hw: pointer to the HW structure | ||
| 76 | * | ||
| 77 | * Stop any current commands to the EEPROM and clear the EEPROM request bit. | ||
| 78 | */ | ||
| 79 | void igc_release_nvm(struct igc_hw *hw) | ||
| 80 | { | ||
| 81 | u32 eecd; | ||
| 82 | |||
| 83 | eecd = rd32(IGC_EECD); | ||
| 84 | eecd &= ~IGC_EECD_REQ; | ||
| 85 | wr32(IGC_EECD, eecd); | ||
| 86 | } | ||
| 87 | |||
| 88 | /** | ||
| 89 | * igc_read_nvm_eerd - Reads EEPROM using EERD register | ||
| 90 | * @hw: pointer to the HW structure | ||
| 91 | * @offset: offset of word in the EEPROM to read | ||
| 92 | * @words: number of words to read | ||
| 93 | * @data: word read from the EEPROM | ||
| 94 | * | ||
| 95 | * Reads a 16 bit word from the EEPROM using the EERD register. | ||
| 96 | */ | ||
| 97 | s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data) | ||
| 98 | { | ||
| 99 | struct igc_nvm_info *nvm = &hw->nvm; | ||
| 100 | u32 i, eerd = 0; | ||
| 101 | s32 ret_val = 0; | ||
| 102 | |||
| 103 | /* A check for invalid values: offset too large, too many words, | ||
| 104 | * and not enough words. | ||
| 105 | */ | ||
| 106 | if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) || | ||
| 107 | words == 0) { | ||
| 108 | hw_dbg("nvm parameter(s) out of bounds\n"); | ||
| 109 | ret_val = -IGC_ERR_NVM; | ||
| 110 | goto out; | ||
| 111 | } | ||
| 112 | |||
| 113 | for (i = 0; i < words; i++) { | ||
| 114 | eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) + | ||
| 115 | IGC_NVM_RW_REG_START; | ||
| 116 | |||
| 117 | wr32(IGC_EERD, eerd); | ||
| 118 | ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ); | ||
| 119 | if (ret_val) | ||
| 120 | break; | ||
| 121 | |||
| 122 | data[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA); | ||
| 123 | } | ||
| 124 | |||
| 125 | out: | ||
| 126 | return ret_val; | ||
| 127 | } | ||
| 128 | |||
| 129 | /** | ||
| 130 | * igc_read_mac_addr - Read device MAC address | ||
| 131 | * @hw: pointer to the HW structure | ||
| 132 | */ | ||
| 133 | s32 igc_read_mac_addr(struct igc_hw *hw) | ||
| 134 | { | ||
| 135 | u32 rar_high; | ||
| 136 | u32 rar_low; | ||
| 137 | u16 i; | ||
| 138 | |||
| 139 | rar_high = rd32(IGC_RAH(0)); | ||
| 140 | rar_low = rd32(IGC_RAL(0)); | ||
| 141 | |||
| 142 | for (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++) | ||
| 143 | hw->mac.perm_addr[i] = (u8)(rar_low >> (i * 8)); | ||
| 144 | |||
| 145 | for (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++) | ||
| 146 | hw->mac.perm_addr[i + 4] = (u8)(rar_high >> (i * 8)); | ||
| 147 | |||
| 148 | for (i = 0; i < ETH_ALEN; i++) | ||
| 149 | hw->mac.addr[i] = hw->mac.perm_addr[i]; | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | /** | ||
| 155 | * igc_validate_nvm_checksum - Validate EEPROM checksum | ||
| 156 | * @hw: pointer to the HW structure | ||
| 157 | * | ||
| 158 | * Calculates the EEPROM checksum by reading/adding each word of the EEPROM | ||
| 159 | * and then verifies that the sum of the EEPROM is equal to 0xBABA. | ||
| 160 | */ | ||
| 161 | s32 igc_validate_nvm_checksum(struct igc_hw *hw) | ||
| 162 | { | ||
| 163 | u16 checksum = 0; | ||
| 164 | u16 i, nvm_data; | ||
| 165 | s32 ret_val = 0; | ||
| 166 | |||
| 167 | for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { | ||
| 168 | ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); | ||
| 169 | if (ret_val) { | ||
| 170 | hw_dbg("NVM Read Error\n"); | ||
| 171 | goto out; | ||
| 172 | } | ||
| 173 | checksum += nvm_data; | ||
| 174 | } | ||
| 175 | |||
| 176 | if (checksum != (u16)NVM_SUM) { | ||
| 177 | hw_dbg("NVM Checksum Invalid\n"); | ||
| 178 | ret_val = -IGC_ERR_NVM; | ||
| 179 | goto out; | ||
| 180 | } | ||
| 181 | |||
| 182 | out: | ||
| 183 | return ret_val; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * igc_update_nvm_checksum - Update EEPROM checksum | ||
| 188 | * @hw: pointer to the HW structure | ||
| 189 | * | ||
| 190 | * Updates the EEPROM checksum by reading/adding each word of the EEPROM | ||
| 191 | * up to the checksum. Then calculates the EEPROM checksum and writes the | ||
| 192 | * value to the EEPROM. | ||
| 193 | */ | ||
| 194 | s32 igc_update_nvm_checksum(struct igc_hw *hw) | ||
| 195 | { | ||
| 196 | u16 checksum = 0; | ||
| 197 | u16 i, nvm_data; | ||
| 198 | s32 ret_val; | ||
| 199 | |||
| 200 | for (i = 0; i < NVM_CHECKSUM_REG; i++) { | ||
| 201 | ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); | ||
| 202 | if (ret_val) { | ||
| 203 | hw_dbg("NVM Read Error while updating checksum.\n"); | ||
| 204 | goto out; | ||
| 205 | } | ||
| 206 | checksum += nvm_data; | ||
| 207 | } | ||
| 208 | checksum = (u16)NVM_SUM - checksum; | ||
| 209 | ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum); | ||
| 210 | if (ret_val) | ||
| 211 | hw_dbg("NVM Write Error while updating checksum.\n"); | ||
| 212 | |||
| 213 | out: | ||
| 214 | return ret_val; | ||
| 215 | } | ||
diff --git a/drivers/net/ethernet/intel/igc/igc_nvm.h b/drivers/net/ethernet/intel/igc/igc_nvm.h new file mode 100644 index 000000000000..f9fc2e9cfb03 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_nvm.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* Copyright (c) 2018 Intel Corporation */ | ||
| 3 | |||
| 4 | #ifndef _IGC_NVM_H_ | ||
| 5 | #define _IGC_NVM_H_ | ||
| 6 | |||
| 7 | s32 igc_acquire_nvm(struct igc_hw *hw); | ||
| 8 | void igc_release_nvm(struct igc_hw *hw); | ||
| 9 | s32 igc_read_mac_addr(struct igc_hw *hw); | ||
| 10 | s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data); | ||
| 11 | s32 igc_validate_nvm_checksum(struct igc_hw *hw); | ||
| 12 | s32 igc_update_nvm_checksum(struct igc_hw *hw); | ||
| 13 | |||
| 14 | #endif | ||
diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index c57f573fb864..b5996e474c3c 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h | |||
| @@ -191,6 +191,9 @@ | |||
| 191 | /* Management registers */ | 191 | /* Management registers */ |
| 192 | #define IGC_MANC 0x05820 /* Management Control - RW */ | 192 | #define IGC_MANC 0x05820 /* Management Control - RW */ |
| 193 | 193 | ||
| 194 | /* Shadow Ram Write Register - RW */ | ||
| 195 | #define IGC_SRWR 0x12018 | ||
| 196 | |||
| 194 | /* forward declaration */ | 197 | /* forward declaration */ |
| 195 | struct igc_hw; | 198 | struct igc_hw; |
| 196 | u32 igc_rd32(struct igc_hw *hw, u32 reg); | 199 | u32 igc_rd32(struct igc_hw *hw, u32 reg); |
