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