xref: /onnv-gate/usr/src/uts/common/io/igb/igb_nvm.c (revision 10319:0355b7a83c0d)
15779Sxy150489 /*
25779Sxy150489  * CDDL HEADER START
35779Sxy150489  *
48571SChenlu.Chen@Sun.COM  * Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
55779Sxy150489  * The contents of this file are subject to the terms of the
65779Sxy150489  * Common Development and Distribution License (the "License").
75779Sxy150489  * You may not use this file except in compliance with the License.
85779Sxy150489  *
95779Sxy150489  * You can obtain a copy of the license at:
105779Sxy150489  *	http://www.opensolaris.org/os/licensing.
115779Sxy150489  * See the License for the specific language governing permissions
125779Sxy150489  * and limitations under the License.
135779Sxy150489  *
145779Sxy150489  * When using or redistributing this file, you may do so under the
155779Sxy150489  * License only. No other modification of this header is permitted.
165779Sxy150489  *
175779Sxy150489  * If applicable, add the following below this CDDL HEADER, with the
185779Sxy150489  * fields enclosed by brackets "[]" replaced with your own identifying
195779Sxy150489  * information: Portions Copyright [yyyy] [name of copyright owner]
205779Sxy150489  *
215779Sxy150489  * CDDL HEADER END
225779Sxy150489  */
235779Sxy150489 
245779Sxy150489 /*
258571SChenlu.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
265779Sxy150489  * Use is subject to license terms of the CDDL.
275779Sxy150489  */
285779Sxy150489 
29*10319SJason.Xu@Sun.COM /* IntelVersion: 1.49 v2-9-8_2009-6-12 */
305779Sxy150489 
315779Sxy150489 #include "igb_api.h"
328571SChenlu.Chen@Sun.COM 
338571SChenlu.Chen@Sun.COM static void e1000_stop_nvm(struct e1000_hw *hw);
348571SChenlu.Chen@Sun.COM static void e1000_reload_nvm_generic(struct e1000_hw *hw);
358571SChenlu.Chen@Sun.COM 
368571SChenlu.Chen@Sun.COM /*
378571SChenlu.Chen@Sun.COM  * e1000_init_nvm_ops_generic - Initialize NVM function pointers
388571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
398571SChenlu.Chen@Sun.COM  *
408571SChenlu.Chen@Sun.COM  * Setups up the function pointers to no-op functions
418571SChenlu.Chen@Sun.COM  */
428571SChenlu.Chen@Sun.COM void
438571SChenlu.Chen@Sun.COM e1000_init_nvm_ops_generic(struct e1000_hw *hw)
448571SChenlu.Chen@Sun.COM {
458571SChenlu.Chen@Sun.COM 	struct e1000_nvm_info *nvm = &hw->nvm;
468571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_init_nvm_ops_generic");
478571SChenlu.Chen@Sun.COM 
488571SChenlu.Chen@Sun.COM 	/* Initialize function pointers */
498571SChenlu.Chen@Sun.COM 	nvm->ops.init_params = e1000_null_ops_generic;
508571SChenlu.Chen@Sun.COM 	nvm->ops.acquire = e1000_null_ops_generic;
518571SChenlu.Chen@Sun.COM 	nvm->ops.read = e1000_null_read_nvm;
528571SChenlu.Chen@Sun.COM 	nvm->ops.release = e1000_null_nvm_generic;
538571SChenlu.Chen@Sun.COM 	nvm->ops.reload = e1000_reload_nvm_generic;
548571SChenlu.Chen@Sun.COM 	nvm->ops.update = e1000_null_ops_generic;
558571SChenlu.Chen@Sun.COM 	nvm->ops.valid_led_default = e1000_null_led_default;
568571SChenlu.Chen@Sun.COM 	nvm->ops.validate = e1000_null_ops_generic;
578571SChenlu.Chen@Sun.COM 	nvm->ops.write = e1000_null_write_nvm;
588571SChenlu.Chen@Sun.COM }
598571SChenlu.Chen@Sun.COM 
608571SChenlu.Chen@Sun.COM /*
618571SChenlu.Chen@Sun.COM  * e1000_null_nvm_read - No-op function, return 0
628571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
638571SChenlu.Chen@Sun.COM  */
648571SChenlu.Chen@Sun.COM s32
658571SChenlu.Chen@Sun.COM e1000_null_read_nvm(struct e1000_hw *hw, u16 a, u16 b, u16 *c)
668571SChenlu.Chen@Sun.COM {
678571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_read_nvm");
688571SChenlu.Chen@Sun.COM 	UNREFERENCED_4PARAMETER(hw, a, b, c);
698571SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
708571SChenlu.Chen@Sun.COM }
718571SChenlu.Chen@Sun.COM 
728571SChenlu.Chen@Sun.COM /*
738571SChenlu.Chen@Sun.COM  * e1000_null_nvm_generic - No-op function, return void
748571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
758571SChenlu.Chen@Sun.COM  */
768571SChenlu.Chen@Sun.COM void
778571SChenlu.Chen@Sun.COM e1000_null_nvm_generic(struct e1000_hw *hw)
788571SChenlu.Chen@Sun.COM {
798571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_nvm_generic");
808571SChenlu.Chen@Sun.COM 	UNREFERENCED_1PARAMETER(hw);
818571SChenlu.Chen@Sun.COM }
828571SChenlu.Chen@Sun.COM 
838571SChenlu.Chen@Sun.COM /*
848571SChenlu.Chen@Sun.COM  * e1000_null_led_default - No-op function, return 0
858571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
868571SChenlu.Chen@Sun.COM  */
878571SChenlu.Chen@Sun.COM s32
888571SChenlu.Chen@Sun.COM e1000_null_led_default(struct e1000_hw *hw, u16 *data)
898571SChenlu.Chen@Sun.COM {
908571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_led_default");
918571SChenlu.Chen@Sun.COM 	UNREFERENCED_2PARAMETER(hw, data);
928571SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
938571SChenlu.Chen@Sun.COM }
948571SChenlu.Chen@Sun.COM 
958571SChenlu.Chen@Sun.COM /*
968571SChenlu.Chen@Sun.COM  * e1000_null_write_nvm - No-op function, return 0
978571SChenlu.Chen@Sun.COM  * @hw: pointer to the HW structure
988571SChenlu.Chen@Sun.COM  */
998571SChenlu.Chen@Sun.COM s32
1008571SChenlu.Chen@Sun.COM e1000_null_write_nvm(struct e1000_hw *hw, u16 a, u16 b, u16 *c)
1018571SChenlu.Chen@Sun.COM {
1028571SChenlu.Chen@Sun.COM 	DEBUGFUNC("e1000_null_write_nvm");
1038571SChenlu.Chen@Sun.COM 	UNREFERENCED_4PARAMETER(hw, a, b, c);
1048571SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
1058571SChenlu.Chen@Sun.COM }
1065779Sxy150489 
1075779Sxy150489 /*
1085779Sxy150489  * e1000_raise_eec_clk - Raise EEPROM clock
1095779Sxy150489  * @hw: pointer to the HW structure
1105779Sxy150489  * @eecd: pointer to the EEPROM
1115779Sxy150489  *
1125779Sxy150489  * Enable/Raise the EEPROM clock bit.
1135779Sxy150489  */
1145779Sxy150489 static void
1155779Sxy150489 e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
1165779Sxy150489 {
1175779Sxy150489 	*eecd = *eecd | E1000_EECD_SK;
1185779Sxy150489 	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
1195779Sxy150489 	E1000_WRITE_FLUSH(hw);
1205779Sxy150489 	usec_delay(hw->nvm.delay_usec);
1215779Sxy150489 }
1225779Sxy150489 
1235779Sxy150489 /*
1245779Sxy150489  * e1000_lower_eec_clk - Lower EEPROM clock
1255779Sxy150489  * @hw: pointer to the HW structure
1265779Sxy150489  * @eecd: pointer to the EEPROM
1275779Sxy150489  *
1285779Sxy150489  * Clear/Lower the EEPROM clock bit.
1295779Sxy150489  */
1305779Sxy150489 static void
1315779Sxy150489 e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
1325779Sxy150489 {
1335779Sxy150489 	*eecd = *eecd & ~E1000_EECD_SK;
1345779Sxy150489 	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
1355779Sxy150489 	E1000_WRITE_FLUSH(hw);
1365779Sxy150489 	usec_delay(hw->nvm.delay_usec);
1375779Sxy150489 }
1385779Sxy150489 
1395779Sxy150489 /*
1405779Sxy150489  * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
1415779Sxy150489  * @hw: pointer to the HW structure
1425779Sxy150489  * @data: data to send to the EEPROM
1435779Sxy150489  * @count: number of bits to shift out
1445779Sxy150489  *
1455779Sxy150489  * We need to shift 'count' bits out to the EEPROM.  So, the value in the
1465779Sxy150489  * "data" parameter will be shifted out to the EEPROM one bit at a time.
1475779Sxy150489  * In order to do this, "data" must be broken down into bits.
1485779Sxy150489  */
1495779Sxy150489 static void
1505779Sxy150489 e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
1515779Sxy150489 {
1525779Sxy150489 	struct e1000_nvm_info *nvm = &hw->nvm;
1535779Sxy150489 	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
1545779Sxy150489 	u32 mask;
1555779Sxy150489 
1565779Sxy150489 	DEBUGFUNC("e1000_shift_out_eec_bits");
1575779Sxy150489 
1585779Sxy150489 	mask = 0x01 << (count - 1);
1595779Sxy150489 	if (nvm->type == e1000_nvm_eeprom_microwire)
1605779Sxy150489 		eecd &= ~E1000_EECD_DO;
1615779Sxy150489 	else if (nvm->type == e1000_nvm_eeprom_spi)
1625779Sxy150489 		eecd |= E1000_EECD_DO;
1635779Sxy150489 
1645779Sxy150489 	do {
1655779Sxy150489 		eecd &= ~E1000_EECD_DI;
1665779Sxy150489 
1675779Sxy150489 		if (data & mask)
1685779Sxy150489 			eecd |= E1000_EECD_DI;
1695779Sxy150489 
1705779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
1715779Sxy150489 		E1000_WRITE_FLUSH(hw);
1725779Sxy150489 
1735779Sxy150489 		usec_delay(nvm->delay_usec);
1745779Sxy150489 
1755779Sxy150489 		e1000_raise_eec_clk(hw, &eecd);
1765779Sxy150489 		e1000_lower_eec_clk(hw, &eecd);
1775779Sxy150489 
1785779Sxy150489 		mask >>= 1;
1795779Sxy150489 	} while (mask);
1805779Sxy150489 
1815779Sxy150489 	eecd &= ~E1000_EECD_DI;
1825779Sxy150489 	E1000_WRITE_REG(hw, E1000_EECD, eecd);
1835779Sxy150489 }
1845779Sxy150489 
1855779Sxy150489 /*
1865779Sxy150489  * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
1875779Sxy150489  * @hw: pointer to the HW structure
1885779Sxy150489  * @count: number of bits to shift in
1895779Sxy150489  *
1905779Sxy150489  * In order to read a register from the EEPROM, we need to shift 'count' bits
1915779Sxy150489  * in from the EEPROM.  Bits are "shifted in" by raising the clock input to
1925779Sxy150489  * the EEPROM (setting the SK bit), and then reading the value of the data out
1935779Sxy150489  * "DO" bit.  During this "shifting in" process the data in "DI" bit should
1945779Sxy150489  * always be clear.
1955779Sxy150489  */
1965779Sxy150489 static u16
1975779Sxy150489 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
1985779Sxy150489 {
1995779Sxy150489 	u32 eecd;
2005779Sxy150489 	u32 i;
2015779Sxy150489 	u16 data;
2025779Sxy150489 
2035779Sxy150489 	DEBUGFUNC("e1000_shift_in_eec_bits");
2045779Sxy150489 
2055779Sxy150489 	eecd = E1000_READ_REG(hw, E1000_EECD);
2065779Sxy150489 
2075779Sxy150489 	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
2085779Sxy150489 	data = 0;
2095779Sxy150489 
2105779Sxy150489 	for (i = 0; i < count; i++) {
2115779Sxy150489 		data <<= 1;
2125779Sxy150489 		e1000_raise_eec_clk(hw, &eecd);
2135779Sxy150489 
2145779Sxy150489 		eecd = E1000_READ_REG(hw, E1000_EECD);
2155779Sxy150489 
2165779Sxy150489 		eecd &= ~E1000_EECD_DI;
2175779Sxy150489 		if (eecd & E1000_EECD_DO)
2185779Sxy150489 			data |= 1;
2195779Sxy150489 
2205779Sxy150489 		e1000_lower_eec_clk(hw, &eecd);
2215779Sxy150489 	}
2225779Sxy150489 
2235779Sxy150489 	return (data);
2245779Sxy150489 }
2255779Sxy150489 
2265779Sxy150489 /*
2275779Sxy150489  * e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion
2285779Sxy150489  * @hw: pointer to the HW structure
2295779Sxy150489  * @ee_reg: EEPROM flag for polling
2305779Sxy150489  *
2315779Sxy150489  * Polls the EEPROM status bit for either read or write completion based
2325779Sxy150489  * upon the value of 'ee_reg'.
2335779Sxy150489  */
2345779Sxy150489 s32
2355779Sxy150489 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
2365779Sxy150489 {
2375779Sxy150489 	u32 attempts = 100000;
2385779Sxy150489 	u32 i, reg = 0;
2395779Sxy150489 	s32 ret_val = -E1000_ERR_NVM;
2405779Sxy150489 
2415779Sxy150489 	DEBUGFUNC("e1000_poll_eerd_eewr_done");
2425779Sxy150489 
2435779Sxy150489 	for (i = 0; i < attempts; i++) {
2445779Sxy150489 		if (ee_reg == E1000_NVM_POLL_READ)
2455779Sxy150489 			reg = E1000_READ_REG(hw, E1000_EERD);
2465779Sxy150489 		else
2475779Sxy150489 			reg = E1000_READ_REG(hw, E1000_EEWR);
2485779Sxy150489 
2495779Sxy150489 		if (reg & E1000_NVM_RW_REG_DONE) {
2505779Sxy150489 			ret_val = E1000_SUCCESS;
2515779Sxy150489 			break;
2525779Sxy150489 		}
2535779Sxy150489 
2545779Sxy150489 		usec_delay(5);
2555779Sxy150489 	}
2565779Sxy150489 
2575779Sxy150489 	return (ret_val);
2585779Sxy150489 }
2595779Sxy150489 
2605779Sxy150489 /*
2615779Sxy150489  * e1000_acquire_nvm_generic - Generic request for access to EEPROM
2625779Sxy150489  * @hw: pointer to the HW structure
2635779Sxy150489  *
2645779Sxy150489  * Set the EEPROM access request bit and wait for EEPROM access grant bit.
2655779Sxy150489  * Return successful if access grant bit set, else clear the request for
2665779Sxy150489  * EEPROM access and return -E1000_ERR_NVM (-1).
2675779Sxy150489  */
2685779Sxy150489 s32
2695779Sxy150489 e1000_acquire_nvm_generic(struct e1000_hw *hw)
2705779Sxy150489 {
2715779Sxy150489 	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
2725779Sxy150489 	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
2735779Sxy150489 	s32 ret_val = E1000_SUCCESS;
2745779Sxy150489 
2755779Sxy150489 	DEBUGFUNC("e1000_acquire_nvm_generic");
2765779Sxy150489 
2775779Sxy150489 	E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ);
2785779Sxy150489 	eecd = E1000_READ_REG(hw, E1000_EECD);
2795779Sxy150489 
2805779Sxy150489 	while (timeout) {
2815779Sxy150489 		if (eecd & E1000_EECD_GNT)
2825779Sxy150489 			break;
2835779Sxy150489 		usec_delay(5);
2845779Sxy150489 		eecd = E1000_READ_REG(hw, E1000_EECD);
2855779Sxy150489 		timeout--;
2865779Sxy150489 	}
2875779Sxy150489 
2885779Sxy150489 	if (!timeout) {
2895779Sxy150489 		eecd &= ~E1000_EECD_REQ;
2905779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
2915779Sxy150489 		DEBUGOUT("Could not acquire NVM grant\n");
2925779Sxy150489 		ret_val = -E1000_ERR_NVM;
2935779Sxy150489 	}
2945779Sxy150489 
2955779Sxy150489 	return (ret_val);
2965779Sxy150489 }
2975779Sxy150489 
2985779Sxy150489 /*
2995779Sxy150489  * e1000_standby_nvm - Return EEPROM to standby state
3005779Sxy150489  * @hw: pointer to the HW structure
3015779Sxy150489  *
3025779Sxy150489  * Return the EEPROM to a standby state.
3035779Sxy150489  */
3045779Sxy150489 static void
3055779Sxy150489 e1000_standby_nvm(struct e1000_hw *hw)
3065779Sxy150489 {
3075779Sxy150489 	struct e1000_nvm_info *nvm = &hw->nvm;
3085779Sxy150489 	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
3095779Sxy150489 
3105779Sxy150489 	DEBUGFUNC("e1000_standby_nvm");
3115779Sxy150489 
3125779Sxy150489 	if (nvm->type == e1000_nvm_eeprom_microwire) {
3135779Sxy150489 		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
3145779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
3155779Sxy150489 		E1000_WRITE_FLUSH(hw);
3165779Sxy150489 		usec_delay(nvm->delay_usec);
3175779Sxy150489 
3185779Sxy150489 		e1000_raise_eec_clk(hw, &eecd);
3195779Sxy150489 
3205779Sxy150489 		/* Select EEPROM */
3215779Sxy150489 		eecd |= E1000_EECD_CS;
3225779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
3235779Sxy150489 		E1000_WRITE_FLUSH(hw);
3245779Sxy150489 		usec_delay(nvm->delay_usec);
3255779Sxy150489 
3265779Sxy150489 		e1000_lower_eec_clk(hw, &eecd);
3275779Sxy150489 	} else if (nvm->type == e1000_nvm_eeprom_spi) {
3285779Sxy150489 		/* Toggle CS to flush commands */
3295779Sxy150489 		eecd |= E1000_EECD_CS;
3305779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
3315779Sxy150489 		E1000_WRITE_FLUSH(hw);
3325779Sxy150489 		usec_delay(nvm->delay_usec);
3335779Sxy150489 		eecd &= ~E1000_EECD_CS;
3345779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
3355779Sxy150489 		E1000_WRITE_FLUSH(hw);
3365779Sxy150489 		usec_delay(nvm->delay_usec);
3375779Sxy150489 	}
3385779Sxy150489 }
3395779Sxy150489 
3405779Sxy150489 /*
3415779Sxy150489  * e1000_stop_nvm - Terminate EEPROM command
3425779Sxy150489  * @hw: pointer to the HW structure
3435779Sxy150489  *
3445779Sxy150489  * Terminates the current command by inverting the EEPROM's chip select pin.
3455779Sxy150489  */
3465779Sxy150489 void
3475779Sxy150489 e1000_stop_nvm(struct e1000_hw *hw)
3485779Sxy150489 {
3495779Sxy150489 	u32 eecd;
3505779Sxy150489 
3515779Sxy150489 	DEBUGFUNC("e1000_stop_nvm");
3525779Sxy150489 
3535779Sxy150489 	eecd = E1000_READ_REG(hw, E1000_EECD);
3545779Sxy150489 	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
3555779Sxy150489 		/* Pull CS high */
3565779Sxy150489 		eecd |= E1000_EECD_CS;
3575779Sxy150489 		e1000_lower_eec_clk(hw, &eecd);
3585779Sxy150489 	} else if (hw->nvm.type == e1000_nvm_eeprom_microwire) {
3598571SChenlu.Chen@Sun.COM 		/* CS on Microwire is active-high */
3605779Sxy150489 		eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
3615779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
3625779Sxy150489 		e1000_raise_eec_clk(hw, &eecd);
3635779Sxy150489 		e1000_lower_eec_clk(hw, &eecd);
3645779Sxy150489 	}
3655779Sxy150489 }
3665779Sxy150489 
3675779Sxy150489 /*
3685779Sxy150489  * e1000_release_nvm_generic - Release exclusive access to EEPROM
3695779Sxy150489  * @hw: pointer to the HW structure
3705779Sxy150489  *
3715779Sxy150489  * Stop any current commands to the EEPROM and clear the EEPROM request bit.
3725779Sxy150489  */
3735779Sxy150489 void
3745779Sxy150489 e1000_release_nvm_generic(struct e1000_hw *hw)
3755779Sxy150489 {
3765779Sxy150489 	u32 eecd;
3775779Sxy150489 
3785779Sxy150489 	DEBUGFUNC("e1000_release_nvm_generic");
3795779Sxy150489 
3805779Sxy150489 	e1000_stop_nvm(hw);
3815779Sxy150489 
3825779Sxy150489 	eecd = E1000_READ_REG(hw, E1000_EECD);
3835779Sxy150489 	eecd &= ~E1000_EECD_REQ;
3845779Sxy150489 	E1000_WRITE_REG(hw, E1000_EECD, eecd);
3855779Sxy150489 }
3865779Sxy150489 
3875779Sxy150489 /*
3885779Sxy150489  * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
3895779Sxy150489  * @hw: pointer to the HW structure
3905779Sxy150489  *
3915779Sxy150489  * Setups the EEPROM for reading and writing.
3925779Sxy150489  */
3935779Sxy150489 static s32
3945779Sxy150489 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
3955779Sxy150489 {
3965779Sxy150489 	struct e1000_nvm_info *nvm = &hw->nvm;
3975779Sxy150489 	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
3985779Sxy150489 	s32 ret_val = E1000_SUCCESS;
3995779Sxy150489 	u16 timeout = 0;
4005779Sxy150489 	u8 spi_stat_reg;
4015779Sxy150489 
4025779Sxy150489 	DEBUGFUNC("e1000_ready_nvm_eeprom");
4035779Sxy150489 
4045779Sxy150489 	if (nvm->type == e1000_nvm_eeprom_microwire) {
4055779Sxy150489 		/* Clear SK and DI */
4065779Sxy150489 		eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
4075779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
4085779Sxy150489 		/* Set CS */
4095779Sxy150489 		eecd |= E1000_EECD_CS;
4105779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
4115779Sxy150489 	} else if (nvm->type == e1000_nvm_eeprom_spi) {
4125779Sxy150489 		/* Clear SK and CS */
4135779Sxy150489 		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
4145779Sxy150489 		E1000_WRITE_REG(hw, E1000_EECD, eecd);
4155779Sxy150489 		usec_delay(1);
4165779Sxy150489 		timeout = NVM_MAX_RETRY_SPI;
4175779Sxy150489 
4185779Sxy150489 		/*
4195779Sxy150489 		 * Read "Status Register" repeatedly until the LSB is cleared.
4205779Sxy150489 		 * The EEPROM will signal that the command has been completed
4215779Sxy150489 		 * by clearing bit 0 of the internal status register.  If it's
4225779Sxy150489 		 * not cleared within 'timeout', then error out.
4235779Sxy150489 		 */
4245779Sxy150489 		while (timeout) {
4255779Sxy150489 			e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
4265779Sxy150489 			    hw->nvm.opcode_bits);
4275779Sxy150489 			spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8);
4285779Sxy150489 			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
4295779Sxy150489 				break;
4305779Sxy150489 
4315779Sxy150489 			usec_delay(5);
4325779Sxy150489 			e1000_standby_nvm(hw);
4335779Sxy150489 			timeout--;
4345779Sxy150489 		}
4355779Sxy150489 
4365779Sxy150489 		if (!timeout) {
4375779Sxy150489 			DEBUGOUT("SPI NVM Status error\n");
4385779Sxy150489 			ret_val = -E1000_ERR_NVM;
4395779Sxy150489 			goto out;
4405779Sxy150489 		}
4415779Sxy150489 	}
4425779Sxy150489 
4435779Sxy150489 out:
4445779Sxy150489 	return (ret_val);
4455779Sxy150489 }
4465779Sxy150489 
4475779Sxy150489 /*
4485779Sxy150489  * e1000_read_nvm_microwire - Reads EEPROM's using microwire
4495779Sxy150489  * @hw: pointer to the HW structure
4505779Sxy150489  * @offset: offset of word in the EEPROM to read
4515779Sxy150489  * @words: number of words to read
4525779Sxy150489  * @data: word read from the EEPROM
4535779Sxy150489  *
4545779Sxy150489  * Reads a 16 bit word from the EEPROM.
4555779Sxy150489  */
4565779Sxy150489 s32
4575779Sxy150489 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words,
4585779Sxy150489     u16 *data)
4595779Sxy150489 {
4605779Sxy150489 	struct e1000_nvm_info *nvm = &hw->nvm;
4615779Sxy150489 	u32 i = 0;
4625779Sxy150489 	s32 ret_val;
4635779Sxy150489 	u8 read_opcode = NVM_READ_OPCODE_MICROWIRE;
4645779Sxy150489 
4655779Sxy150489 	DEBUGFUNC("e1000_read_nvm_microwire");
4665779Sxy150489 
4675779Sxy150489 	/*
4685779Sxy150489 	 * A check for invalid values:  offset too large, too many words,
4695779Sxy150489 	 * and not enough words.
4705779Sxy150489 	 */
4715779Sxy150489 	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
4725779Sxy150489 	    (words == 0)) {
4735779Sxy150489 		DEBUGOUT("nvm parameter(s) out of bounds\n");
4745779Sxy150489 		ret_val = -E1000_ERR_NVM;
4755779Sxy150489 		goto out;
4765779Sxy150489 	}
4775779Sxy150489 
4788571SChenlu.Chen@Sun.COM 	ret_val = nvm->ops.acquire(hw);
4795779Sxy150489 	if (ret_val)
4805779Sxy150489 		goto out;
4815779Sxy150489 
4825779Sxy150489 	ret_val = e1000_ready_nvm_eeprom(hw);
4835779Sxy150489 	if (ret_val)
4845779Sxy150489 		goto release;
4855779Sxy150489 
4865779Sxy150489 	for (i = 0; i < words; i++) {
4875779Sxy150489 		/* Send the READ command (opcode + addr) */
4885779Sxy150489 		e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
4895779Sxy150489 		e1000_shift_out_eec_bits(hw, (u16)(offset + i),
4905779Sxy150489 		    nvm->address_bits);
4915779Sxy150489 
4925779Sxy150489 		/*
4935779Sxy150489 		 * Read the data.  For microwire, each word requires the
4945779Sxy150489 		 * overhead of setup and tear-down.
4955779Sxy150489 		 */
4965779Sxy150489 		data[i] = e1000_shift_in_eec_bits(hw, 16);
4975779Sxy150489 		e1000_standby_nvm(hw);
4985779Sxy150489 	}
4995779Sxy150489 
5005779Sxy150489 release:
5018571SChenlu.Chen@Sun.COM 	nvm->ops.release(hw);
5025779Sxy150489 
5035779Sxy150489 out:
5045779Sxy150489 	return (ret_val);
5055779Sxy150489 }
5065779Sxy150489 
5075779Sxy150489 /*
5085779Sxy150489  * e1000_read_nvm_eerd - Reads EEPROM using EERD register
5095779Sxy150489  * @hw: pointer to the HW structure
5105779Sxy150489  * @offset: offset of word in the EEPROM to read
5115779Sxy150489  * @words: number of words to read
5125779Sxy150489  * @data: word read from the EEPROM
5135779Sxy150489  *
5145779Sxy150489  * Reads a 16 bit word from the EEPROM using the EERD register.
5155779Sxy150489  */
5165779Sxy150489 s32
5175779Sxy150489 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
5185779Sxy150489 {
5195779Sxy150489 	struct e1000_nvm_info *nvm = &hw->nvm;
5205779Sxy150489 	u32 i, eerd = 0;
5215779Sxy150489 	s32 ret_val = E1000_SUCCESS;
5225779Sxy150489 
5235779Sxy150489 	DEBUGFUNC("e1000_read_nvm_eerd");
5245779Sxy150489 
5255779Sxy150489 	/*
5265779Sxy150489 	 * A check for invalid values:  offset too large, too many words,
5275779Sxy150489 	 * too many words for the offset, and not enough words.
5285779Sxy150489 	 */
5295779Sxy150489 	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
5305779Sxy150489 	    (words == 0)) {
5315779Sxy150489 		DEBUGOUT("nvm parameter(s) out of bounds\n");
5325779Sxy150489 		ret_val = -E1000_ERR_NVM;
5335779Sxy150489 		goto out;
5345779Sxy150489 	}
5355779Sxy150489 
5365779Sxy150489 	for (i = 0; i < words; i++) {
5375779Sxy150489 		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
5385779Sxy150489 		    E1000_NVM_RW_REG_START;
5395779Sxy150489 
5405779Sxy150489 		E1000_WRITE_REG(hw, E1000_EERD, eerd);
5415779Sxy150489 		ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
5425779Sxy150489 		if (ret_val)
5435779Sxy150489 			break;
5445779Sxy150489 
5455779Sxy150489 		data[i] = (E1000_READ_REG(hw, E1000_EERD) >>
5465779Sxy150489 		    E1000_NVM_RW_REG_DATA);
5475779Sxy150489 	}
5485779Sxy150489 
5495779Sxy150489 out:
5505779Sxy150489 	return (ret_val);
5515779Sxy150489 }
5525779Sxy150489 
5535779Sxy150489 /*
5545779Sxy150489  * e1000_write_nvm_spi - Write to EEPROM using SPI
5555779Sxy150489  * @hw: pointer to the HW structure
5565779Sxy150489  * @offset: offset within the EEPROM to be written to
5575779Sxy150489  * @words: number of words to write
5585779Sxy150489  * @data: 16 bit word(s) to be written to the EEPROM
5595779Sxy150489  *
5605779Sxy150489  * Writes data to EEPROM at offset using SPI interface.
5615779Sxy150489  *
5625779Sxy150489  * If e1000_update_nvm_checksum is not called after this function , the
5638571SChenlu.Chen@Sun.COM  * EEPROM will most likely contain an invalid checksum.
5645779Sxy150489  */
5655779Sxy150489 s32
5665779Sxy150489 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
5675779Sxy150489 {
5685779Sxy150489 	struct e1000_nvm_info *nvm = &hw->nvm;
5695779Sxy150489 	s32 ret_val;
5705779Sxy150489 	u16 widx = 0;
5715779Sxy150489 
5725779Sxy150489 	DEBUGFUNC("e1000_write_nvm_spi");
5735779Sxy150489 
5745779Sxy150489 	/*
5755779Sxy150489 	 * A check for invalid values:  offset too large, too many words,
5765779Sxy150489 	 * and not enough words.
5775779Sxy150489 	 */
5785779Sxy150489 	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
5795779Sxy150489 	    (words == 0)) {
5805779Sxy150489 		DEBUGOUT("nvm parameter(s) out of bounds\n");
5815779Sxy150489 		ret_val = -E1000_ERR_NVM;
5825779Sxy150489 		goto out;
5835779Sxy150489 	}
5845779Sxy150489 
5858571SChenlu.Chen@Sun.COM 	ret_val = nvm->ops.acquire(hw);
5865779Sxy150489 	if (ret_val)
5875779Sxy150489 		goto out;
5885779Sxy150489 
5895779Sxy150489 	while (widx < words) {
5905779Sxy150489 		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
5915779Sxy150489 
5925779Sxy150489 		ret_val = e1000_ready_nvm_eeprom(hw);
5935779Sxy150489 		if (ret_val)
5945779Sxy150489 			goto release;
5955779Sxy150489 
5965779Sxy150489 		e1000_standby_nvm(hw);
5975779Sxy150489 
5985779Sxy150489 		/* Send the WRITE ENABLE command (8 bit opcode) */
5995779Sxy150489 		e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
6005779Sxy150489 		    nvm->opcode_bits);
6015779Sxy150489 
6025779Sxy150489 		e1000_standby_nvm(hw);
6035779Sxy150489 
6045779Sxy150489 		/*
6055779Sxy150489 		 * Some SPI eeproms use the 8th address bit embedded in the
6065779Sxy150489 		 * opcode
6075779Sxy150489 		 */
6085779Sxy150489 		if ((nvm->address_bits == 8) && (offset >= 128))
6095779Sxy150489 			write_opcode |= NVM_A8_OPCODE_SPI;
6105779Sxy150489 
6115779Sxy150489 		/* Send the Write command (8-bit opcode + addr) */
6125779Sxy150489 		e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
6135779Sxy150489 		e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
6145779Sxy150489 		    nvm->address_bits);
6155779Sxy150489 
6165779Sxy150489 		/* Loop to allow for up to whole page write of eeprom */
6175779Sxy150489 		while (widx < words) {
6185779Sxy150489 			u16 word_out = data[widx];
6195779Sxy150489 			word_out = (word_out >> 8) | (word_out << 8);
6205779Sxy150489 			e1000_shift_out_eec_bits(hw, word_out, 16);
6215779Sxy150489 			widx++;
6225779Sxy150489 
6235779Sxy150489 			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
6245779Sxy150489 				e1000_standby_nvm(hw);
6255779Sxy150489 				break;
6265779Sxy150489 			}
6275779Sxy150489 		}
6285779Sxy150489 	}
6295779Sxy150489 
6305779Sxy150489 	msec_delay(10);
6315779Sxy150489 release:
6328571SChenlu.Chen@Sun.COM 	nvm->ops.release(hw);
6335779Sxy150489 
6345779Sxy150489 out:
6355779Sxy150489 	return (ret_val);
6365779Sxy150489 }
6375779Sxy150489 
6385779Sxy150489 /*
6395779Sxy150489  * e1000_write_nvm_microwire - Writes EEPROM using microwire
6405779Sxy150489  * @hw: pointer to the HW structure
6415779Sxy150489  * @offset: offset within the EEPROM to be written to
6425779Sxy150489  * @words: number of words to write
6435779Sxy150489  * @data: 16 bit word(s) to be written to the EEPROM
6445779Sxy150489  *
6455779Sxy150489  * Writes data to EEPROM at offset using microwire interface.
6465779Sxy150489  *
6475779Sxy150489  * If e1000_update_nvm_checksum is not called after this function , the
6488571SChenlu.Chen@Sun.COM  * EEPROM will most likely contain an invalid checksum.
6495779Sxy150489  */
6505779Sxy150489 s32
6515779Sxy150489 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words,
6525779Sxy150489 	u16 *data)
6535779Sxy150489 {
6545779Sxy150489 	struct e1000_nvm_info *nvm = &hw->nvm;
6555779Sxy150489 	s32  ret_val;
6565779Sxy150489 	u32 eecd;
6575779Sxy150489 	u16 words_written = 0;
6585779Sxy150489 	u16 widx = 0;
6595779Sxy150489 
6605779Sxy150489 	DEBUGFUNC("e1000_write_nvm_microwire");
6615779Sxy150489 
6625779Sxy150489 	/*
6635779Sxy150489 	 * A check for invalid values:  offset too large, too many words,
6645779Sxy150489 	 * and not enough words.
6655779Sxy150489 	 */
6665779Sxy150489 	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
6675779Sxy150489 	    (words == 0)) {
6685779Sxy150489 		DEBUGOUT("nvm parameter(s) out of bounds\n");
6695779Sxy150489 		ret_val = -E1000_ERR_NVM;
6705779Sxy150489 		goto out;
6715779Sxy150489 	}
6725779Sxy150489 
6738571SChenlu.Chen@Sun.COM 	ret_val = nvm->ops.acquire(hw);
6745779Sxy150489 	if (ret_val)
6755779Sxy150489 		goto out;
6765779Sxy150489 
6775779Sxy150489 	ret_val = e1000_ready_nvm_eeprom(hw);
6785779Sxy150489 	if (ret_val)
6795779Sxy150489 		goto release;
6805779Sxy150489 
6815779Sxy150489 	e1000_shift_out_eec_bits(hw, NVM_EWEN_OPCODE_MICROWIRE,
6825779Sxy150489 	    (u16)(nvm->opcode_bits + 2));
6835779Sxy150489 
6845779Sxy150489 	e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2));
6855779Sxy150489 
6865779Sxy150489 	e1000_standby_nvm(hw);
6875779Sxy150489 
6885779Sxy150489 	while (words_written < words) {
6895779Sxy150489 		e1000_shift_out_eec_bits(hw, NVM_WRITE_OPCODE_MICROWIRE,
6905779Sxy150489 		    nvm->opcode_bits);
6915779Sxy150489 
6925779Sxy150489 		e1000_shift_out_eec_bits(hw, (u16)(offset + words_written),
6935779Sxy150489 		    nvm->address_bits);
6945779Sxy150489 
6955779Sxy150489 		e1000_shift_out_eec_bits(hw, data[words_written], 16);
6965779Sxy150489 
6975779Sxy150489 		e1000_standby_nvm(hw);
6985779Sxy150489 
6995779Sxy150489 		for (widx = 0; widx < 200; widx++) {
7005779Sxy150489 			eecd = E1000_READ_REG(hw, E1000_EECD);
7015779Sxy150489 			if (eecd & E1000_EECD_DO)
7025779Sxy150489 				break;
7035779Sxy150489 			usec_delay(50);
7045779Sxy150489 		}
7055779Sxy150489 
7065779Sxy150489 		if (widx == 200) {
7075779Sxy150489 			DEBUGOUT("NVM Write did not complete\n");
7085779Sxy150489 			ret_val = -E1000_ERR_NVM;
7095779Sxy150489 			goto release;
7105779Sxy150489 		}
7115779Sxy150489 
7125779Sxy150489 		e1000_standby_nvm(hw);
7135779Sxy150489 
7145779Sxy150489 		words_written++;
7155779Sxy150489 	}
7165779Sxy150489 
7175779Sxy150489 	e1000_shift_out_eec_bits(hw, NVM_EWDS_OPCODE_MICROWIRE,
7185779Sxy150489 	    (u16)(nvm->opcode_bits + 2));
7195779Sxy150489 
7205779Sxy150489 	e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2));
7215779Sxy150489 
7225779Sxy150489 release:
7238571SChenlu.Chen@Sun.COM 	nvm->ops.release(hw);
7245779Sxy150489 
7255779Sxy150489 out:
7265779Sxy150489 	return (ret_val);
7275779Sxy150489 }
7285779Sxy150489 
7295779Sxy150489 /*
7305779Sxy150489  * e1000_read_pba_num_generic - Read device part number
7315779Sxy150489  * @hw: pointer to the HW structure
7325779Sxy150489  * @pba_num: pointer to device part number
7335779Sxy150489  *
7345779Sxy150489  * Reads the product board assembly (PBA) number from the EEPROM and stores
7355779Sxy150489  * the value in pba_num.
7365779Sxy150489  */
7375779Sxy150489 s32
7385779Sxy150489 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num)
7395779Sxy150489 {
7405779Sxy150489 	s32  ret_val;
7415779Sxy150489 	u16 nvm_data;
7425779Sxy150489 
7435779Sxy150489 	DEBUGFUNC("e1000_read_pba_num_generic");
7445779Sxy150489 
7458571SChenlu.Chen@Sun.COM 	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
7465779Sxy150489 	if (ret_val) {
7475779Sxy150489 		DEBUGOUT("NVM Read Error\n");
7485779Sxy150489 		goto out;
7495779Sxy150489 	}
7505779Sxy150489 	*pba_num = (u32)(nvm_data << 16);
7515779Sxy150489 
7528571SChenlu.Chen@Sun.COM 	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
7535779Sxy150489 	if (ret_val) {
7545779Sxy150489 		DEBUGOUT("NVM Read Error\n");
7555779Sxy150489 		goto out;
7565779Sxy150489 	}
7575779Sxy150489 	*pba_num |= nvm_data;
7585779Sxy150489 
7595779Sxy150489 out:
7605779Sxy150489 	return (ret_val);
7615779Sxy150489 }
7625779Sxy150489 
7635779Sxy150489 /*
7645779Sxy150489  * e1000_read_mac_addr_generic - Read device MAC address
7655779Sxy150489  * @hw: pointer to the HW structure
7665779Sxy150489  *
7675779Sxy150489  * Reads the device MAC address from the EEPROM and stores the value.
7685779Sxy150489  * Since devices with two ports use the same EEPROM, we increment the
7695779Sxy150489  * last bit in the MAC address for the second port.
7705779Sxy150489  */
7715779Sxy150489 s32
7725779Sxy150489 e1000_read_mac_addr_generic(struct e1000_hw *hw)
7735779Sxy150489 {
774*10319SJason.Xu@Sun.COM 	u32 rar_high;
775*10319SJason.Xu@Sun.COM 	u32 rar_low;
776*10319SJason.Xu@Sun.COM 	u16 i;
7775779Sxy150489 
778*10319SJason.Xu@Sun.COM 	rar_high = E1000_READ_REG(hw, E1000_RAH(0));
779*10319SJason.Xu@Sun.COM 	rar_low = E1000_READ_REG(hw, E1000_RAL(0));
7805779Sxy150489 
781*10319SJason.Xu@Sun.COM 	for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
782*10319SJason.Xu@Sun.COM 		hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
783*10319SJason.Xu@Sun.COM 
784*10319SJason.Xu@Sun.COM 	for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
785*10319SJason.Xu@Sun.COM 		hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
7865779Sxy150489 
7875779Sxy150489 	for (i = 0; i < ETH_ADDR_LEN; i++)
7885779Sxy150489 		hw->mac.addr[i] = hw->mac.perm_addr[i];
7895779Sxy150489 
790*10319SJason.Xu@Sun.COM 	return (E1000_SUCCESS);
7915779Sxy150489 }
7925779Sxy150489 
7935779Sxy150489 /*
7945779Sxy150489  * e1000_validate_nvm_checksum_generic - Validate EEPROM checksum
7955779Sxy150489  * @hw: pointer to the HW structure
7965779Sxy150489  *
7975779Sxy150489  * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
7985779Sxy150489  * and then verifies that the sum of the EEPROM is equal to 0xBABA.
7995779Sxy150489  */
8005779Sxy150489 s32
8015779Sxy150489 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw)
8025779Sxy150489 {
8035779Sxy150489 	s32 ret_val = E1000_SUCCESS;
8045779Sxy150489 	u16 checksum = 0;
8055779Sxy150489 	u16 i, nvm_data;
8065779Sxy150489 
8075779Sxy150489 	DEBUGFUNC("e1000_validate_nvm_checksum_generic");
8085779Sxy150489 
8095779Sxy150489 	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
8108571SChenlu.Chen@Sun.COM 		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
8115779Sxy150489 		if (ret_val) {
8125779Sxy150489 			DEBUGOUT("NVM Read Error\n");
8135779Sxy150489 			goto out;
8145779Sxy150489 		}
8155779Sxy150489 		checksum += nvm_data;
8165779Sxy150489 	}
8175779Sxy150489 
8185779Sxy150489 	if (checksum != (u16) NVM_SUM) {
8195779Sxy150489 		DEBUGOUT("NVM Checksum Invalid\n");
8205779Sxy150489 		ret_val = -E1000_ERR_NVM;
8215779Sxy150489 		goto out;
8225779Sxy150489 	}
8235779Sxy150489 
8245779Sxy150489 out:
8255779Sxy150489 	return (ret_val);
8265779Sxy150489 }
8275779Sxy150489 
8285779Sxy150489 /*
8295779Sxy150489  * e1000_update_nvm_checksum_generic - Update EEPROM checksum
8305779Sxy150489  * @hw: pointer to the HW structure
8315779Sxy150489  *
8325779Sxy150489  * Updates the EEPROM checksum by reading/adding each word of the EEPROM
8335779Sxy150489  * up to the checksum.  Then calculates the EEPROM checksum and writes the
8345779Sxy150489  * value to the EEPROM.
8355779Sxy150489  */
8365779Sxy150489 s32
8375779Sxy150489 e1000_update_nvm_checksum_generic(struct e1000_hw *hw)
8385779Sxy150489 {
8395779Sxy150489 	s32  ret_val;
8405779Sxy150489 	u16 checksum = 0;
8415779Sxy150489 	u16 i, nvm_data;
8425779Sxy150489 
8435779Sxy150489 	DEBUGFUNC("e1000_update_nvm_checksum");
8445779Sxy150489 
8455779Sxy150489 	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
8468571SChenlu.Chen@Sun.COM 		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
8475779Sxy150489 		if (ret_val) {
8485779Sxy150489 			DEBUGOUT("NVM Read Error while updating checksum.\n");
8495779Sxy150489 			goto out;
8505779Sxy150489 		}
8515779Sxy150489 		checksum += nvm_data;
8525779Sxy150489 	}
8535779Sxy150489 	checksum = (u16) NVM_SUM - checksum;
8548571SChenlu.Chen@Sun.COM 	ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
8558571SChenlu.Chen@Sun.COM 	if (ret_val)
8565779Sxy150489 		DEBUGOUT("NVM Write Error while updating checksum.\n");
8575779Sxy150489 
8585779Sxy150489 out:
8595779Sxy150489 	return (ret_val);
8605779Sxy150489 }
8615779Sxy150489 
8625779Sxy150489 /*
8635779Sxy150489  * e1000_reload_nvm_generic - Reloads EEPROM
8645779Sxy150489  * @hw: pointer to the HW structure
8655779Sxy150489  *
8665779Sxy150489  * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
8675779Sxy150489  * extended control register.
8685779Sxy150489  */
8695779Sxy150489 void
8705779Sxy150489 e1000_reload_nvm_generic(struct e1000_hw *hw)
8715779Sxy150489 {
8725779Sxy150489 	u32 ctrl_ext;
8735779Sxy150489 
8745779Sxy150489 	DEBUGFUNC("e1000_reload_nvm_generic");
8755779Sxy150489 
8765779Sxy150489 	usec_delay(10);
8775779Sxy150489 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
8785779Sxy150489 	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
8795779Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
8805779Sxy150489 	E1000_WRITE_FLUSH(hw);
8815779Sxy150489 }
882