Home | History | Annotate | Line # | Download | only in igc
igc_nvm.c revision 1.1.1.1
      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
     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
     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
     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
     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
     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
    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
    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
    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
    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