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