[next,S70,02/12] i40e: DCR 287 new AQ commands

Submitted by alice michael on April 13, 2017, 8:45 a.m.

Details

Message ID 20170413084555.6962-2-alice.michael@intel.com
State Accepted
Delegated to: Jeff Kirsher
Headers show

Commit Message

alice michael April 13, 2017, 8:45 a.m.
From: Jingjing Wu <jingjing.wu@intel.com>

Add admin queue functions for Pipeline Personalization Profile AQ
commands defined in DCR 287:
 - Write Recipe Command buffer (Opcode: 0x0270)
 - Get Applied Profiles list (Opcode: 0x0271)

Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
Change-ID: I558b4145364140f624013af48d4bbf79d21ebb0d
---
 drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |  34 ++++
 drivers/net/ethernet/intel/i40e/i40e_common.c      | 212 +++++++++++++++++++++
 drivers/net/ethernet/intel/i40e/i40e_prototype.h   |  17 ++
 drivers/net/ethernet/intel/i40e/i40e_type.h        |  80 ++++++++
 .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |  34 ++++
 drivers/net/ethernet/intel/i40evf/i40e_common.c    | 212 +++++++++++++++++++++
 drivers/net/ethernet/intel/i40evf/i40e_prototype.h |  17 ++
 drivers/net/ethernet/intel/i40evf/i40e_type.h      |  80 ++++++++
 8 files changed, 686 insertions(+)

Comments

Shannon Nelson April 14, 2017, 7:17 p.m.
On 4/13/2017 1:45 AM, Alice Michael wrote:
> From: Jingjing Wu <jingjing.wu@intel.com>
>

The DCR is an internal numbering and means nothing to the rest of the 
world in the Subject line or the commit message.

More information would be good to describe this new feature - what is 
it, how does the typical user get to it.

