/** * i40e_ddp_profiles_eq - checks if DDP profiles are the equivalent * @a: new profile info * @b: old profile info * * checks if DDP profiles are the equivalent. * Returns true if profiles are the same.
**/ staticbool i40e_ddp_profiles_eq(struct i40e_profile_info *a, struct i40e_profile_info *b)
{ return a->track_id == b->track_id &&
!memcmp(&a->version, &b->version, sizeof(a->version)) &&
!memcmp(&a->name, &b->name, I40E_DDP_NAME_SIZE);
}
/** * i40e_ddp_does_profile_exist - checks if DDP profile loaded already * @hw: HW data structure * @pinfo: DDP profile information structure * * checks if DDP profile loaded already. * Returns >0 if the profile exists. * Returns 0 if the profile is absent. * Returns <0 if error.
**/ staticint i40e_ddp_does_profile_exist(struct i40e_hw *hw, struct i40e_profile_info *pinfo)
{ struct i40e_ddp_profile_list *profile_list;
u8 buff[I40E_PROFILE_LIST_SIZE]; int status; int i;
status = i40e_aq_get_ddp_list(hw, buff, I40E_PROFILE_LIST_SIZE, 0,
NULL); if (status) return -1;
profile_list = (struct i40e_ddp_profile_list *)buff; for (i = 0; i < profile_list->p_count; i++) { if (i40e_ddp_profiles_eq(pinfo, &profile_list->p_info[i])) return 1;
} return 0;
}
/** * i40e_ddp_profiles_overlap - checks if DDP profiles overlap. * @new: new profile info * @old: old profile info * * checks if DDP profiles overlap. * Returns true if profiles are overlap.
**/ staticbool i40e_ddp_profiles_overlap(struct i40e_profile_info *new, struct i40e_profile_info *old)
{ unsignedint group_id_old = FIELD_GET(0x00FF0000, old->track_id); unsignedint group_id_new = FIELD_GET(0x00FF0000, new->track_id);
/* 0x00 group must be only the first */ if (group_id_new == 0) returntrue; /* 0xFF group is compatible with anything else */ if (group_id_new == 0xFF || group_id_old == 0xFF) returnfalse; /* otherwise only profiles from the same group are compatible*/ return group_id_old != group_id_new;
}
/** * i40e_ddp_does_profile_overlap - checks if DDP overlaps with existing one. * @hw: HW data structure * @pinfo: DDP profile information structure * * checks if DDP profile overlaps with existing one. * Returns >0 if the profile overlaps. * Returns 0 if the profile is ok. * Returns <0 if error.
**/ staticint i40e_ddp_does_profile_overlap(struct i40e_hw *hw, struct i40e_profile_info *pinfo)
{ struct i40e_ddp_profile_list *profile_list;
u8 buff[I40E_PROFILE_LIST_SIZE]; int status; int i;
status = i40e_aq_get_ddp_list(hw, buff, I40E_PROFILE_LIST_SIZE, 0,
NULL); if (status) return -EIO;
profile_list = (struct i40e_ddp_profile_list *)buff; for (i = 0; i < profile_list->p_count; i++) { if (i40e_ddp_profiles_overlap(pinfo,
&profile_list->p_info[i])) return 1;
} return 0;
}
/** * i40e_add_pinfo * @hw: pointer to the hardware structure * @profile: pointer to the profile segment of the package * @profile_info_sec: buffer for information section * @track_id: package tracking id * * Register a profile to the list of loaded profiles.
*/ staticint
i40e_add_pinfo(struct i40e_hw *hw, struct i40e_profile_segment *profile,
u8 *profile_info_sec, u32 track_id)
{ struct i40e_profile_section_header *sec; struct i40e_profile_info *pinfo;
u32 offset = 0, info = 0; int status;
/* Check if profile data already exists*/
istatus = i40e_ddp_does_profile_exist(&pf->hw, &pinfo); if (istatus < 0) {
netdev_err(netdev, "Failed to fetch loaded profiles."); return istatus;
} if (is_add) { if (istatus > 0) {
netdev_err(netdev, "DDP profile already loaded."); return -EINVAL;
}
istatus = i40e_ddp_does_profile_overlap(&pf->hw, &pinfo); if (istatus < 0) {
netdev_err(netdev, "Failed to fetch loaded profiles."); return istatus;
} if (istatus > 0) {
netdev_err(netdev, "DDP profile overlaps with existing one."); return -EINVAL;
}
} else { if (istatus == 0) {
netdev_err(netdev, "DDP profile for deletion does not exist."); return -EINVAL;
}
}
/* Load profile data */ if (is_add) {
status = i40e_write_profile(&pf->hw, profile_hdr, track_id); if (status) { if (status == -ENODEV) {
netdev_err(netdev, "Profile is not supported by the device."); return -EPERM;
}
netdev_err(netdev, "Failed to write DDP profile."); return -EIO;
}
} else {
status = i40e_rollback_profile(&pf->hw, profile_hdr, track_id); if (status) {
netdev_err(netdev, "Failed to remove DDP profile."); return -EIO;
}
}
/* Add/remove profile to/from profile list in FW */ if (is_add) {
status = i40e_add_pinfo(&pf->hw, profile_hdr, profile_info_sec,
track_id); if (status) {
netdev_err(netdev, "Failed to add DDP profile info."); return -EIO;
}
} else {
status = i40e_del_pinfo(&pf->hw, profile_hdr, profile_info_sec,
track_id); if (status) {
netdev_err(netdev, "Failed to restore DDP profile info."); return -EIO;
}
}
return 0;
}
/** * i40e_ddp_restore - restore previously loaded profile and remove from list * @pf: PF data struct * * Restores previously loaded profile stored on the list in driver memory. * After rolling back removes entry from the list.
**/ staticint i40e_ddp_restore(struct i40e_pf *pf)
{ struct i40e_vsi *vsi = i40e_pf_get_main_vsi(pf); struct net_device *netdev = vsi->netdev; struct i40e_ddp_old_profile_list *entry; int status = 0;
/** * i40e_ddp_flash - callback function for ethtool flash feature * @netdev: net device structure * @flash: kernel flash structure * * Ethtool callback function used for loading and unloading DDP profiles.
**/ int i40e_ddp_flash(struct net_device *netdev, struct ethtool_flash *flash)
{ conststruct firmware *ddp_config; struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; int status = 0;
/* Check for valid region first */ if (flash->region != I40_DDP_FLASH_REGION) {
netdev_err(netdev, "Requested firmware region is not recognized by this driver."); return -EINVAL;
} if (pf->hw.bus.func != 0) {
netdev_err(netdev, "Any DDP operation is allowed only on Phy0 NIC interface"); return -EINVAL;
}
/* If the user supplied "-" instead of file name rollback previously * stored profile.
*/ if (strncmp(flash->data, "-", 2) != 0) { struct i40e_ddp_old_profile_list *list_entry; char profile_name[sizeof(I40E_DDP_PROFILE_PATH)
+ I40E_DDP_PROFILE_NAME_MAX];
status = i40e_ddp_load(netdev, ddp_config->data,
ddp_config->size, true);
if (!status) {
list_entry =
kzalloc(sizeof(struct i40e_ddp_old_profile_list) +
ddp_config->size, GFP_KERNEL); if (!list_entry) {
netdev_info(netdev, "Failed to allocate memory for previous DDP profile data.");
netdev_info(netdev, "New profile loaded but roll-back will be impossible.");
} else {
memcpy(list_entry->old_ddp_buf,
ddp_config->data, ddp_config->size);
list_entry->old_ddp_size = ddp_config->size;
list_add(&list_entry->list, &pf->ddp_old_prof);
}
}
release_firmware(ddp_config);
} else { if (!list_empty(&pf->ddp_old_prof)) {
status = i40e_ddp_restore(pf);
} else {
netdev_warn(netdev, "There is no DDP profile to restore.");
status = -ENOENT;
}
} return status;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.