xref: /netbsd-src/sys/dev/pci/igc/igc_nvm.c (revision fb38d839b48b9b6204dbbee1672454d6e719ba01)
1 /*	$NetBSD: igc_nvm.c,v 1.2 2023/10/04 07:35:27 rin Exp $	*/
2 /*	$OpenBSD: igc_nvm.c,v 1.1 2021/10/31 14:52:57 patrick Exp $	*/
3 /*-
4  * Copyright 2021 Intel Corp
5  * Copyright 2021 Rubicon Communications, LLC (Netgate)
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include <sys/cdefs.h>
10 __KERNEL_RCSID(0, "$NetBSD: igc_nvm.c,v 1.2 2023/10/04 07:35:27 rin Exp $");
11 
12 #include <dev/pci/igc/igc_api.h>
13 
14 /**
15  *  igc_init_nvm_ops_generic - Initialize NVM function pointers
16  *  @hw: pointer to the HW structure
17  *
18  *  Setups up the function pointers to no-op functions
19  **/
20 void
igc_init_nvm_ops_generic(struct igc_hw * hw)21 igc_init_nvm_ops_generic(struct igc_hw *hw)
22 {
23 	struct igc_nvm_info *nvm = &hw->nvm;
24 	DEBUGFUNC("igc_init_nvm_ops_generic");
25 
26 	/* Initialize function pointers */
27 	nvm->ops.init_params = igc_null_ops_generic;
28 	nvm->ops.acquire = igc_null_ops_generic;
29 	nvm->ops.read = igc_null_read_nvm;
30 	nvm->ops.release = igc_null_nvm_generic;
31 	nvm->ops.reload = igc_reload_nvm_generic;
32 	nvm->ops.update = igc_null_ops_generic;
33 	nvm->ops.validate = igc_null_ops_generic;
34 	nvm->ops.write = igc_null_write_nvm;
35 }
36 
37 /**
38  *  igc_null_nvm_read - No-op function, return 0
39  *  @hw: pointer to the HW structure
40  *  @a: dummy variable
41  *  @b: dummy variable
42  *  @c: dummy variable
43  **/
44 int
igc_null_read_nvm(struct igc_hw IGC_UNUSEDARG * hw,uint16_t IGC_UNUSEDARG a,uint16_t IGC_UNUSEDARG b,uint16_t IGC_UNUSEDARG * c)45 igc_null_read_nvm(struct igc_hw IGC_UNUSEDARG *hw, uint16_t IGC_UNUSEDARG a,
46     uint16_t IGC_UNUSEDARG b, uint16_t IGC_UNUSEDARG *c)
47 {
48 	DEBUGFUNC("igc_null_read_nvm");
49 	return IGC_SUCCESS;
50 }
51 
52 /**
53  *  igc_null_nvm_generic - No-op function, return void
54  *  @hw: pointer to the HW structure
55  **/
56 void
igc_null_nvm_generic(struct igc_hw IGC_UNUSEDARG * hw)57 igc_null_nvm_generic(struct igc_hw IGC_UNUSEDARG *hw)
58 {
59 	DEBUGFUNC("igc_null_nvm_generic");
60 	return;
61 }
62 
63 /**
64  *  igc_reload_nvm_generic - Reloads EEPROM
65  *  @hw: pointer to the HW structure
66  *
67  *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
68  *  extended control register.
69  **/
70 void
igc_reload_nvm_generic(struct igc_hw * hw)71 igc_reload_nvm_generic(struct igc_hw *hw)
72 {
73 	uint32_t ctrl_ext;
74 
75 	DEBUGFUNC("igc_reload_nvm_generic");
76 
77 	DELAY(10);
78 	ctrl_ext = IGC_READ_REG(hw, IGC_CTRL_EXT);
79 	ctrl_ext |= IGC_CTRL_EXT_EE_RST;
80 	IGC_WRITE_REG(hw, IGC_CTRL_EXT, ctrl_ext);
81 	IGC_WRITE_FLUSH(hw);
82 }
83 
84 /**
85  *  igc_null_write_nvm - No-op function, return 0
86  *  @hw: pointer to the HW structure
87  *  @a: dummy variable
88  *  @b: dummy variable
89  *  @c: dummy variable
90  **/
91 int
igc_null_write_nvm(struct igc_hw IGC_UNUSEDARG * hw,uint16_t IGC_UNUSEDARG a,uint16_t IGC_UNUSEDARG b,uint16_t IGC_UNUSEDARG * c)92 igc_null_write_nvm(struct igc_hw IGC_UNUSEDARG *hw, uint16_t IGC_UNUSEDARG a,
93     uint16_t IGC_UNUSEDARG b, uint16_t IGC_UNUSEDARG *c)
94 {
95 	DEBUGFUNC("igc_null_write_nvm");
96 	return IGC_SUCCESS;
97 }
98 
99 /**
100  *  igc_poll_eerd_eewr_done - Poll for EEPROM read/write completion
101  *  @hw: pointer to the HW structure
102  *  @ee_reg: EEPROM flag for polling
103  *
104  *  Polls the EEPROM status bit for either read or write completion based
105  *  upon the value of 'ee_reg'.
106  **/
107 int
igc_poll_eerd_eewr_done(struct igc_hw * hw,int ee_reg)108 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
109 {
110 	uint32_t attempts = 100000;
111 	uint32_t i, reg = 0;
112 
113 	DEBUGFUNC("igc_poll_eerd_eewr_done");
114 
115 	for (i = 0; i < attempts; i++) {
116 		if (ee_reg == IGC_NVM_POLL_READ)
117 			reg = IGC_READ_REG(hw, IGC_EERD);
118 		else
119 			reg = IGC_READ_REG(hw, IGC_EEWR);
120 
121 		if (reg & IGC_NVM_RW_REG_DONE)
122 			return IGC_SUCCESS;
123 
124 		DELAY(5);
125 	}
126 
127 	return -IGC_ERR_NVM;
128 }
129 
130 /**
131  *  igc_read_nvm_eerd - Reads EEPROM using EERD register
132  *  @hw: pointer to the HW structure
133  *  @offset: offset of word in the EEPROM to read
134  *  @words: number of words to read
135  *  @data: word read from the EEPROM
136  *
137  *  Reads a 16 bit word from the EEPROM using the EERD register.
138  **/
139 int
igc_read_nvm_eerd(struct igc_hw * hw,uint16_t offset,uint16_t words,uint16_t * data)140 igc_read_nvm_eerd(struct igc_hw *hw, uint16_t offset, uint16_t words,
141     uint16_t *data)
142 {
143 	struct igc_nvm_info *nvm = &hw->nvm;
144 	uint32_t i, eerd = 0;
145 	int ret_val = IGC_SUCCESS;
146 
147 	DEBUGFUNC("igc_read_nvm_eerd");
148 
149 	/* A check for invalid values:  offset too large, too many words,
150 	 * too many words for the offset, and not enough words.
151 	 */
152 	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
153 	    (words == 0)) {
154 		DEBUGOUT("nvm parameter(s) out of bounds\n");
155 		return -IGC_ERR_NVM;
156 	}
157 
158 	for (i = 0; i < words; i++) {
159 		eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
160 		    IGC_NVM_RW_REG_START;
161 
162 		IGC_WRITE_REG(hw, IGC_EERD, eerd);
163 		ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
164 		if (ret_val)
165 			break;
166 
167 		data[i] = (IGC_READ_REG(hw, IGC_EERD) >> IGC_NVM_RW_REG_DATA);
168 	}
169 
170 	if (ret_val)
171 		DEBUGOUT1("NVM read error: %d\n", ret_val);
172 
173 	return ret_val;
174 }
175 
176 /**
177  *  igc_read_mac_addr_generic - Read device MAC address
178  *  @hw: pointer to the HW structure
179  *
180  *  Reads the device MAC address from the EEPROM and stores the value.
181  *  Since devices with two ports use the same EEPROM, we increment the
182  *  last bit in the MAC address for the second port.
183  **/
184 int
igc_read_mac_addr_generic(struct igc_hw * hw)185 igc_read_mac_addr_generic(struct igc_hw *hw)
186 {
187 	uint32_t rar_high, rar_low;
188 	uint16_t i;
189 
190 	rar_high = IGC_READ_REG(hw, IGC_RAH(0));
191 	rar_low = IGC_READ_REG(hw, IGC_RAL(0));
192 
193 	for (i = 0; i < IGC_RAL_MAC_ADDR_LEN; i++)
194 		hw->mac.perm_addr[i] = (uint8_t)(rar_low >> (i * 8));
195 
196 	for (i = 0; i < IGC_RAH_MAC_ADDR_LEN; i++)
197 		hw->mac.perm_addr[i+4] = (uint8_t)(rar_high >> (i * 8));
198 
199 	for (i = 0; i < ETHER_ADDR_LEN; i++)
200 		hw->mac.addr[i] = hw->mac.perm_addr[i];
201 
202 	return IGC_SUCCESS;
203 }
204 
205 /**
206  *  igc_validate_nvm_checksum_generic - Validate EEPROM checksum
207  *  @hw: pointer to the HW structure
208  *
209  *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
210  *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
211  **/
212 int
igc_validate_nvm_checksum_generic(struct igc_hw * hw)213 igc_validate_nvm_checksum_generic(struct igc_hw *hw)
214 {
215 	uint16_t checksum = 0;
216 	uint16_t i, nvm_data;
217 	int ret_val;
218 
219 	DEBUGFUNC("igc_validate_nvm_checksum_generic");
220 
221 	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
222 		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
223 		if (ret_val) {
224 			DEBUGOUT("NVM Read Error\n");
225 			return ret_val;
226 		}
227 		checksum += nvm_data;
228 	}
229 
230 	if (checksum != (uint16_t) NVM_SUM) {
231 		DEBUGOUT("NVM Checksum Invalid\n");
232 		return -IGC_ERR_NVM;
233 	}
234 
235 	return IGC_SUCCESS;
236 }
237