> Add admin queue functions for Pipeline Personalization Profile AQ
> commands defined in DCR 287:
>  - Write Recipe Command buffer (Opcode: 0x0270)
>  - Get Applied Profiles list (Opcode: 0x0271)
>
> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
> Change-ID: I558b4145364140f624013af48d4bbf79d21ebb0d
> ---
>  drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |  34 ++++
>  drivers/net/ethernet/intel/i40e/i40e_common.c      | 212 +++++++++++++++++++++
>  drivers/net/ethernet/intel/i40e/i40e_prototype.h   |  17 ++
>  drivers/net/ethernet/intel/i40e/i40e_type.h        |  80 ++++++++
>  .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |  34 ++++
>  drivers/net/ethernet/intel/i40evf/i40e_common.c    | 212 +++++++++++++++++++++
>  drivers/net/ethernet/intel/i40evf/i40e_prototype.h |  17 ++
>  drivers/net/ethernet/intel/i40evf/i40e_type.h      |  80 ++++++++
>  8 files changed, 686 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> index 251074c..5eb0411 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> @@ -190,6 +190,10 @@ enum i40e_admin_queue_opc {
>  	i40e_aqc_opc_add_mirror_rule	= 0x0260,
>  	i40e_aqc_opc_delete_mirror_rule	= 0x0261,
>
> +	/* Pipeline Personalization Profile */
> +	i40e_aqc_opc_write_personalization_profile	= 0x0270,
> +	i40e_aqc_opc_get_personalization_profile_list	= 0x0271,
> +

No version bump for the new API?

>  	/* DCB commands */
>  	i40e_aqc_opc_dcb_ignore_pfc	= 0x0301,
>  	i40e_aqc_opc_dcb_updated	= 0x0302,
> @@ -1431,6 +1435,36 @@ struct i40e_aqc_add_delete_mirror_rule_completion {
>
>  I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion);
>
> +/* Pipeline Personalization Profile */
> +struct i40e_aqc_write_personalization_profile {
> +	u8      flags;
> +	u8      reserved[3];
> +	__le32  profile_track_id;
> +	__le32  addr_high;
> +	__le32  addr_low;
> +};
> +
> +I40E_CHECK_CMD_LENGTH(i40e_aqc_write_personalization_profile);
> +
> +struct i40e_aqc_write_ppp_resp {
> +	__le32 error_offset;
> +	__le32 error_info;
> +	__le32 addr_high;
> +	__le32 addr_low;
> +};
> +
> +struct i40e_aqc_get_applied_profiles {
> +	u8      flags;
> +#define I40E_AQC_GET_PPP_GET_CONF	0x1
> +#define I40E_AQC_GET_PPP_GET_RDPU_CONF	0x2
> +	u8      rsv[3];
> +	__le32  reserved;
> +	__le32  addr_high;
> +	__le32  addr_low;
> +};
> +
> +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_applied_profiles);
> +
>  /* DCB 0x03xx*/
>
>  /* PFC Ignore (direct 0x0301)
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
> index f9db95a..72d1793 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
> @@ -5042,3 +5042,215 @@ void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
>  	if (status || use_register)
>  		wr32(hw, reg_addr, reg_val);
>  }
> +
> +/**
> + * i40e_aq_write_ppp - Write pipeline personalization profile (ppp)
> + * @hw: pointer to the hw struct
> + * @buff: command buffer (size in bytes = buff_size)
> + * @buff_size: buffer size in bytes
> + * @track_id: package tracking id
> + * @error_offset: returns error offset
> + * @error_info: returns error information
> + * @cmd_details: pointer to command details structure or NULL
> + **/
> +enum
> +i40e_status_code i40e_aq_write_ppp(struct i40e_hw *hw, void *buff,
> +				   u16 buff_size, u32 track_id,
> +				   u32 *error_offset, u32 *error_info,
> +				   struct i40e_asq_cmd_details *cmd_details)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_write_personalization_profile *cmd =
> +		(struct i40e_aqc_write_personalization_profile *)
> +		&desc.params.raw;
> +	struct i40e_aqc_write_ppp_resp *resp;
> +	i40e_status status;
> +
> +	i40e_fill_default_direct_cmd_desc(&desc,
> +					  i40e_aqc_opc_write_personalization_profile);
> +
> +	desc.flags |= cpu_to_le16(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD);
> +	if (buff_size > I40E_AQ_LARGE_BUF)
> +		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
> +
> +	desc.datalen = cpu_to_le16(buff_size);
> +
> +	cmd->profile_track_id = cpu_to_le32(track_id);
> +
> +	status = i40e_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
> +	if (!status) {
> +		resp = (struct i40e_aqc_write_ppp_resp *)&desc.params.raw;
> +		if (error_offset)
> +			*error_offset = le32_to_cpu(resp->error_offset);
> +		if (error_info)
> +			*error_info = le32_to_cpu(resp->error_info);
> +	}
> +
> +	return status;
> +}
> +
> +/**
> + * i40e_aq_get_ppp_list - Read pipeline personalization profile (ppp)
> + * @hw: pointer to the hw struct
> + * @buff: command buffer (size in bytes = buff_size)
> + * @buff_size: buffer size in bytes
> + * @cmd_details: pointer to command details structure or NULL
> + **/
> +enum
> +i40e_status_code i40e_aq_get_ppp_list(struct i40e_hw *hw, void *buff,
> +				      u16 buff_size, u8 flags,
> +				       struct i40e_asq_cmd_details *cmd_details)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_get_applied_profiles *cmd =
> +		(struct i40e_aqc_get_applied_profiles *)&desc.params.raw;
> +	i40e_status status;
> +
> +	i40e_fill_default_direct_cmd_desc(&desc,
> +					  i40e_aqc_opc_get_personalization_profile_list);
> +
> +	desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
> +	if (buff_size > I40E_AQ_LARGE_BUF)
> +		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
> +	desc.datalen = cpu_to_le16(buff_size);
> +
> +	cmd->flags = flags;
> +
> +	status = i40e_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
> +
> +	return status;
> +}
> +
> +/**
> + * i40e_find_segment_in_package
> + * @segment_type: the segment type to search for (i.e., SEGMENT_TYPE_I40E)
> + * @pkg_hdr: pointer to the package header to be searched
> + *
> + * This function searches a package file for a particular segment type. On
> + * success it returns a pointer to the segment header, otherwise it will
> + * return NULL.
> + **/
> +struct i40e_generic_seg_header *
> +i40e_find_segment_in_package(u32 segment_type,
> +			     struct i40e_package_header *pkg_hdr)
> +{
> +	struct i40e_generic_seg_header *segment;
> +	u32 i;
> +
> +	/* Search all package segments for the requested segment type */
> +	for (i = 0; i < pkg_hdr->segment_count; i++) {
> +		segment =
> +			(struct i40e_generic_seg_header *)((u8 *)pkg_hdr +
> +			 pkg_hdr->segment_offset[i]);
> +
> +		if (segment->type == segment_type)
> +			return segment;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * i40e_write_profile
> + * @hw: pointer to the hardware structure
> + * @profile: pointer to the profile segment of the package to be downloaded
> + * @track_id: package tracking id
> + *
> + * Handles the download of a complete package.
> + */
> +enum i40e_status_code
> +i40e_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
> +		   u32 track_id)
> +{
> +	i40e_status status = 0;
> +	struct i40e_section_table *sec_tbl;
> +	struct i40e_profile_section_header *sec = NULL;
> +	u32 dev_cnt;
> +	u32 vendor_dev_id;
> +	u32 *nvm;
> +	u32 section_size = 0;
> +	u32 offset = 0, info = 0;
> +	u32 i;
> +
> +	if (!track_id) {
> +		i40e_debug(hw, I40E_DEBUG_PACKAGE, "Track_id can't be 0.");

I believe there should be newlines in all the i40e_debug messages.

> +		return I40E_NOT_SUPPORTED;
> +	}
> +
> +	dev_cnt = profile->device_table_count;
> +
> +	for (i = 0; i < dev_cnt; i++) {
> +		vendor_dev_id = profile->device_table[i].vendor_dev_id;
> +		if ((vendor_dev_id >> 16) == PCI_VENDOR_ID_INTEL)
> +			if (hw->device_id == (vendor_dev_id & 0xFFFF))
> +				break;
> +	}
> +	if (i == dev_cnt) {
> +		i40e_debug(hw, I40E_DEBUG_PACKAGE, "Device doesn't support PPP");
> +		return I40E_ERR_DEVICE_NOT_SUPPORTED;
> +	}
> +
> +	nvm = (u32 *)&profile->device_table[dev_cnt];
> +	sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1];
> +
> +	for (i = 0; i < sec_tbl->section_count; i++) {
> +		sec = (struct i40e_profile_section_header *)((u8 *)profile +
> +					     sec_tbl->section_offset[i]);
> +
> +		/* Skip 'AQ', 'note' and 'name' sections */
> +		if (sec->section.type != SECTION_TYPE_MMIO)
> +			continue;
> +
> +		section_size = sec->section.size +
> +			sizeof(struct i40e_profile_section_header);
> +
> +		/* Write profile */
> +		status = i40e_aq_write_ppp(hw, (void *)sec, (u16)section_size,
> +					   track_id, &offset, &info, NULL);
> +		if (status) {
> +			i40e_debug(hw, I40E_DEBUG_PACKAGE,
> +				   "Failed to write profile: offset %d, info %d",
> +				   offset, info);
> +			break;
> +		}
> +	}
> +	return status;
> +}
> +
> +/**
> + * i40e_add_pinfo_to_list
> + * @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.
> + */
> +enum i40e_status_code
> +i40e_add_pinfo_to_list(struct i40e_hw *hw,
> +		       struct i40e_profile_segment *profile,
> +		       u8 *profile_info_sec, u32 track_id)
> +{
> +	i40e_status status = 0;
> +	struct i40e_profile_section_header *sec = NULL;
> +	struct i40e_profile_info *pinfo;
> +	u32 offset = 0, info = 0;
> +
> +	sec = (struct i40e_profile_section_header *)profile_info_sec;
> +	sec->tbl_size = 1;
> +	sec->data_end = sizeof(struct i40e_profile_section_header) +
> +			sizeof(struct i40e_profile_info);
> +	sec->section.type = SECTION_TYPE_INFO;
> +	sec->section.offset = sizeof(struct i40e_profile_section_header);
> +	sec->section.size = sizeof(struct i40e_profile_info);
> +	pinfo = (struct i40e_profile_info *)(profile_info_sec +
> +					     sec->section.offset);
> +	pinfo->track_id = track_id;
> +	pinfo->version = profile->version;
> +	pinfo->op = I40E_PPP_ADD_TRACKID;
> +	memcpy(pinfo->name, profile->name, I40E_PPP_NAME_SIZE);
> +
> +	status = i40e_aq_write_ppp(hw, (void *)sec, sec->data_end,
> +				   track_id, &offset, &info, NULL);
> +	return status;
> +}
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> index dfc5e59..611bbc7 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> @@ -377,4 +377,21 @@ i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page, u16 reg,
>  u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
>  i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
>  				    u32 time, u32 interval);
> +i40e_status i40e_aq_write_ppp(struct i40e_hw *hw, void *buff,
> +			      u16 buff_size, u32 track_id,
> +				u32 *error_offset, u32 *error_info,
> +				struct i40e_asq_cmd_details *cmd_details);
> +i40e_status i40e_aq_get_ppp_list(struct i40e_hw *hw, void *buff,
> +				 u16 buff_size, u8 flags,
> +				   struct i40e_asq_cmd_details *cmd_details);
> +struct i40e_generic_seg_header *
> +i40e_find_segment_in_package(u32 segment_type,
> +			     struct i40e_package_header *pkg_header);
> +enum i40e_status_code
> +i40e_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *i40e_seg,
> +		   u32 track_id);
> +enum i40e_status_code
> +i40e_add_pinfo_to_list(struct i40e_hw *hw,
> +		       struct i40e_profile_segment *profile,
> +		       u8 *profile_info_sec, u32 track_id);
>  #endif /* _I40E_PROTOTYPE_H_ */
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
> index 08364a4..f235899 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
> @@ -78,6 +78,7 @@ enum i40e_debug_mask {
>  	I40E_DEBUG_DCB			= 0x00000400,
>  	I40E_DEBUG_DIAG			= 0x00000800,
>  	I40E_DEBUG_FD			= 0x00001000,
> +	I40E_DEBUG_PACKAGE		= 0x00002000,
>  	I40E_DEBUG_IWARP		= 0x00F00000,
>  	I40E_DEBUG_AQ_MESSAGE		= 0x01000000,
>  	I40E_DEBUG_AQ_DESCRIPTOR	= 0x02000000,
> @@ -1465,4 +1466,83 @@ struct i40e_lldp_variables {
>  #define I40E_FLEX_56_MASK		(0x1ULL << I40E_FLEX_56_SHIFT)
>  #define I40E_FLEX_57_SHIFT		6
>  #define I40E_FLEX_57_MASK		(0x1ULL << I40E_FLEX_57_SHIFT)
> +
> +/* Version format for PPP */
> +struct i40e_ppp_version {
> +	u8 major;
> +	u8 minor;
> +	u8 update;
> +	u8 draft;
> +};
> +
> +#define I40E_PPP_NAME_SIZE	32
> +
> +/* Package header */
> +struct i40e_package_header {
> +	struct i40e_ppp_version version;
> +	u32 segment_count;
> +	u32 segment_offset[1];
> +};
> +
> +/* Generic segment header */
> +struct i40e_generic_seg_header {
> +#define SEGMENT_TYPE_METADATA	0x00000001
> +#define SEGMENT_TYPE_NOTES	0x00000002
> +#define SEGMENT_TYPE_I40E	0x00000011
> +#define SEGMENT_TYPE_X722	0x00000012
> +	u32 type;
> +	struct i40e_ppp_version version;
> +	u32 size;
> +	char name[I40E_PPP_NAME_SIZE];
> +};
> +
> +struct i40e_metadata_segment {
> +	struct i40e_generic_seg_header header;
> +	struct i40e_ppp_version version;
> +	u32 track_id;
> +	char     name[I40E_PPP_NAME_SIZE];
> +};
> +
> +struct i40e_device_id_entry {
> +	u32 vendor_dev_id;
> +	u32 sub_vendor_dev_id;
> +};
> +
> +struct i40e_profile_segment {
> +	struct i40e_generic_seg_header header;
> +	struct i40e_ppp_version version;
> +	char name[I40E_PPP_NAME_SIZE];
> +	u32 device_table_count;
> +	struct i40e_device_id_entry device_table[1];
> +};
> +
> +struct i40e_section_table {
> +	u32 section_count;
> +	u32 section_offset[1];
> +};
> +
> +struct i40e_profile_section_header {
> +	u16 tbl_size;
> +	u16 data_end;
> +	struct {
> +#define SECTION_TYPE_INFO	0x00000010
> +#define SECTION_TYPE_MMIO	0x00000800
> +#define SECTION_TYPE_AQ		0x00000801
> +#define SECTION_TYPE_NOTE	0x80000000
> +#define SECTION_TYPE_NAME	0x80000001
> +		u32 type;
> +		u32 offset;
> +		u32 size;
> +	} section;
> +};
> +
> +struct i40e_profile_info {
> +	u32 track_id;
> +	struct i40e_ppp_version version;
> +	u8 op;
> +#define I40E_PPP_ADD_TRACKID		0x01
> +#define I40E_PPP_REMOVE_TRACKID	0x02
> +	u8 reserved[7];
> +	u8 name[I40E_PPP_NAME_SIZE];
> +};
>  #endif /* _I40E_TYPE_H_ */
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> index c28cb8f..91d8786 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> @@ -190,6 +190,10 @@ enum i40e_admin_queue_opc {
>  	i40e_aqc_opc_add_mirror_rule	= 0x0260,
>  	i40e_aqc_opc_delete_mirror_rule	= 0x0261,
>
> +	/* Pipeline Personalization Profile */
> +	i40e_aqc_opc_write_personalization_profile	= 0x0270,
> +	i40e_aqc_opc_get_personalization_profile_list	= 0x0271,
> +
>  	/* DCB commands */
>  	i40e_aqc_opc_dcb_ignore_pfc	= 0x0301,
>  	i40e_aqc_opc_dcb_updated	= 0x0302,
> @@ -1426,6 +1430,36 @@ struct i40e_aqc_add_delete_mirror_rule_completion {
>
>  I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion);
>
> +/* Pipeline Personalization Profile */
> +struct i40e_aqc_write_personalization_profile {
> +	u8      flags;
> +	u8      reserved[3];
> +	__le32  profile_track_id;
> +	__le32  addr_high;
> +	__le32  addr_low;
> +};
> +
> +I40E_CHECK_CMD_LENGTH(i40e_aqc_write_personalization_profile);
> +
> +struct i40e_aqc_write_ppp_resp {
> +	__le32 error_offset;
> +	__le32 error_info;
> +	__le32 addr_high;
> +	__le32 addr_low;
> +};
> +
> +struct i40e_aqc_get_applied_profiles {
> +	u8      flags;
> +#define I40E_AQC_GET_PPP_GET_CONF	0x1
> +#define I40E_AQC_GET_PPP_GET_RDPU_CONF	0x2
> +	u8      rsv[3];
> +	__le32  reserved;
> +	__le32  addr_high;
> +	__le32  addr_low;
> +};
> +
> +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_applied_profiles);
> +
>  /* DCB 0x03xx*/
>
>  /* PFC Ignore (direct 0x0301)
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c
> index 626fbf1..606f5f1 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c
> @@ -1131,3 +1131,215 @@ i40e_status i40e_vf_reset(struct i40e_hw *hw)
>  	return i40e_aq_send_msg_to_pf(hw, I40E_VIRTCHNL_OP_RESET_VF,
>  				      0, NULL, 0, NULL);
>  }
> +
> +/**
> + * i40evf_aq_write_ppp - Write pipeline personalization profile (ppp)
> + * @hw: pointer to the hw struct
> + * @buff: command buffer (size in bytes = buff_size)
> + * @buff_size: buffer size in bytes
> + * @track_id: package tracking id
> + * @error_offset: returns error offset
> + * @error_info: returns error information
> + * @cmd_details: pointer to command details structure or NULL
> + **/
> +enum
> +i40e_status_code i40evf_aq_write_ppp(struct i40e_hw *hw, void *buff,
> +				     u16 buff_size, u32 track_id,
> +				   u32 *error_offset, u32 *error_info,
> +				   struct i40e_asq_cmd_details *cmd_details)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_write_personalization_profile *cmd =
> +		(struct i40e_aqc_write_personalization_profile *)
> +		&desc.params.raw;
> +	struct i40e_aqc_write_ppp_resp *resp;
> +	i40e_status status;
> +
> +	i40evf_fill_default_direct_cmd_desc(&desc,
> +					    i40e_aqc_opc_write_personalization_profile);
> +
> +	desc.flags |= cpu_to_le16(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD);
> +	if (buff_size > I40E_AQ_LARGE_BUF)
> +		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
> +
> +	desc.datalen = cpu_to_le16(buff_size);
> +
> +	cmd->profile_track_id = cpu_to_le32(track_id);
> +
> +	status = i40evf_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
> +	if (!status) {
> +		resp = (struct i40e_aqc_write_ppp_resp *)&desc.params.raw;
> +		if (error_offset)
> +			*error_offset = le32_to_cpu(resp->error_offset);
> +		if (error_info)
> +			*error_info = le32_to_cpu(resp->error_info);
> +	}
> +
> +	return status;
> +}
> +
> +/**
> + * i40evf_aq_get_ppp_list - Read pipeline personalization profile (ppp)
> + * @hw: pointer to the hw struct
> + * @buff: command buffer (size in bytes = buff_size)
> + * @buff_size: buffer size in bytes
> + * @cmd_details: pointer to command details structure or NULL
> + **/
> +enum
> +i40e_status_code i40evf_aq_get_ppp_list(struct i40e_hw *hw, void *buff,
> +					u16 buff_size, u8 flags,
> +				      struct i40e_asq_cmd_details *cmd_details)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_get_applied_profiles *cmd =
> +		(struct i40e_aqc_get_applied_profiles *)&desc.params.raw;
> +	i40e_status status;
> +
> +	i40evf_fill_default_direct_cmd_desc(&desc,
> +					    i40e_aqc_opc_get_personalization_profile_list);
> +
> +	desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
> +	if (buff_size > I40E_AQ_LARGE_BUF)
> +		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
> +	desc.datalen = cpu_to_le16(buff_size);
> +
> +	cmd->flags = flags;
> +
> +	status = i40evf_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
> +
> +	return status;
> +}
> +
> +/**
> + * i40evf_find_segment_in_package
> + * @segment_type: the segment type to search for (i.e., SEGMENT_TYPE_I40E)
> + * @pkg_hdr: pointer to the package header to be searched
> + *
> + * This function searches a package file for a particular segment type. On
> + * success it returns a pointer to the segment header, otherwise it will
> + * return NULL.
> + **/
> +struct i40e_generic_seg_header *
> +i40evf_find_segment_in_package(u32 segment_type,
> +			       struct i40e_package_header *pkg_hdr)
> +{
> +	struct i40e_generic_seg_header *segment;
> +	u32 i;
> +
> +	/* Search all package segments for the requested segment type */
> +	for (i = 0; i < pkg_hdr->segment_count; i++) {
> +		segment =
> +			(struct i40e_generic_seg_header *)((u8 *)pkg_hdr +
> +			 pkg_hdr->segment_offset[i]);
> +
> +		if (segment->type == segment_type)
> +			return segment;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * i40evf_write_profile
> + * @hw: pointer to the hardware structure
> + * @profile: pointer to the profile segment of the package to be downloaded
> + * @track_id: package tracking id
> + *
> + * Handles the download of a complete package.
> + */
> +enum i40e_status_code
> +i40evf_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
> +		     u32 track_id)
> +{
> +	i40e_status status = 0;
> +	struct i40e_section_table *sec_tbl;
> +	struct i40e_profile_section_header *sec = NULL;
> +	u32 dev_cnt;
> +	u32 vendor_dev_id;
> +	u32 *nvm;
> +	u32 section_size = 0;
> +	u32 offset = 0, info = 0;
> +	u32 i;
> +
> +	if (!track_id) {
> +		i40e_debug(hw, I40E_DEBUG_PACKAGE, "Track_id can't be 0.");
> +		return I40E_NOT_SUPPORTED;
> +	}
> +
> +	dev_cnt = profile->device_table_count;
> +
> +	for (i = 0; i < dev_cnt; i++) {
> +		vendor_dev_id = profile->device_table[i].vendor_dev_id;
> +		if ((vendor_dev_id >> 16) == PCI_VENDOR_ID_INTEL)
> +			if (hw->device_id == (vendor_dev_id & 0xFFFF))
> +				break;
> +	}
> +	if (i == dev_cnt) {
> +		i40e_debug(hw, I40E_DEBUG_PACKAGE, "Device doesn't support PPP");
> +		return I40E_ERR_DEVICE_NOT_SUPPORTED;
> +	}
> +
> +	nvm = (u32 *)&profile->device_table[dev_cnt];
> +	sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1];
> +
> +	for (i = 0; i < sec_tbl->section_count; i++) {
> +		sec = (struct i40e_profile_section_header *)((u8 *)profile +
> +					     sec_tbl->section_offset[i]);
> +
> +		/* Skip 'AQ', 'note' and 'name' sections */
> +		if (sec->section.type != SECTION_TYPE_MMIO)
> +			continue;
> +
> +		section_size = sec->section.size +
> +			sizeof(struct i40e_profile_section_header);
> +
> +		/* Write profile */
> +		status = i40evf_aq_write_ppp(hw, (void *)sec, (u16)section_size,
> +					     track_id, &offset, &info, NULL);
> +		if (status) {
> +			i40e_debug(hw, I40E_DEBUG_PACKAGE,
> +				   "Failed to write profile: offset %d, info %d",
> +				   offset, info);
> +			break;
> +		}
> +	}
> +	return status;
> +}
> +
> +/**
> + * i40evf_add_pinfo_to_list
> + * @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.
> + */
> +enum i40e_status_code
> +i40evf_add_pinfo_to_list(struct i40e_hw *hw,
> +			 struct i40e_profile_segment *profile,
> +			  u8 *profile_info_sec, u32 track_id)
> +{
> +	i40e_status status = 0;
> +	struct i40e_profile_section_header *sec = NULL;
> +	struct i40e_profile_info *pinfo;
> +	u32 offset = 0, info = 0;
> +
> +	sec = (struct i40e_profile_section_header *)profile_info_sec;
> +	sec->tbl_size = 1;
> +	sec->data_end = sizeof(struct i40e_profile_section_header) +
> +			sizeof(struct i40e_profile_info);
> +	sec->section.type = SECTION_TYPE_INFO;
> +	sec->section.offset = sizeof(struct i40e_profile_section_header);
> +	sec->section.size = sizeof(struct i40e_profile_info);
> +	pinfo = (struct i40e_profile_info *)(profile_info_sec +
> +					     sec->section.offset);
> +	pinfo->track_id = track_id;
> +	pinfo->version = profile->version;
> +	pinfo->op = I40E_PPP_ADD_TRACKID;
> +	memcpy(pinfo->name, profile->name, I40E_PPP_NAME_SIZE);
> +
> +	status = i40evf_aq_write_ppp(hw, (void *)sec, sec->data_end,
> +				     track_id, &offset, &info, NULL);
> +	return status;
> +}
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
> index ba6c6bd..329ce2b 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
> @@ -122,4 +122,21 @@ i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page, u16 reg,
>  u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
>  i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
>  				    u32 time, u32 interval);
> +i40e_status i40evf_aq_write_ppp(struct i40e_hw *hw, void *buff,
> +				u16 buff_size, u32 track_id,
> +				u32 *error_offset, u32 *error_info,
> +				struct i40e_asq_cmd_details *cmd_details);
> +i40e_status i40evf_aq_get_ppp_list(struct i40e_hw *hw, void *buff,
> +				   u16 buff_size, u8 flags,
> +				   struct i40e_asq_cmd_details *cmd_details);
> +struct i40e_generic_seg_header *
> +i40evf_find_segment_in_package(u32 segment_type,
> +			       struct i40e_package_header *pkg_header);
> +enum i40e_status_code
> +i40evf_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *i40e_seg,
> +		     u32 track_id);
> +enum i40e_status_code
> +i40evf_add_pinfo_to_list(struct i40e_hw *hw,
> +			 struct i40e_profile_segment *profile,
> +			  u8 *profile_info_sec, u32 track_id);
>  #endif /* _I40E_PROTOTYPE_H_ */
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
> index 16bb880..44bb9f0 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
> @@ -78,6 +78,7 @@ enum i40e_debug_mask {
>  	I40E_DEBUG_DCB			= 0x00000400,
>  	I40E_DEBUG_DIAG			= 0x00000800,
>  	I40E_DEBUG_FD			= 0x00001000,
> +	I40E_DEBUG_PACKAGE		= 0x00002000,
>
>  	I40E_DEBUG_AQ_MESSAGE		= 0x01000000,
>  	I40E_DEBUG_AQ_DESCRIPTOR	= 0x02000000,
> @@ -1396,4 +1397,83 @@ enum i40e_reset_type {
>  #define I40E_FD_INSET_FLEX_WORD57_SHIFT		10
>  #define I40E_FD_INSET_FLEX_WORD57_MASK		(0x1ULL << \
>  					I40E_FD_INSET_FLEX_WORD57_SHIFT)
> +
> +/* Version format for PPP */
> +struct i40e_ppp_version {
> +	u8 major;
> +	u8 minor;
> +	u8 update;
> +	u8 draft;
> +};
> +
> +#define I40E_PPP_NAME_SIZE	32
> +
> +/* Package header */
> +struct i40e_package_header {
> +	struct i40e_ppp_version version;
> +	u32 segment_count;
> +	u32 segment_offset[1];
> +};
> +
> +/* Generic segment header */
> +struct i40e_generic_seg_header {
> +#define SEGMENT_TYPE_METADATA	0x00000001
> +#define SEGMENT_TYPE_NOTES	0x00000002
> +#define SEGMENT_TYPE_I40E	0x00000011
> +#define SEGMENT_TYPE_X722	0x00000012
> +	u32 type;
> +	struct i40e_ppp_version version;
> +	u32 size;
> +	char name[I40E_PPP_NAME_SIZE];
> +};
> +
> +struct i40e_metadata_segment {
> +	struct i40e_generic_seg_header header;
> +	struct i40e_ppp_version version;
> +	u32 track_id;
> +	char     name[I40E_PPP_NAME_SIZE];
> +};
> +
> +struct i40e_device_id_entry {
> +	u32 vendor_dev_id;
> +	u32 sub_vendor_dev_id;
> +};
> +
> +struct i40e_profile_segment {
> +	struct i40e_generic_seg_header header;
> +	struct i40e_ppp_version version;
> +	char name[I40E_PPP_NAME_SIZE];
> +	u32 device_table_count;
> +	struct i40e_device_id_entry device_table[1];
> +};
> +
> +struct i40e_section_table {
> +	u32 section_count;
> +	u32 section_offset[1];
> +};
> +
> +struct i40e_profile_section_header {
> +	u16 tbl_size;
> +	u16 data_end;
> +	struct {
> +#define SECTION_TYPE_INFO	0x00000010
> +#define SECTION_TYPE_MMIO	0x00000800
> +#define SECTION_TYPE_AQ		0x00000801
> +#define SECTION_TYPE_NOTE	0x80000000
> +#define SECTION_TYPE_NAME	0x80000001
> +		u32 type;
> +		u32 offset;
> +		u32 size;
> +	} section;
> +};
> +
> +struct i40e_profile_info {
> +	u32 track_id;
> +	struct i40e_ppp_version version;
> +	u8 op;
> +#define I40E_PPP_ADD_TRACKID		0x01
> +#define I40E_PPP_REMOVE_TRACKID	0x02
> +	u8 reserved[7];
> +	u8 name[I40E_PPP_NAME_SIZE];
> +};
>  #endif /* _I40E_TYPE_H_ */
>
Bowers, AndrewX April 17, 2017, 5:34 p.m.
> -----Original Message-----
> From: Intel-wired-lan [mailto:intel-wired-lan-bounces@lists.osuosl.org] On
> Behalf Of Alice Michael
> Sent: Thursday, April 13, 2017 1:46 AM
> To: Michael, Alice <alice.michael@intel.com>; intel-wired-
> lan@lists.osuosl.org
> Cc: Wu, Jingjing <jingjing.wu@intel.com>
> Subject: [Intel-wired-lan] [next PATCH S70 02/12] i40e: DCR 287 new AQ
> commands
> 
> From: Jingjing Wu <jingjing.wu@intel.com>
> 
> Add admin queue functions for Pipeline Personalization Profile AQ
> commands defined in DCR 287:
>  - Write Recipe Command buffer (Opcode: 0x0270)
>  - Get Applied Profiles list (Opcode: 0x0271)
> 
> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
> Change-ID: I558b4145364140f624013af48d4bbf79d21ebb0d
> ---
>  drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |  34 ++++
>  drivers/net/ethernet/intel/i40e/i40e_common.c      | 212
> +++++++++++++++++++++
>  drivers/net/ethernet/intel/i40e/i40e_prototype.h   |  17 ++
>  drivers/net/ethernet/intel/i40e/i40e_type.h        |  80 ++++++++
>  .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |  34 ++++
>  drivers/net/ethernet/intel/i40evf/i40e_common.c    | 212
> +++++++++++++++++++++
>  drivers/net/ethernet/intel/i40evf/i40e_prototype.h |  17 ++
>  drivers/net/ethernet/intel/i40evf/i40e_type.h      |  80 ++++++++
>  8 files changed, 686 insertions(+)

Tested-by: Andrew Bowers <andrewx.bowers@intel.com>

Patch hide | download patch | download mbox

diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
index 251074c..5eb0411 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
@@ -190,6 +190,10 @@  enum i40e_admin_queue_opc {
 	i40e_aqc_opc_add_mirror_rule	= 0x0260,
 	i40e_aqc_opc_delete_mirror_rule	= 0x0261,
 
+	/* Pipeline Personalization Profile */
+	i40e_aqc_opc_write_personalization_profile	= 0x0270,
+	i40e_aqc_opc_get_personalization_profile_list	= 0x0271,
+
 	/* DCB commands */
 	i40e_aqc_opc_dcb_ignore_pfc	= 0x0301,
 	i40e_aqc_opc_dcb_updated	= 0x0302,
@@ -1431,6 +1435,36 @@  struct i40e_aqc_add_delete_mirror_rule_completion {
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion);
 
+/* Pipeline Personalization Profile */
+struct i40e_aqc_write_personalization_profile {
+	u8      flags;
+	u8      reserved[3];
+	__le32  profile_track_id;
+	__le32  addr_high;
+	__le32  addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_write_personalization_profile);
+
+struct i40e_aqc_write_ppp_resp {
+	__le32 error_offset;
+	__le32 error_info;
+	__le32 addr_high;
+	__le32 addr_low;
+};
+
+struct i40e_aqc_get_applied_profiles {
+	u8      flags;
+#define I40E_AQC_GET_PPP_GET_CONF	0x1
+#define I40E_AQC_GET_PPP_GET_RDPU_CONF	0x2
+	u8      rsv[3];
+	__le32  reserved;
+	__le32  addr_high;
+	__le32  addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_applied_profiles);
+
 /* DCB 0x03xx*/
 
 /* PFC Ignore (direct 0x0301)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index f9db95a..72d1793 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -5042,3 +5042,215 @@  void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
 	if (status || use_register)
 		wr32(hw, reg_addr, reg_val);
 }
+
+/**
+ * i40e_aq_write_ppp - Write pipeline personalization profile (ppp)
+ * @hw: pointer to the hw struct
+ * @buff: command buffer (size in bytes = buff_size)
+ * @buff_size: buffer size in bytes
+ * @track_id: package tracking id
+ * @error_offset: returns error offset
+ * @error_info: returns error information
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+enum
+i40e_status_code i40e_aq_write_ppp(struct i40e_hw *hw, void *buff,
+				   u16 buff_size, u32 track_id,
+				   u32 *error_offset, u32 *error_info,
+				   struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_write_personalization_profile *cmd =
+		(struct i40e_aqc_write_personalization_profile *)
+		&desc.params.raw;
+	struct i40e_aqc_write_ppp_resp *resp;
+	i40e_status status;
+
+	i40e_fill_default_direct_cmd_desc(&desc,
+					  i40e_aqc_opc_write_personalization_profile);
+
+	desc.flags |= cpu_to_le16(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD);
+	if (buff_size > I40E_AQ_LARGE_BUF)
+		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+	desc.datalen = cpu_to_le16(buff_size);
+
+	cmd->profile_track_id = cpu_to_le32(track_id);
+
+	status = i40e_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
+	if (!status) {
+		resp = (struct i40e_aqc_write_ppp_resp *)&desc.params.raw;
+		if (error_offset)
+			*error_offset = le32_to_cpu(resp->error_offset);
+		if (error_info)
+			*error_info = le32_to_cpu(resp->error_info);
+	}
+
+	return status;
+}
+
+/**
+ * i40e_aq_get_ppp_list - Read pipeline personalization profile (ppp)
+ * @hw: pointer to the hw struct
+ * @buff: command buffer (size in bytes = buff_size)
+ * @buff_size: buffer size in bytes
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+enum
+i40e_status_code i40e_aq_get_ppp_list(struct i40e_hw *hw, void *buff,
+				      u16 buff_size, u8 flags,
+				       struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_get_applied_profiles *cmd =
+		(struct i40e_aqc_get_applied_profiles *)&desc.params.raw;
+	i40e_status status;
+
+	i40e_fill_default_direct_cmd_desc(&desc,
+					  i40e_aqc_opc_get_personalization_profile_list);
+
+	desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+	if (buff_size > I40E_AQ_LARGE_BUF)
+		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+	desc.datalen = cpu_to_le16(buff_size);
+
+	cmd->flags = flags;
+
+	status = i40e_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
+
+	return status;
+}
+
+/**
+ * i40e_find_segment_in_package
+ * @segment_type: the segment type to search for (i.e., SEGMENT_TYPE_I40E)
+ * @pkg_hdr: pointer to the package header to be searched
+ *
+ * This function searches a package file for a particular segment type. On
+ * success it returns a pointer to the segment header, otherwise it will
+ * return NULL.
+ **/
+struct i40e_generic_seg_header *
+i40e_find_segment_in_package(u32 segment_type,
+			     struct i40e_package_header *pkg_hdr)
+{
+	struct i40e_generic_seg_header *segment;
+	u32 i;
+
+	/* Search all package segments for the requested segment type */
+	for (i = 0; i < pkg_hdr->segment_count; i++) {
+		segment =
+			(struct i40e_generic_seg_header *)((u8 *)pkg_hdr +
+			 pkg_hdr->segment_offset[i]);
+
+		if (segment->type == segment_type)
+			return segment;
+	}
+
+	return NULL;
+}
+
+/**
+ * i40e_write_profile
+ * @hw: pointer to the hardware structure
+ * @profile: pointer to the profile segment of the package to be downloaded
+ * @track_id: package tracking id
+ *
+ * Handles the download of a complete package.
+ */
+enum i40e_status_code
+i40e_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
+		   u32 track_id)
+{
+	i40e_status status = 0;
+	struct i40e_section_table *sec_tbl;
+	struct i40e_profile_section_header *sec = NULL;
+	u32 dev_cnt;
+	u32 vendor_dev_id;
+	u32 *nvm;
+	u32 section_size = 0;
+	u32 offset = 0, info = 0;
+	u32 i;
+
+	if (!track_id) {
+		i40e_debug(hw, I40E_DEBUG_PACKAGE, "Track_id can't be 0.");
+		return I40E_NOT_SUPPORTED;
+	}
+
+	dev_cnt = profile->device_table_count;
+
+	for (i = 0; i < dev_cnt; i++) {
+		vendor_dev_id = profile->device_table[i].vendor_dev_id;
+		if ((vendor_dev_id >> 16) == PCI_VENDOR_ID_INTEL)
+			if (hw->device_id == (vendor_dev_id & 0xFFFF))
+				break;
+	}
+	if (i == dev_cnt) {
+		i40e_debug(hw, I40E_DEBUG_PACKAGE, "Device doesn't support PPP");
+		return I40E_ERR_DEVICE_NOT_SUPPORTED;
+	}
+
+	nvm = (u32 *)&profile->device_table[dev_cnt];
+	sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1];
+
+	for (i = 0; i < sec_tbl->section_count; i++) {
+		sec = (struct i40e_profile_section_header *)((u8 *)profile +
+					     sec_tbl->section_offset[i]);
+
+		/* Skip 'AQ', 'note' and 'name' sections */
+		if (sec->section.type != SECTION_TYPE_MMIO)
+			continue;
+
+		section_size = sec->section.size +
+			sizeof(struct i40e_profile_section_header);
+
+		/* Write profile */
+		status = i40e_aq_write_ppp(hw, (void *)sec, (u16)section_size,
+					   track_id, &offset, &info, NULL);
+		if (status) {
+			i40e_debug(hw, I40E_DEBUG_PACKAGE,
+				   "Failed to write profile: offset %d, info %d",
+				   offset, info);
+			break;
+		}
+	}
+	return status;
+}
+
+/**
+ * i40e_add_pinfo_to_list
+ * @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.
+ */
+enum i40e_status_code
+i40e_add_pinfo_to_list(struct i40e_hw *hw,
+		       struct i40e_profile_segment *profile,
+		       u8 *profile_info_sec, u32 track_id)
+{
+	i40e_status status = 0;
+	struct i40e_profile_section_header *sec = NULL;
+	struct i40e_profile_info *pinfo;
+	u32 offset = 0, info = 0;
+
+	sec = (struct i40e_profile_section_header *)profile_info_sec;
+	sec->tbl_size = 1;
+	sec->data_end = sizeof(struct i40e_profile_section_header) +
+			sizeof(struct i40e_profile_info);
+	sec->section.type = SECTION_TYPE_INFO;
+	sec->section.offset = sizeof(struct i40e_profile_section_header);
+	sec->section.size = sizeof(struct i40e_profile_info);
+	pinfo = (struct i40e_profile_info *)(profile_info_sec +
+					     sec->section.offset);
+	pinfo->track_id = track_id;
+	pinfo->version = profile->version;
+	pinfo->op = I40E_PPP_ADD_TRACKID;
+	memcpy(pinfo->name, profile->name, I40E_PPP_NAME_SIZE);
+
+	status = i40e_aq_write_ppp(hw, (void *)sec, sec->data_end,
+				   track_id, &offset, &info, NULL);
+	return status;
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index dfc5e59..611bbc7 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -377,4 +377,21 @@  i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page, u16 reg,
 u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
 i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
 				    u32 time, u32 interval);
