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