ice: implement snapshot for device capabilities
Add a new devlink region used for capturing a snapshot of the device capabilities buffer which is reported by the firmware over the AdminQ. This information can useful in debugging driver and firmware interactions. Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
		
							parent
							
								
									2b04a66156
								
							
						
					
					
						commit
						8d7aab3515
					
				| @ -373,6 +373,7 @@ struct ice_pf { | ||||
| 	struct devlink_port devlink_port; | ||||
| 
 | ||||
| 	struct devlink_region *nvm_region; | ||||
| 	struct devlink_region *devcaps_region; | ||||
| 
 | ||||
| 	/* OS reserved IRQ details */ | ||||
| 	struct msix_entry *msix_entries; | ||||
|  | ||||
| @ -1823,20 +1823,27 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count, | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ice_aq_discover_caps - query function/device capabilities | ||||
|  * ice_aq_list_caps - query function/device capabilities | ||||
|  * @hw: pointer to the HW struct | ||||
|  * @buf: a virtual buffer to hold the capabilities | ||||
|  * @buf_size: Size of the virtual buffer | ||||
|  * @cap_count: cap count needed if AQ err==ENOMEM | ||||
|  * @opc: capabilities type to discover - pass in the command opcode | ||||
|  * @buf: a buffer to hold the capabilities | ||||
|  * @buf_size: size of the buffer | ||||
|  * @cap_count: if not NULL, set to the number of capabilities reported | ||||
|  * @opc: capabilities type to discover, device or function | ||||
|  * @cd: pointer to command details structure or NULL | ||||
|  * | ||||
|  * Get the function(0x000a)/device(0x000b) capabilities description from | ||||
|  * the firmware. | ||||
|  * Get the function (0x000A) or device (0x000B) capabilities description from | ||||
|  * firmware and store it in the buffer. | ||||
|  * | ||||
|  * If the cap_count pointer is not NULL, then it is set to the number of | ||||
|  * capabilities firmware will report. Note that if the buffer size is too | ||||
|  * small, it is possible the command will return ICE_AQ_ERR_ENOMEM. The | ||||
|  * cap_count will still be updated in this case. It is recommended that the | ||||
|  * buffer size be set to ICE_AQ_MAX_BUF_LEN (the largest possible buffer that | ||||
|  * firmware could return) to avoid this. | ||||
|  */ | ||||
| static enum ice_status | ||||
| ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, | ||||
| 		     enum ice_adminq_opc opc, struct ice_sq_cd *cd) | ||||
| enum ice_status | ||||
| ice_aq_list_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, | ||||
| 		 enum ice_adminq_opc opc, struct ice_sq_cd *cd) | ||||
| { | ||||
| 	struct ice_aqc_list_caps *cmd; | ||||
| 	struct ice_aq_desc desc; | ||||
| @ -1849,12 +1856,43 @@ ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, | ||||
| 		return ICE_ERR_PARAM; | ||||
| 
 | ||||
| 	ice_fill_dflt_direct_cmd_desc(&desc, opc); | ||||
| 
 | ||||
| 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); | ||||
| 	if (!status) | ||||
| 		ice_parse_caps(hw, buf, le32_to_cpu(cmd->count), opc); | ||||
| 	else if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOMEM) | ||||
| 
 | ||||
| 	if (cap_count) | ||||
| 		*cap_count = le32_to_cpu(cmd->count); | ||||
| 
 | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ice_aq_discover_caps - query function/device capabilities | ||||
|  * @hw: pointer to the HW struct | ||||
|  * @buf: a virtual buffer to hold the capabilities | ||||
|  * @buf_size: Size of the virtual buffer | ||||
|  * @cap_count: cap count needed if AQ err==ENOMEM | ||||
|  * @opc: capabilities type to discover - pass in the command opcode | ||||
|  * @cd: pointer to command details structure or NULL | ||||
|  * | ||||
|  * Get the function(0x000a)/device(0x000b) capabilities description from | ||||
|  * the firmware. | ||||
|  * | ||||
|  * NOTE: this function has the side effect of updating the hw->dev_caps or | ||||
|  * hw->func_caps by way of calling ice_parse_caps. | ||||
|  */ | ||||
| static enum ice_status | ||||
| ice_aq_discover_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, | ||||
| 		     enum ice_adminq_opc opc, struct ice_sq_cd *cd) | ||||
| { | ||||
| 	u32 local_cap_count = 0; | ||||
| 	enum ice_status status; | ||||
| 
 | ||||
| 	status = ice_aq_list_caps(hw, buf, buf_size, &local_cap_count, | ||||
| 				  opc, cd); | ||||
| 	if (!status) | ||||
| 		ice_parse_caps(hw, buf, local_cap_count, opc); | ||||
| 	else if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOMEM) | ||||
| 		*cap_count = local_cap_count; | ||||
| 
 | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -87,6 +87,9 @@ enum ice_status | ||||
| ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode, | ||||
| 		    struct ice_aqc_get_phy_caps_data *caps, | ||||
| 		    struct ice_sq_cd *cd); | ||||
| enum ice_status | ||||
| ice_aq_list_caps(struct ice_hw *hw, void *buf, u16 buf_size, u32 *cap_count, | ||||
| 		 enum ice_adminq_opc opc, struct ice_sq_cd *cd); | ||||
| void | ||||
| ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high, | ||||
| 		    u16 link_speeds_bitmap); | ||||
|  | ||||
| @ -397,12 +397,60 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ice_devlink_devcaps_snapshot - Capture snapshot of device capabilities | ||||
|  * @devlink: the devlink instance | ||||
|  * @extack: extended ACK response structure | ||||
|  * @data: on exit points to snapshot data buffer | ||||
|  * | ||||
|  * This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for | ||||
|  * the device-caps devlink region. It captures a snapshot of the device | ||||
|  * capabilities reported by firmware. | ||||
|  * | ||||
|  * @returns zero on success, and updates the data pointer. Returns a non-zero | ||||
|  * error code on failure. | ||||
|  */ | ||||
| static int | ||||
| ice_devlink_devcaps_snapshot(struct devlink *devlink, | ||||
| 			     struct netlink_ext_ack *extack, u8 **data) | ||||
| { | ||||
| 	struct ice_pf *pf = devlink_priv(devlink); | ||||
| 	struct device *dev = ice_pf_to_dev(pf); | ||||
| 	struct ice_hw *hw = &pf->hw; | ||||
| 	enum ice_status status; | ||||
| 	void *devcaps; | ||||
| 
 | ||||
| 	devcaps = vzalloc(ICE_AQ_MAX_BUF_LEN); | ||||
| 	if (!devcaps) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	status = ice_aq_list_caps(hw, devcaps, ICE_AQ_MAX_BUF_LEN, NULL, | ||||
| 				  ice_aqc_opc_list_dev_caps, NULL); | ||||
| 	if (status) { | ||||
| 		dev_dbg(dev, "ice_aq_list_caps: failed to read device capabilities, err %d aq_err %d\n", | ||||
| 			status, hw->adminq.sq_last_status); | ||||
| 		NL_SET_ERR_MSG_MOD(extack, "Failed to read device capabilities"); | ||||
| 		vfree(devcaps); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	*data = (u8 *)devcaps; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct devlink_region_ops ice_nvm_region_ops = { | ||||
| 	.name = "nvm-flash", | ||||
| 	.destructor = vfree, | ||||
| 	.snapshot = ice_devlink_nvm_snapshot, | ||||
| }; | ||||
| 
 | ||||
| static const struct devlink_region_ops ice_devcaps_region_ops = { | ||||
| 	.name = "device-caps", | ||||
| 	.destructor = vfree, | ||||
| 	.snapshot = ice_devlink_devcaps_snapshot, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * ice_devlink_init_regions - Initialize devlink regions | ||||
|  * @pf: the PF device structure | ||||
| @ -424,6 +472,15 @@ void ice_devlink_init_regions(struct ice_pf *pf) | ||||
| 			PTR_ERR(pf->nvm_region)); | ||||
| 		pf->nvm_region = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	pf->devcaps_region = devlink_region_create(devlink, | ||||
| 						   &ice_devcaps_region_ops, 10, | ||||
| 						   ICE_AQ_MAX_BUF_LEN); | ||||
| 	if (IS_ERR(pf->devcaps_region)) { | ||||
| 		dev_err(dev, "failed to create device-caps devlink region, err %ld\n", | ||||
| 			PTR_ERR(pf->devcaps_region)); | ||||
| 		pf->devcaps_region = NULL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| @ -436,4 +493,6 @@ void ice_devlink_destroy_regions(struct ice_pf *pf) | ||||
| { | ||||
| 	if (pf->nvm_region) | ||||
| 		devlink_region_destroy(pf->nvm_region); | ||||
| 	if (pf->devcaps_region) | ||||
| 		devlink_region_destroy(pf->devcaps_region); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user