+i40e_status i40e_aq_write_ppp(struct i40e_hw *hw, void *buff,
+			      u16 buff_size, u32 track_id,
+				u32 *error_offset, u32 *error_info,
+				struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_get_ppp_list(struct i40e_hw *hw, void *buff,
+				 u16 buff_size, u8 flags,
+				   struct i40e_asq_cmd_details *cmd_details);
+struct i40e_generic_seg_header *
+i40e_find_segment_in_package(u32 segment_type,
+			     struct i40e_package_header *pkg_header);
+enum i40e_status_code
+i40e_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *i40e_seg,
+		   u32 track_id);
+enum i40e_status_code
+i40e_add_pinfo_to_list(struct i40e_hw *hw,
+		       struct i40e_profile_segment *profile,
+		       u8 *profile_info_sec, u32 track_id);
 #endif /* _I40E_PROTOTYPE_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index 08364a4..f235899 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -78,6 +78,7 @@  enum i40e_debug_mask {
 	I40E_DEBUG_DCB			= 0x00000400,
 	I40E_DEBUG_DIAG			= 0x00000800,
 	I40E_DEBUG_FD			= 0x00001000,
+	I40E_DEBUG_PACKAGE		= 0x00002000,
 	I40E_DEBUG_IWARP		= 0x00F00000,
 	I40E_DEBUG_AQ_MESSAGE		= 0x01000000,
 	I40E_DEBUG_AQ_DESCRIPTOR	= 0x02000000,
