forked from mirrors/linux
		
	ice: Reimplement module reads used by ethtool
There was an excessive increment of the QSFP page, which is now fixed. Additionally, this new update now reads 8 bytes at a time and will retry each request if the module/bus is busy. Also, prevent reading from upper pages if module does not support those pages. Signed-off-by: Scott W Taylor <scott.w.taylor@intel.com> Tested-by: Tony Brelinski <tonyx.brelinski@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
		
							parent
							
								
									d59684a07e
								
							
						
					
					
						commit
						e9c9692c8a
					
				
					 1 changed files with 39 additions and 10 deletions
				
			
		| 
						 | 
					@ -3914,30 +3914,33 @@ ice_get_module_eeprom(struct net_device *netdev,
 | 
				
			||||||
		      struct ethtool_eeprom *ee, u8 *data)
 | 
							      struct ethtool_eeprom *ee, u8 *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ice_netdev_priv *np = netdev_priv(netdev);
 | 
						struct ice_netdev_priv *np = netdev_priv(netdev);
 | 
				
			||||||
 | 
					#define SFF_READ_BLOCK_SIZE 8
 | 
				
			||||||
 | 
						u8 value[SFF_READ_BLOCK_SIZE] = { 0 };
 | 
				
			||||||
	u8 addr = ICE_I2C_EEPROM_DEV_ADDR;
 | 
						u8 addr = ICE_I2C_EEPROM_DEV_ADDR;
 | 
				
			||||||
	struct ice_vsi *vsi = np->vsi;
 | 
						struct ice_vsi *vsi = np->vsi;
 | 
				
			||||||
	struct ice_pf *pf = vsi->back;
 | 
						struct ice_pf *pf = vsi->back;
 | 
				
			||||||
	struct ice_hw *hw = &pf->hw;
 | 
						struct ice_hw *hw = &pf->hw;
 | 
				
			||||||
	enum ice_status status;
 | 
						enum ice_status status;
 | 
				
			||||||
	bool is_sfp = false;
 | 
						bool is_sfp = false;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i, j;
 | 
				
			||||||
	u16 offset = 0;
 | 
						u16 offset = 0;
 | 
				
			||||||
	u8 value = 0;
 | 
					 | 
				
			||||||
	u8 page = 0;
 | 
						u8 page = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ee || !ee->len || !data)
 | 
						if (!ee || !ee->len || !data)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, 0, &value, 1, 0,
 | 
						status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, 0, value, 1, 0,
 | 
				
			||||||
				   NULL);
 | 
									   NULL);
 | 
				
			||||||
	if (status)
 | 
						if (status)
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (value == ICE_MODULE_TYPE_SFP)
 | 
						if (value[0] == ICE_MODULE_TYPE_SFP)
 | 
				
			||||||
		is_sfp = true;
 | 
							is_sfp = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ee->len; i++) {
 | 
						memset(data, 0, ee->len);
 | 
				
			||||||
 | 
						for (i = 0; i < ee->len; i += SFF_READ_BLOCK_SIZE) {
 | 
				
			||||||
		offset = i + ee->offset;
 | 
							offset = i + ee->offset;
 | 
				
			||||||
 | 
							page = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Check if we need to access the other memory page */
 | 
							/* Check if we need to access the other memory page */
 | 
				
			||||||
		if (is_sfp) {
 | 
							if (is_sfp) {
 | 
				
			||||||
| 
						 | 
					@ -3953,11 +3956,37 @@ ice_get_module_eeprom(struct net_device *netdev,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, !is_sfp,
 | 
							/* Bit 2 of EEPROM address 0x02 declares upper
 | 
				
			||||||
					   &value, 1, 0, NULL);
 | 
							 * pages are disabled on QSFP modules.
 | 
				
			||||||
		if (status)
 | 
							 * SFP modules only ever use page 0.
 | 
				
			||||||
			value = 0;
 | 
							 */
 | 
				
			||||||
		data[i] = value;
 | 
							if (page == 0 || !(data[0x2] & 0x4)) {
 | 
				
			||||||
 | 
								/* If i2c bus is busy due to slow page change or
 | 
				
			||||||
 | 
								 * link management access, call can fail. This is normal.
 | 
				
			||||||
 | 
								 * So we retry this a few times.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								for (j = 0; j < 4; j++) {
 | 
				
			||||||
 | 
									status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
 | 
				
			||||||
 | 
												   !is_sfp, value,
 | 
				
			||||||
 | 
												   SFF_READ_BLOCK_SIZE,
 | 
				
			||||||
 | 
												   0, NULL);
 | 
				
			||||||
 | 
									netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n",
 | 
				
			||||||
 | 
										   addr, offset, page, is_sfp,
 | 
				
			||||||
 | 
										   value[0], value[1], value[2], value[3],
 | 
				
			||||||
 | 
										   value[4], value[5], value[6], value[7],
 | 
				
			||||||
 | 
										   status);
 | 
				
			||||||
 | 
									if (status) {
 | 
				
			||||||
 | 
										usleep_range(1500, 2500);
 | 
				
			||||||
 | 
										memset(value, 0, SFF_READ_BLOCK_SIZE);
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* Make sure we have enough room for the new block */
 | 
				
			||||||
 | 
								if ((i + SFF_READ_BLOCK_SIZE) < ee->len)
 | 
				
			||||||
 | 
									memcpy(data + i, value, SFF_READ_BLOCK_SIZE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue