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