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