xref: /netbsd-src/sys/dev/pci/igc/igc_api.c (revision fb38d839b48b9b6204dbbee1672454d6e719ba01)
1*fb38d839Srin /*	$NetBSD: igc_api.c,v 1.2 2023/10/04 07:35:27 rin Exp $	*/
2d0d8f2a5Srin /*	$OpenBSD: igc_api.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_api.c,v 1.2 2023/10/04 07:35:27 rin Exp $");
11*fb38d839Srin 
12*fb38d839Srin #include <dev/pci/igc/igc_api.h>
13*fb38d839Srin #include <dev/pci/igc/igc_hw.h>
14d0d8f2a5Srin 
15d0d8f2a5Srin /**
16d0d8f2a5Srin  *  igc_init_mac_params - Initialize MAC function pointers
17d0d8f2a5Srin  *  @hw: pointer to the HW structure
18d0d8f2a5Srin  *
19d0d8f2a5Srin  *  This function initializes the function pointers for the MAC
20d0d8f2a5Srin  *  set of functions.  Called by drivers or by igc_setup_init_funcs.
21d0d8f2a5Srin  **/
22d0d8f2a5Srin int
igc_init_mac_params(struct igc_hw * hw)23d0d8f2a5Srin igc_init_mac_params(struct igc_hw *hw)
24d0d8f2a5Srin {
25d0d8f2a5Srin 	int ret_val = IGC_SUCCESS;
26d0d8f2a5Srin 
27d0d8f2a5Srin 	if (hw->mac.ops.init_params) {
28d0d8f2a5Srin 		ret_val = hw->mac.ops.init_params(hw);
29d0d8f2a5Srin 		if (ret_val) {
30d0d8f2a5Srin 			DEBUGOUT("MAC Initialization Error\n");
31d0d8f2a5Srin 			goto out;
32d0d8f2a5Srin 		}
33d0d8f2a5Srin 	} else {
34d0d8f2a5Srin 		DEBUGOUT("mac.init_mac_params was NULL\n");
35d0d8f2a5Srin 		ret_val = -IGC_ERR_CONFIG;
36d0d8f2a5Srin 	}
37d0d8f2a5Srin out:
38d0d8f2a5Srin 	return ret_val;
39d0d8f2a5Srin }
40d0d8f2a5Srin 
41d0d8f2a5Srin /**
42d0d8f2a5Srin  *  igc_init_nvm_params - Initialize NVM function pointers
43d0d8f2a5Srin  *  @hw: pointer to the HW structure
44d0d8f2a5Srin  *
45d0d8f2a5Srin  *  This function initializes the function pointers for the NVM
46d0d8f2a5Srin  *  set of functions.  Called by drivers or by igc_setup_init_funcs.
47d0d8f2a5Srin  **/
48d0d8f2a5Srin int
igc_init_nvm_params(struct igc_hw * hw)49d0d8f2a5Srin igc_init_nvm_params(struct igc_hw *hw)
50d0d8f2a5Srin {
51d0d8f2a5Srin 	int ret_val = IGC_SUCCESS;
52d0d8f2a5Srin 
53d0d8f2a5Srin 	if (hw->nvm.ops.init_params) {
54d0d8f2a5Srin 		ret_val = hw->nvm.ops.init_params(hw);
55d0d8f2a5Srin 		if (ret_val) {
56d0d8f2a5Srin 			DEBUGOUT("NVM Initialization Error\n");
57d0d8f2a5Srin 			goto out;
58d0d8f2a5Srin 		}
59d0d8f2a5Srin 	} else {
60d0d8f2a5Srin 		DEBUGOUT("nvm.init_nvm_params was NULL\n");
61d0d8f2a5Srin 		ret_val = -IGC_ERR_CONFIG;
62d0d8f2a5Srin 	}
63d0d8f2a5Srin out:
64d0d8f2a5Srin 	return ret_val;
65d0d8f2a5Srin }
66d0d8f2a5Srin 
67d0d8f2a5Srin /**
68d0d8f2a5Srin  *  igc_init_phy_params - Initialize PHY function pointers
69d0d8f2a5Srin  *  @hw: pointer to the HW structure
70d0d8f2a5Srin  *
71d0d8f2a5Srin  *  This function initializes the function pointers for the PHY
72d0d8f2a5Srin  *  set of functions.  Called by drivers or by igc_setup_init_funcs.
73d0d8f2a5Srin  **/
74d0d8f2a5Srin int
igc_init_phy_params(struct igc_hw * hw)75d0d8f2a5Srin igc_init_phy_params(struct igc_hw *hw)
76d0d8f2a5Srin {
77d0d8f2a5Srin 	int ret_val = IGC_SUCCESS;
78d0d8f2a5Srin 
79d0d8f2a5Srin 	if (hw->phy.ops.init_params) {
80d0d8f2a5Srin 		ret_val = hw->phy.ops.init_params(hw);
81d0d8f2a5Srin 		if (ret_val) {
82d0d8f2a5Srin 			DEBUGOUT("PHY Initialization Error\n");
83d0d8f2a5Srin 			goto out;
84d0d8f2a5Srin 		}
85d0d8f2a5Srin 	} else {
86d0d8f2a5Srin 		DEBUGOUT("phy.init_phy_params was NULL\n");
87d0d8f2a5Srin 		ret_val =  -IGC_ERR_CONFIG;
88d0d8f2a5Srin 	}
89d0d8f2a5Srin out:
90d0d8f2a5Srin 	return ret_val;
91d0d8f2a5Srin }
92d0d8f2a5Srin 
93d0d8f2a5Srin /**
94d0d8f2a5Srin  *  igc_set_mac_type - Sets MAC type
95d0d8f2a5Srin  *  @hw: pointer to the HW structure
96d0d8f2a5Srin  *
97d0d8f2a5Srin  *  This function sets the mac type of the adapter based on the
98d0d8f2a5Srin  *  device ID stored in the hw structure.
99d0d8f2a5Srin  *  MUST BE FIRST FUNCTION CALLED (explicitly or through
100d0d8f2a5Srin  *  igc_setup_init_funcs()).
101d0d8f2a5Srin  **/
102d0d8f2a5Srin int
igc_set_mac_type(struct igc_hw * hw)103d0d8f2a5Srin igc_set_mac_type(struct igc_hw *hw)
104d0d8f2a5Srin {
105d0d8f2a5Srin 	struct igc_mac_info *mac = &hw->mac;
106d0d8f2a5Srin 	int ret_val = IGC_SUCCESS;
107d0d8f2a5Srin 
108d0d8f2a5Srin 	DEBUGFUNC("igc_set_mac_type");
109d0d8f2a5Srin 
110d0d8f2a5Srin 	switch (hw->device_id) {
111d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I220_V:
112d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I221_V:
113d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I225_BLANK_NVM:
114d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I225_I:
115d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I225_IT:
116d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I225_K:
117d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I225_K2:
118d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I225_LM:
119d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I225_LMVP:
120d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I225_V:
121d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I226_BLANK_NVM:
122d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I226_IT:
123d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I226_LM:
124*fb38d839Srin 	case PCI_PRODUCT_INTEL_I226_LMVP:
125d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I226_K:
126d0d8f2a5Srin 	case PCI_PRODUCT_INTEL_I226_V:
127d0d8f2a5Srin 		mac->type = igc_i225;
128d0d8f2a5Srin 		break;
129d0d8f2a5Srin 	default:
130d0d8f2a5Srin 		/* Should never have loaded on this device */
131d0d8f2a5Srin 		ret_val = -IGC_ERR_MAC_INIT;
132d0d8f2a5Srin 		break;
133d0d8f2a5Srin 	}
134d0d8f2a5Srin 
135d0d8f2a5Srin 	return ret_val;
136d0d8f2a5Srin }
137d0d8f2a5Srin 
138d0d8f2a5Srin /**
139d0d8f2a5Srin  *  igc_setup_init_funcs - Initializes function pointers
140d0d8f2a5Srin  *  @hw: pointer to the HW structure
141d0d8f2a5Srin  *  @init_device: true will initialize the rest of the function pointers
142d0d8f2a5Srin  *		  getting the device ready for use.  FALSE will only set
143d0d8f2a5Srin  *		  MAC type and the function pointers for the other init
144d0d8f2a5Srin  *		  functions.  Passing FALSE will not generate any hardware
145d0d8f2a5Srin  *		  reads or writes.
146d0d8f2a5Srin  *
147d0d8f2a5Srin  *  This function must be called by a driver in order to use the rest
148d0d8f2a5Srin  *  of the 'shared' code files. Called by drivers only.
149d0d8f2a5Srin  **/
150d0d8f2a5Srin int
igc_setup_init_funcs(struct igc_hw * hw,bool init_device)151d0d8f2a5Srin igc_setup_init_funcs(struct igc_hw *hw, bool init_device)
152d0d8f2a5Srin {
153d0d8f2a5Srin 	int ret_val;
154d0d8f2a5Srin 
155d0d8f2a5Srin 	/* Can't do much good without knowing the MAC type. */
156d0d8f2a5Srin 	ret_val = igc_set_mac_type(hw);
157d0d8f2a5Srin 	if (ret_val) {
158d0d8f2a5Srin 		DEBUGOUT("ERROR: MAC type could not be set properly.\n");
159d0d8f2a5Srin 		goto out;
160d0d8f2a5Srin 	}
161d0d8f2a5Srin 
162d0d8f2a5Srin 	if (!hw->hw_addr) {
163d0d8f2a5Srin 		DEBUGOUT("ERROR: Registers not mapped\n");
164d0d8f2a5Srin 		ret_val = -IGC_ERR_CONFIG;
165d0d8f2a5Srin 		goto out;
166d0d8f2a5Srin 	}
167d0d8f2a5Srin 
168d0d8f2a5Srin 	/*
169d0d8f2a5Srin 	 * Init function pointers to generic implementations. We do this first
170d0d8f2a5Srin 	 * allowing a driver module to override it afterward.
171d0d8f2a5Srin 	 */
172d0d8f2a5Srin 	igc_init_mac_ops_generic(hw);
173d0d8f2a5Srin 	igc_init_phy_ops_generic(hw);
174d0d8f2a5Srin 	igc_init_nvm_ops_generic(hw);
175d0d8f2a5Srin 
176d0d8f2a5Srin 	/*
177d0d8f2a5Srin 	 * Set up the init function pointers. These are functions within the
178d0d8f2a5Srin 	 * adapter family file that sets up function pointers for the rest of
179d0d8f2a5Srin 	 * the functions in that family.
180d0d8f2a5Srin 	 */
181d0d8f2a5Srin 	switch (hw->mac.type) {
182d0d8f2a5Srin 	case igc_i225:
183d0d8f2a5Srin 		igc_init_function_pointers_i225(hw);
184d0d8f2a5Srin 		break;
185d0d8f2a5Srin 	default:
186d0d8f2a5Srin 		DEBUGOUT("Hardware not supported\n");
187d0d8f2a5Srin 		ret_val = -IGC_ERR_CONFIG;
188d0d8f2a5Srin 		break;
189d0d8f2a5Srin 	}
190d0d8f2a5Srin 
191d0d8f2a5Srin 	/*
192d0d8f2a5Srin 	 * Initialize the rest of the function pointers. These require some
193d0d8f2a5Srin 	 * register reads/writes in some cases.
194d0d8f2a5Srin 	 */
195d0d8f2a5Srin 	if (!(ret_val) && init_device) {
196d0d8f2a5Srin 		ret_val = igc_init_mac_params(hw);
197d0d8f2a5Srin 		if (ret_val)
198d0d8f2a5Srin 			goto out;
199d0d8f2a5Srin 
200d0d8f2a5Srin 		ret_val = igc_init_nvm_params(hw);
201d0d8f2a5Srin 		if (ret_val)
202d0d8f2a5Srin 			goto out;
203d0d8f2a5Srin 
204d0d8f2a5Srin 		ret_val = igc_init_phy_params(hw);
205d0d8f2a5Srin 		if (ret_val)
206d0d8f2a5Srin 			goto out;
207d0d8f2a5Srin 	}
208d0d8f2a5Srin out:
209d0d8f2a5Srin 	return ret_val;
210d0d8f2a5Srin }
211d0d8f2a5Srin 
212d0d8f2a5Srin /**
213d0d8f2a5Srin  *  igc_update_mc_addr_list - Update Multicast addresses
214d0d8f2a5Srin  *  @hw: pointer to the HW structure
215d0d8f2a5Srin  *  @mc_addr_list: array of multicast addresses to program
216d0d8f2a5Srin  *  @mc_addr_count: number of multicast addresses to program
217d0d8f2a5Srin  *
218d0d8f2a5Srin  *  Updates the Multicast Table Array.
219d0d8f2a5Srin  *  The caller must have a packed mc_addr_list of multicast addresses.
220d0d8f2a5Srin  **/
221d0d8f2a5Srin void
igc_update_mc_addr_list(struct igc_hw * hw,uint8_t * mc_addr_list,uint32_t mc_addr_count)222d0d8f2a5Srin igc_update_mc_addr_list(struct igc_hw *hw, uint8_t *mc_addr_list,
223d0d8f2a5Srin     uint32_t mc_addr_count)
224d0d8f2a5Srin {
225d0d8f2a5Srin 	if (hw->mac.ops.update_mc_addr_list)
226d0d8f2a5Srin 		hw->mac.ops.update_mc_addr_list(hw, mc_addr_list,
227d0d8f2a5Srin 		    mc_addr_count);
228d0d8f2a5Srin }
229d0d8f2a5Srin 
230d0d8f2a5Srin /**
231d0d8f2a5Srin  *  igc_check_for_link - Check/Store link connection
232d0d8f2a5Srin  *  @hw: pointer to the HW structure
233d0d8f2a5Srin  *
234d0d8f2a5Srin  *  This checks the link condition of the adapter and stores the
235d0d8f2a5Srin  *  results in the hw->mac structure. This is a function pointer entry
236d0d8f2a5Srin  *  point called by drivers.
237d0d8f2a5Srin  **/
238d0d8f2a5Srin int
igc_check_for_link(struct igc_hw * hw)239d0d8f2a5Srin igc_check_for_link(struct igc_hw *hw)
240d0d8f2a5Srin {
241d0d8f2a5Srin 	if (hw->mac.ops.check_for_link)
242d0d8f2a5Srin 		return hw->mac.ops.check_for_link(hw);
243d0d8f2a5Srin 
244d0d8f2a5Srin 	return -IGC_ERR_CONFIG;
245d0d8f2a5Srin }
246d0d8f2a5Srin 
247d0d8f2a5Srin /**
248d0d8f2a5Srin  *  igc_reset_hw - Reset hardware
249d0d8f2a5Srin  *  @hw: pointer to the HW structure
250d0d8f2a5Srin  *
251d0d8f2a5Srin  *  This resets the hardware into a known state. This is a function pointer
252d0d8f2a5Srin  *  entry point called by drivers.
253d0d8f2a5Srin  **/
254d0d8f2a5Srin int
igc_reset_hw(struct igc_hw * hw)255d0d8f2a5Srin igc_reset_hw(struct igc_hw *hw)
256d0d8f2a5Srin {
257d0d8f2a5Srin 	if (hw->mac.ops.reset_hw)
258d0d8f2a5Srin 		return hw->mac.ops.reset_hw(hw);
259d0d8f2a5Srin 
260d0d8f2a5Srin 	return -IGC_ERR_CONFIG;
261d0d8f2a5Srin }
262d0d8f2a5Srin 
263d0d8f2a5Srin /**
264d0d8f2a5Srin  *  igc_init_hw - Initialize hardware
265d0d8f2a5Srin  *  @hw: pointer to the HW structure
266d0d8f2a5Srin  *
267d0d8f2a5Srin  *  This inits the hardware readying it for operation. This is a function
268d0d8f2a5Srin  *  pointer entry point called by drivers.
269d0d8f2a5Srin  **/
270d0d8f2a5Srin int
igc_init_hw(struct igc_hw * hw)271d0d8f2a5Srin igc_init_hw(struct igc_hw *hw)
272d0d8f2a5Srin {
273d0d8f2a5Srin 	if (hw->mac.ops.init_hw)
274d0d8f2a5Srin 		return hw->mac.ops.init_hw(hw);
275d0d8f2a5Srin 
276d0d8f2a5Srin 	return -IGC_ERR_CONFIG;
277d0d8f2a5Srin }
278d0d8f2a5Srin 
279d0d8f2a5Srin /**
280d0d8f2a5Srin  *  igc_get_speed_and_duplex - Returns current speed and duplex
281d0d8f2a5Srin  *  @hw: pointer to the HW structure
282d0d8f2a5Srin  *  @speed: pointer to a 16-bit value to store the speed
283d0d8f2a5Srin  *  @duplex: pointer to a 16-bit value to store the duplex.
284d0d8f2a5Srin  *
285d0d8f2a5Srin  *  This returns the speed and duplex of the adapter in the two 'out'
286d0d8f2a5Srin  *  variables passed in. This is a function pointer entry point called
287d0d8f2a5Srin  *  by drivers.
288d0d8f2a5Srin  **/
289d0d8f2a5Srin int
igc_get_speed_and_duplex(struct igc_hw * hw,uint16_t * speed,uint16_t * duplex)290d0d8f2a5Srin igc_get_speed_and_duplex(struct igc_hw *hw, uint16_t *speed, uint16_t *duplex)
291d0d8f2a5Srin {
292d0d8f2a5Srin 	if (hw->mac.ops.get_link_up_info)
293d0d8f2a5Srin 		return hw->mac.ops.get_link_up_info(hw, speed, duplex);
294d0d8f2a5Srin 
295d0d8f2a5Srin 	return -IGC_ERR_CONFIG;
296d0d8f2a5Srin }
297d0d8f2a5Srin 
298d0d8f2a5Srin /**
299d0d8f2a5Srin  *  igc_rar_set - Sets a receive address register
300d0d8f2a5Srin  *  @hw: pointer to the HW structure
301d0d8f2a5Srin  *  @addr: address to set the RAR to
302d0d8f2a5Srin  *  @index: the RAR to set
303d0d8f2a5Srin  *
304d0d8f2a5Srin  *  Sets a Receive Address Register (RAR) to the specified address.
305d0d8f2a5Srin  **/
306d0d8f2a5Srin int
igc_rar_set(struct igc_hw * hw,uint8_t * addr,uint32_t index)307d0d8f2a5Srin igc_rar_set(struct igc_hw *hw, uint8_t *addr, uint32_t index)
308d0d8f2a5Srin {
309d0d8f2a5Srin 	if (hw->mac.ops.rar_set)
310d0d8f2a5Srin 		return hw->mac.ops.rar_set(hw, addr, index);
311d0d8f2a5Srin 
312d0d8f2a5Srin 	return IGC_SUCCESS;
313d0d8f2a5Srin }
314d0d8f2a5Srin 
315d0d8f2a5Srin /**
316d0d8f2a5Srin  *  igc_check_reset_block - Verifies PHY can be reset
317d0d8f2a5Srin  *  @hw: pointer to the HW structure
318d0d8f2a5Srin  *
319d0d8f2a5Srin  *  Checks if the PHY is in a state that can be reset or if manageability
320d0d8f2a5Srin  *  has it tied up. This is a function pointer entry point called by drivers.
321d0d8f2a5Srin  **/
322d0d8f2a5Srin int
igc_check_reset_block(struct igc_hw * hw)323d0d8f2a5Srin igc_check_reset_block(struct igc_hw *hw)
324d0d8f2a5Srin {
325d0d8f2a5Srin 	if (hw->phy.ops.check_reset_block)
326d0d8f2a5Srin 		return hw->phy.ops.check_reset_block(hw);
327d0d8f2a5Srin 
328d0d8f2a5Srin 	return IGC_SUCCESS;
329d0d8f2a5Srin }
330d0d8f2a5Srin 
331d0d8f2a5Srin /**
332d0d8f2a5Srin  *  igc_get_phy_info - Retrieves PHY information from registers
333d0d8f2a5Srin  *  @hw: pointer to the HW structure
334d0d8f2a5Srin  *
335d0d8f2a5Srin  *  This function gets some information from various PHY registers and
336d0d8f2a5Srin  *  populates hw->phy values with it. This is a function pointer entry
337d0d8f2a5Srin  *  point called by drivers.
338d0d8f2a5Srin  **/
339d0d8f2a5Srin int
igc_get_phy_info(struct igc_hw * hw)340d0d8f2a5Srin igc_get_phy_info(struct igc_hw *hw)
341d0d8f2a5Srin {
342d0d8f2a5Srin 	if (hw->phy.ops.get_info)
343d0d8f2a5Srin 		return hw->phy.ops.get_info(hw);
344d0d8f2a5Srin 
345d0d8f2a5Srin 	return IGC_SUCCESS;
346d0d8f2a5Srin }
347d0d8f2a5Srin 
348d0d8f2a5Srin /**
349d0d8f2a5Srin  *  igc_phy_hw_reset - Hard PHY reset
350d0d8f2a5Srin  *  @hw: pointer to the HW structure
351d0d8f2a5Srin  *
352d0d8f2a5Srin  *  Performs a hard PHY reset. This is a function pointer entry point called
353d0d8f2a5Srin  *  by drivers.
354d0d8f2a5Srin  **/
355d0d8f2a5Srin int
igc_phy_hw_reset(struct igc_hw * hw)356d0d8f2a5Srin igc_phy_hw_reset(struct igc_hw *hw)
357d0d8f2a5Srin {
358d0d8f2a5Srin 	if (hw->phy.ops.reset)
359d0d8f2a5Srin 		return hw->phy.ops.reset(hw);
360d0d8f2a5Srin 
361d0d8f2a5Srin 	return IGC_SUCCESS;
362d0d8f2a5Srin }
363d0d8f2a5Srin 
364d0d8f2a5Srin /**
365d0d8f2a5Srin  *  igc_read_mac_addr - Reads MAC address
366d0d8f2a5Srin  *  @hw: pointer to the HW structure
367d0d8f2a5Srin  *
368d0d8f2a5Srin  *  Reads the MAC address out of the adapter and stores it in the HW structure.
369d0d8f2a5Srin  *  Currently no func pointer exists and all implementations are handled in the
370d0d8f2a5Srin  *  generic version of this function.
371d0d8f2a5Srin  **/
372d0d8f2a5Srin int
igc_read_mac_addr(struct igc_hw * hw)373d0d8f2a5Srin igc_read_mac_addr(struct igc_hw *hw)
374d0d8f2a5Srin {
375d0d8f2a5Srin 	if (hw->mac.ops.read_mac_addr)
376d0d8f2a5Srin 		return hw->mac.ops.read_mac_addr(hw);
377d0d8f2a5Srin 
378d0d8f2a5Srin 	return igc_read_mac_addr_generic(hw);
379d0d8f2a5Srin }
380d0d8f2a5Srin 
381d0d8f2a5Srin /**
382d0d8f2a5Srin  *  igc_validate_nvm_checksum - Verifies NVM (EEPROM) checksum
383d0d8f2a5Srin  *  @hw: pointer to the HW structure
384d0d8f2a5Srin  *
385d0d8f2a5Srin  *  Validates the NVM checksum is correct. This is a function pointer entry
386d0d8f2a5Srin  *  point called by drivers.
387d0d8f2a5Srin  **/
388d0d8f2a5Srin int
igc_validate_nvm_checksum(struct igc_hw * hw)389d0d8f2a5Srin igc_validate_nvm_checksum(struct igc_hw *hw)
390d0d8f2a5Srin {
391d0d8f2a5Srin 	if (hw->nvm.ops.validate)
392d0d8f2a5Srin 		return hw->nvm.ops.validate(hw);
393d0d8f2a5Srin 
394d0d8f2a5Srin 	return -IGC_ERR_CONFIG;
395d0d8f2a5Srin }
396