@@ -1465,4 +1466,83 @@  struct i40e_lldp_variables {
 #define I40E_FLEX_56_MASK		(0x1ULL << I40E_FLEX_56_SHIFT)
 #define I40E_FLEX_57_SHIFT		6
 #define I40E_FLEX_57_MASK		(0x1ULL << I40E_FLEX_57_SHIFT)
+
+/* Version format for PPP */
+struct i40e_ppp_version {
+	u8 major;
+	u8 minor;
+	u8 update;
+	u8 draft;
+};
+
+#define I40E_PPP_NAME_SIZE	32
+
+/* Package header */
+struct i40e_package_header {
+	struct i40e_ppp_version version;
+	u32 segment_count;
+	u32 segment_offset[1];
+};
+
+/* Generic segment header */
+struct i40e_generic_seg_header {
+#define SEGMENT_TYPE_METADATA	0x00000001
+#define SEGMENT_TYPE_NOTES	0x00000002
+#define SEGMENT_TYPE_I40E	0x00000011
+#define SEGMENT_TYPE_X722	0x00000012
+	u32 type;
+	struct i40e_ppp_version version;
+	u32 size;
+	char name[I40E_PPP_NAME_SIZE];
+};
+
+struct i40e_metadata_segment {
+	struct i40e_generic_seg_header header;
+	struct i40e_ppp_version version;
+	u32 track_id;
+	char     name[I40E_PPP_NAME_SIZE];
+};
+
+struct i40e_device_id_entry {
+	u32 vendor_dev_id;
+	u32 sub_vendor_dev_id;
+};
+
+struct i40e_profile_segment {
+	struct i40e_generic_seg_header header;
+	struct i40e_ppp_version version;
+	char name[I40E_PPP_NAME_SIZE];
+	u32 device_table_count;
+	struct i40e_device_id_entry device_table[1];
+};
+
+struct i40e_section_table {
+	u32 section_count;
+	u32 section_offset[1];
+};
+
+struct i40e_profile_section_header {
+	u16 tbl_size;
+	u16 data_end;
+	struct {
+#define SECTION_TYPE_INFO	0x00000010
+#define SECTION_TYPE_MMIO	0x00000800
+#define SECTION_TYPE_AQ		0x00000801
+#define SECTION_TYPE_NOTE	0x80000000
+#define SECTION_TYPE_NAME	0x80000001
+		u32 type;
+		u32 offset;
+		u32 size;
+	} section;
+};
+
+struct i40e_profile_info {
+	u32 track_id;
+	struct i40e_ppp_version version;
+	u8 op;
+#define I40E_PPP_ADD_TRACKID		0x01
+#define I40E_PPP_REMOVE_TRACKID	0x02
+	u8 reserved[7];
+	u8 name[I40E_PPP_NAME_SIZE];
+};
 #endif /* _I40E_TYPE_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
index c28cb8f..91d8786 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
@@ -190,6 +190,10 @@  enum i40e_admin_queue_opc {
 	i40e_aqc_opc_add_mirror_rule	= 0x0260,
 	i40e_aqc_opc_delete_mirror_rule	= 0x0261,
 
+	/* Pipeline Personalization Profile */
+	i40e_aqc_opc_write_personalization_profile	= 0x0270,
+	i40e_aqc_opc_get_personalization_profile_list	= 0x0271,
+
 	/* DCB commands */
 	i40e_aqc_opc_dcb_ignore_pfc	= 0x0301,
 	i40e_aqc_opc_dcb_updated	= 0x0302,
@@ -1426,6 +1430,36 @@  struct i40e_aqc_add_delete_mirror_rule_completion {
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion);
 
+/* Pipeline Personalization Profile */
+struct i40e_aqc_write_personalization_profile {
+	u8      flags;
+	u8      reserved[3];
+	__le32  profile_track_id;
+	__le32  addr_high;
+	__le32  addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_write_personalization_profile);
+
+struct i40e_aqc_write_ppp_resp {
+	__le32 error_offset;
+	__le32 error_info;
+	__le32 addr_high;
+	__le32 addr_low;
+};
+
+struct i40e_aqc_get_applied_profiles {
+	u8      flags;
+#define I40E_AQC_GET_PPP_GET_CONF	0x1
+#define I40E_AQC_GET_PPP_GET_RDPU_CONF	0x2
+	u8      rsv[3];
+	__le32  reserved;
+	__le32  addr_high;
+	__le32  addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_applied_profiles);
+
 /* DCB 0x03xx*/
 
 /* PFC Ignore (direct 0x0301)
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c
index 626fbf1..606f5f1 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c
@@ -1131,3 +1131,215 @@  i40e_status i40e_vf_reset(struct i40e_hw *hw)
 	return i40e_aq_send_msg_to_pf(hw, I40E_VIRTCHNL_OP_RESET_VF,
 				      0, NULL, 0, NULL);
 }
+
+/**
+ * i40evf_aq_write_ppp - Write pipeline personalization profile (ppp)
+ * @hw: pointer to the hw struct
+ * @buff: command buffer (size in bytes = buff_size)
+ * @buff_size: buffer size in bytes
+ * @track_id: package tracking id
+ * @error_offset: returns error offset
+ * @error_info: returns error information
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+enum
+i40e_status_code i40evf_aq_write_ppp(struct i40e_hw *hw, void *buff,
+				     u16 buff_size, u32 track_id,
+				   u32 *error_offset, u32 *error_info,
+				   struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_write_personalization_profile *cmd =
+		(struct i40e_aqc_write_personalization_profile *)
+		&desc.params.raw;
+	struct i40e_aqc_write_ppp_resp *resp;
+	i40e_status status;
+
+	i40evf_fill_default_direct_cmd_desc(&desc,
+					    i40e_aqc_opc_write_personalization_profile);
+
+	desc.flags |= cpu_to_le16(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD);
+	if (buff_size > I40E_AQ_LARGE_BUF)
+		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+	desc.datalen = cpu_to_le16(buff_size);
+
+	cmd->profile_track_id = cpu_to_le32(track_id);
+
+	status = i40evf_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
+	if (!status) {
+		resp = (struct i40e_aqc_write_ppp_resp *)&desc.params.raw;
+		if (error_offset)
+			*error_offset = le32_to_cpu(resp->error_offset);
+		if (error_info)
+			*error_info = le32_to_cpu(resp->error_info);
+	}
+
+	return status;
+}
+
+/**
+ * i40evf_aq_get_ppp_list - Read pipeline personalization profile (ppp)
+ * @hw: pointer to the hw struct
+ * @buff: command buffer (size in bytes = buff_size)
+ * @buff_size: buffer size in bytes
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+enum
+i40e_status_code i40evf_aq_get_ppp_list(struct i40e_hw *hw, void *buff,
+					u16 buff_size, u8 flags,
+				      struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_get_applied_profiles *cmd =
+		(struct i40e_aqc_get_applied_profiles *)&desc.params.raw;
+	i40e_status status;
+
+	i40evf_fill_default_direct_cmd_desc(&desc,
+					    i40e_aqc_opc_get_personalization_profile_list);
+
+	desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+	if (buff_size > I40E_AQ_LARGE_BUF)
+		desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+	desc.datalen = cpu_to_le16(buff_size);
+
+	cmd->flags = flags;
+
+	status = i40evf_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
+
+	return status;
+}
+
+/**
+ * i40evf_find_segment_in_package
+ * @segment_type: the segment type to search for (i.e., SEGMENT_TYPE_I40E)
+ * @pkg_hdr: pointer to the package header to be searched
+ *
+ * This function searches a package file for a particular segment type. On
+ * success it returns a pointer to the segment header, otherwise it will
+ * return NULL.
+ **/
+struct i40e_generic_seg_header *
+i40evf_find_segment_in_package(u32 segment_type,
+			       struct i40e_package_header *pkg_hdr)
+{
+	struct i40e_generic_seg_header *segment;
+	u32 i;
+
+	/* Search all package segments for the requested segment type */
+	for (i = 0; i < pkg_hdr->segment_count; i++) {
+		segment =
+			(struct i40e_generic_seg_header *)((u8 *)pkg_hdr +
+			 pkg_hdr->segment_offset[i]);
+
+		if (segment->type == segment_type)
+			return segment;
+	}
+
+	return NULL;
+}
+
+/**
+ * i40evf_write_profile
+ * @hw: pointer to the hardware structure
+ * @profile: pointer to the profile segment of the package to be downloaded
+ * @track_id: package tracking id
+ *
+ * Handles the download of a complete package.
+ */
+enum i40e_status_code
+i40evf_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
+		     u32 track_id)
+{
+	i40e_status status = 0;
+	struct i40e_section_table *sec_tbl;
+	struct i40e_profile_section_header *sec = NULL;
+	u32 dev_cnt;
+	u32 vendor_dev_id;
+	u32 *nvm;
+	u32 section_size = 0;
+	u32 offset = 0, info = 0;
+	u32 i;
+
+	if (!track_id) {
+		i40e_debug(hw, I40E_DEBUG_PACKAGE, "Track_id can't be 0.");
+		return I40E_NOT_SUPPORTED;
+	}
+
+	dev_cnt = profile->device_table_count;
+
+	for (i = 0; i < dev_cnt; i++) {
+		vendor_dev_id = profile->device_table[i].vendor_dev_id;
+		if ((vendor_dev_id >> 16) == PCI_VENDOR_ID_INTEL)
+			if (hw->device_id == (vendor_dev_id & 0xFFFF))
+				break;
+	}
+	if (i == dev_cnt) {
+		i40e_debug(hw, I40E_DEBUG_PACKAGE, "Device doesn't support PPP");
+		return I40E_ERR_DEVICE_NOT_SUPPORTED;
+	}
+
+	nvm = (u32 *)&profile->device_table[dev_cnt];
+	sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1];
+
+	for (i = 0; i < sec_tbl->section_count; i++) {
+		sec = (struct i40e_profile_section_header *)((u8 *)profile +
+					     sec_tbl->section_offset[i]);
+
+		/* Skip 'AQ', 'note' and 'name' sections */
+		if (sec->section.type != SECTION_TYPE_MMIO)
+			continue;
+
+		section_size = sec->section.size +
+			sizeof(struct i40e_profile_section_header);
+
+		/* Write profile */
+		status = i40evf_aq_write_ppp(hw, (void *)sec, (u16)section_size,
+					     track_id, &offset, &info, NULL);
+		if (status) {
+			i40e_debug(hw, I40E_DEBUG_PACKAGE,
+				   "Failed to write profile: offset %d, info %d",
+				   offset, info);
+			break;
+		}
+	}
+	return status;
+}
+
+/**
+ * i40evf_add_pinfo_to_list
+ * @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.
+ */
+enum i40e_status_code
+i40evf_add_pinfo_to_list(struct i40e_hw *hw,
+			 struct i40e_profile_segment *profile,
+			  u8 *profile_info_sec, u32 track_id)
+{
+	i40e_status status = 0;
+	struct i40e_profile_section_header *sec = NULL;
+	struct i40e_profile_info *pinfo;
+	u32 offset = 0, info = 0;
+
+	sec = (struct i40e_profile_section_header *)profile_info_sec;
+	sec->tbl_size = 1;
+	sec->data_end = sizeof(struct i40e_profile_section_header) +
+			sizeof(struct i40e_profile_info);
+	sec->section.type = SECTION_TYPE_INFO;
+	sec->section.offset = sizeof(struct i40e_profile_section_header);
+	sec->section.size = sizeof(struct i40e_profile_info);
+	pinfo = (struct i40e_profile_info *)(profile_info_sec +
+					     sec->section.offset);
+	pinfo->track_id = track_id;
+	pinfo->version = profile->version;
+	pinfo->op = I40E_PPP_ADD_TRACKID;
+	memcpy(pinfo->name, profile->name, I40E_PPP_NAME_SIZE);
+
+	status = i40evf_aq_write_ppp(hw, (void *)sec, sec->data_end,
+				     track_id, &offset, &info, NULL);
+	return status;
+}
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
index ba6c6bd..329ce2b 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
@@ -122,4 +122,21 @@  i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page, u16 reg,
 u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
 i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
 				    u32 time, u32 interval);
+i40e_status i40evf_aq_write_ppp(struct i40e_hw *hw, void *buff,
+				u16 buff_size, u32 track_id,
+				u32 *error_offset, u32 *error_info,
+				struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40evf_aq_get_ppp_list(struct i40e_hw *hw, void *buff,
+				   u16 buff_size, u8 flags,
+				   struct i40e_asq_cmd_details *cmd_details);
+struct i40e_generic_seg_header *
+i40evf_find_segment_in_package(u32 segment_type,
+			       struct i40e_package_header *pkg_header);
+enum i40e_status_code
+i40evf_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *i40e_seg,
+		     u32 track_id);
+enum i40e_status_code
+i40evf_add_pinfo_to_list(struct i40e_hw *hw,
+			 struct i40e_profile_segment *profile,
+			  u8 *profile_info_sec, u32 track_id);
 #endif /* _I40E_PROTOTYPE_H_ */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
index 16bb880..44bb9f0 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
@@ -78,6 +78,7 @@  enum i40e_debug_mask {
 	I40E_DEBUG_DCB			= 0x00000400,
 	I40E_DEBUG_DIAG			= 0x00000800,
 	I40E_DEBUG_FD			= 0x00001000,
+	I40E_DEBUG_PACKAGE		= 0x00002000,
 
 	I40E_DEBUG_AQ_MESSAGE		= 0x01000000,
 	I40E_DEBUG_AQ_DESCRIPTOR	= 0x02000000,
@@ -1396,4 +1397,83 @@  enum i40e_reset_type {
 #define I40E_FD_INSET_FLEX_WORD57_SHIFT		10
 #define I40E_FD_INSET_FLEX_WORD57_MASK		(0x1ULL << \
 					I40E_FD_INSET_FLEX_WORD57_SHIFT)
+
+/* Version format for PPP */
+struct i40e_ppp_version {
+	u8 major;
+	u8 minor;
+	u8 update;
+	u8 draft;
+};
+
+#define I40E_PPP_NAME_SIZE	32
+
+/* Package header */
+struct i40e_package_header {
+	struct i40e_ppp_version version;
+	u32 segment_count;
+	u32 segment_offset[1];
+};
+
+/* Generic segment header */
+struct i40e_generic_seg_header {
+#define SEGMENT_TYPE_METADATA	0x00000001
+#define SEGMENT_TYPE_NOTES	0x00000002
+#define SEGMENT_TYPE_I40E	0x00000011
+#define SEGMENT_TYPE_X722	0x00000012
+	u32 type;
+	struct i40e_ppp_version version;
+	u32 size;
+	char name[I40E_PPP_NAME_SIZE];
+};
+
+struct i40e_metadata_segment {
+	struct i40e_generic_seg_header header;
+	struct i40e_ppp_version version;
+	u32 track_id;
+	char     name[I40E_PPP_NAME_SIZE];
+};
+
+struct i40e_device_id_entry {
+	u32 vendor_dev_id;
+	u32 sub_vendor_dev_id;
+};
+
+struct i40e_profile_segment {
+	struct i40e_generic_seg_header header;
+	struct i40e_ppp_version version;
+	char name[I40E_PPP_NAME_SIZE];
+	u32 device_table_count;
+	struct i40e_device_id_entry device_table[1];
+};
+
+struct i40e_section_table {
+	u32 section_count;
+	u32 section_offset[1];
+};
+
+struct i40e_profile_section_header {
+	u16 tbl_size;
+	u16 data_end;
+	struct {
+#define SECTION_TYPE_INFO	0x00000010
+#define SECTION_TYPE_MMIO	0x00000800
+#define SECTION_TYPE_AQ		0x00000801
+#define SECTION_TYPE_NOTE	0x80000000
+#define SECTION_TYPE_NAME	0x80000001
+		u32 type;
+		u32 offset;
+		u32 size;
+	} section;
+};
+
+struct i40e_profile_info {
+	u32 track_id;
+	struct i40e_ppp_version version;
+	u8 op;
+#define I40E_PPP_ADD_TRACKID		0x01
+#define I40E_PPP_REMOVE_TRACKID	0x02
+	u8 reserved[7];
+	u8 name[I40E_PPP_NAME_SIZE];
+};
 #endif /* _I40E_TYPE_H_ */