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 | } |
216 | |