@@ -5448,6 +5448,163 @@ i40e_find_segment_in_package(u32 segment_type,
54485448 return NULL ;
54495449}
54505450
5451+ /* Get section table in profile */
5452+ #define I40E_SECTION_TABLE (profile , sec_tbl ) \
5453+ do { \
5454+ struct i40e_profile_segment *p = (profile); \
5455+ u32 count; \
5456+ u32 *nvm; \
5457+ count = p->device_table_count; \
5458+ nvm = (u32 *)&p->device_table[count]; \
5459+ sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1]; \
5460+ } while (0)
5461+
5462+ /* Get section header in profile */
5463+ #define I40E_SECTION_HEADER (profile , offset ) \
5464+ (struct i40e_profile_section_header *)((u8 *)(profile) + (offset))
5465+
5466+ /**
5467+ * i40e_find_section_in_profile
5468+ * @section_type: the section type to search for (i.e., SECTION_TYPE_NOTE)
5469+ * @profile: pointer to the i40e segment header to be searched
5470+ *
5471+ * This function searches i40e segment for a particular section type. On
5472+ * success it returns a pointer to the section header, otherwise it will
5473+ * return NULL.
5474+ **/
5475+ struct i40e_profile_section_header *
5476+ i40e_find_section_in_profile (u32 section_type ,
5477+ struct i40e_profile_segment * profile )
5478+ {
5479+ struct i40e_profile_section_header * sec ;
5480+ struct i40e_section_table * sec_tbl ;
5481+ u32 sec_off ;
5482+ u32 i ;
5483+
5484+ if (profile -> header .type != SEGMENT_TYPE_I40E )
5485+ return NULL ;
5486+
5487+ I40E_SECTION_TABLE (profile , sec_tbl );
5488+
5489+ for (i = 0 ; i < sec_tbl -> section_count ; i ++ ) {
5490+ sec_off = sec_tbl -> section_offset [i ];
5491+ sec = I40E_SECTION_HEADER (profile , sec_off );
5492+ if (sec -> section .type == section_type )
5493+ return sec ;
5494+ }
5495+
5496+ return NULL ;
5497+ }
5498+
5499+ /**
5500+ * i40e_ddp_exec_aq_section - Execute generic AQ for DDP
5501+ * @hw: pointer to the hw struct
5502+ * @aq: command buffer containing all data to execute AQ
5503+ **/
5504+ static enum
5505+ i40e_status_code i40e_ddp_exec_aq_section (struct i40e_hw * hw ,
5506+ struct i40e_profile_aq_section * aq )
5507+ {
5508+ i40e_status status ;
5509+ struct i40e_aq_desc desc ;
5510+ u8 * msg = NULL ;
5511+ u16 msglen ;
5512+
5513+ i40e_fill_default_direct_cmd_desc (& desc , aq -> opcode );
5514+ desc .flags |= cpu_to_le16 (aq -> flags );
5515+ memcpy (desc .params .raw , aq -> param , sizeof (desc .params .raw ));
5516+
5517+ msglen = aq -> datalen ;
5518+ if (msglen ) {
5519+ desc .flags |= cpu_to_le16 ((u16 )(I40E_AQ_FLAG_BUF |
5520+ I40E_AQ_FLAG_RD ));
5521+ if (msglen > I40E_AQ_LARGE_BUF )
5522+ desc .flags |= cpu_to_le16 ((u16 )I40E_AQ_FLAG_LB );
5523+ desc .datalen = cpu_to_le16 (msglen );
5524+ msg = & aq -> data [0 ];
5525+ }
5526+
5527+ status = i40e_asq_send_command (hw , & desc , msg , msglen , NULL );
5528+
5529+ if (status ) {
5530+ i40e_debug (hw , I40E_DEBUG_PACKAGE ,
5531+ "unable to exec DDP AQ opcode %u, error %d\n" ,
5532+ aq -> opcode , status );
5533+ return status ;
5534+ }
5535+
5536+ /* copy returned desc to aq_buf */
5537+ memcpy (aq -> param , desc .params .raw , sizeof (desc .params .raw ));
5538+
5539+ return 0 ;
5540+ }
5541+
5542+ /**
5543+ * i40e_validate_profile
5544+ * @hw: pointer to the hardware structure
5545+ * @profile: pointer to the profile segment of the package to be validated
5546+ * @track_id: package tracking id
5547+ * @rollback: flag if the profile is for rollback.
5548+ *
5549+ * Validates supported devices and profile's sections.
5550+ */
5551+ static enum i40e_status_code
5552+ i40e_validate_profile (struct i40e_hw * hw , struct i40e_profile_segment * profile ,
5553+ u32 track_id , bool rollback )
5554+ {
5555+ struct i40e_profile_section_header * sec = NULL ;
5556+ i40e_status status = 0 ;
5557+ struct i40e_section_table * sec_tbl ;
5558+ u32 vendor_dev_id ;
5559+ u32 dev_cnt ;
5560+ u32 sec_off ;
5561+ u32 i ;
5562+
5563+ if (track_id == I40E_DDP_TRACKID_INVALID ) {
5564+ i40e_debug (hw , I40E_DEBUG_PACKAGE , "Invalid track_id\n" );
5565+ return I40E_NOT_SUPPORTED ;
5566+ }
5567+
5568+ dev_cnt = profile -> device_table_count ;
5569+ for (i = 0 ; i < dev_cnt ; i ++ ) {
5570+ vendor_dev_id = profile -> device_table [i ].vendor_dev_id ;
5571+ if ((vendor_dev_id >> 16 ) == PCI_VENDOR_ID_INTEL &&
5572+ hw -> device_id == (vendor_dev_id & 0xFFFF ))
5573+ break ;
5574+ }
5575+ if (dev_cnt && i == dev_cnt ) {
5576+ i40e_debug (hw , I40E_DEBUG_PACKAGE ,
5577+ "Device doesn't support DDP\n" );
5578+ return I40E_ERR_DEVICE_NOT_SUPPORTED ;
5579+ }
5580+
5581+ I40E_SECTION_TABLE (profile , sec_tbl );
5582+
5583+ /* Validate sections types */
5584+ for (i = 0 ; i < sec_tbl -> section_count ; i ++ ) {
5585+ sec_off = sec_tbl -> section_offset [i ];
5586+ sec = I40E_SECTION_HEADER (profile , sec_off );
5587+ if (rollback ) {
5588+ if (sec -> section .type == SECTION_TYPE_MMIO ||
5589+ sec -> section .type == SECTION_TYPE_AQ ||
5590+ sec -> section .type == SECTION_TYPE_RB_AQ ) {
5591+ i40e_debug (hw , I40E_DEBUG_PACKAGE ,
5592+ "Not a roll-back package\n" );
5593+ return I40E_NOT_SUPPORTED ;
5594+ }
5595+ } else {
5596+ if (sec -> section .type == SECTION_TYPE_RB_AQ ||
5597+ sec -> section .type == SECTION_TYPE_RB_MMIO ) {
5598+ i40e_debug (hw , I40E_DEBUG_PACKAGE ,
5599+ "Not an original package\n" );
5600+ return I40E_NOT_SUPPORTED ;
5601+ }
5602+ }
5603+ }
5604+
5605+ return status ;
5606+ }
5607+
54515608/**
54525609 * i40e_write_profile
54535610 * @hw: pointer to the hardware structure
@@ -5463,47 +5620,99 @@ i40e_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
54635620 i40e_status status = 0 ;
54645621 struct i40e_section_table * sec_tbl ;
54655622 struct i40e_profile_section_header * sec = NULL ;
5466- u32 dev_cnt ;
5467- u32 vendor_dev_id ;
5468- u32 * nvm ;
5623+ struct i40e_profile_aq_section * ddp_aq ;
54695624 u32 section_size = 0 ;
54705625 u32 offset = 0 , info = 0 ;
5626+ u32 sec_off ;
54715627 u32 i ;
54725628
5473- dev_cnt = profile -> device_table_count ;
5629+ status = i40e_validate_profile (hw , profile , track_id , false);
5630+ if (status )
5631+ return status ;
54745632
5475- for (i = 0 ; i < dev_cnt ; i ++ ) {
5476- vendor_dev_id = profile -> device_table [i ].vendor_dev_id ;
5477- if ((vendor_dev_id >> 16 ) == PCI_VENDOR_ID_INTEL )
5478- if (hw -> device_id == (vendor_dev_id & 0xFFFF ))
5633+ I40E_SECTION_TABLE (profile , sec_tbl );
5634+
5635+ for (i = 0 ; i < sec_tbl -> section_count ; i ++ ) {
5636+ sec_off = sec_tbl -> section_offset [i ];
5637+ sec = I40E_SECTION_HEADER (profile , sec_off );
5638+ /* Process generic admin command */
5639+ if (sec -> section .type == SECTION_TYPE_AQ ) {
5640+ ddp_aq = (struct i40e_profile_aq_section * )& sec [1 ];
5641+ status = i40e_ddp_exec_aq_section (hw , ddp_aq );
5642+ if (status ) {
5643+ i40e_debug (hw , I40E_DEBUG_PACKAGE ,
5644+ "Failed to execute aq: section %d, opcode %u\n" ,
5645+ i , ddp_aq -> opcode );
54795646 break ;
5647+ }
5648+ sec -> section .type = SECTION_TYPE_RB_AQ ;
5649+ }
5650+
5651+ /* Skip any non-mmio sections */
5652+ if (sec -> section .type != SECTION_TYPE_MMIO )
5653+ continue ;
5654+
5655+ section_size = sec -> section .size +
5656+ sizeof (struct i40e_profile_section_header );
5657+
5658+ /* Write MMIO section */
5659+ status = i40e_aq_write_ddp (hw , (void * )sec , (u16 )section_size ,
5660+ track_id , & offset , & info , NULL );
5661+ if (status ) {
5662+ i40e_debug (hw , I40E_DEBUG_PACKAGE ,
5663+ "Failed to write profile: section %d, offset %d, info %d\n" ,
5664+ i , offset , info );
5665+ break ;
5666+ }
54805667 }
5481- if (i == dev_cnt ) {
5482- i40e_debug (hw , I40E_DEBUG_PACKAGE , "Device doesn't support DDP" );
5483- return I40E_ERR_DEVICE_NOT_SUPPORTED ;
5484- }
5668+ return status ;
5669+ }
5670+
5671+ /**
5672+ * i40e_rollback_profile
5673+ * @hw: pointer to the hardware structure
5674+ * @profile: pointer to the profile segment of the package to be removed
5675+ * @track_id: package tracking id
5676+ *
5677+ * Rolls back previously loaded package.
5678+ */
5679+ enum i40e_status_code
5680+ i40e_rollback_profile (struct i40e_hw * hw , struct i40e_profile_segment * profile ,
5681+ u32 track_id )
5682+ {
5683+ struct i40e_profile_section_header * sec = NULL ;
5684+ i40e_status status = 0 ;
5685+ struct i40e_section_table * sec_tbl ;
5686+ u32 offset = 0 , info = 0 ;
5687+ u32 section_size = 0 ;
5688+ u32 sec_off ;
5689+ int i ;
54855690
5486- nvm = (u32 * )& profile -> device_table [dev_cnt ];
5487- sec_tbl = (struct i40e_section_table * )& nvm [nvm [0 ] + 1 ];
5691+ status = i40e_validate_profile (hw , profile , track_id , true);
5692+ if (status )
5693+ return status ;
54885694
5489- for (i = 0 ; i < sec_tbl -> section_count ; i ++ ) {
5490- sec = (struct i40e_profile_section_header * )((u8 * )profile +
5491- sec_tbl -> section_offset [i ]);
5695+ I40E_SECTION_TABLE (profile , sec_tbl );
54925696
5493- /* Skip 'AQ', 'note' and 'name' sections */
5494- if (sec -> section .type != SECTION_TYPE_MMIO )
5697+ /* For rollback write sections in reverse */
5698+ for (i = sec_tbl -> section_count - 1 ; i >= 0 ; i -- ) {
5699+ sec_off = sec_tbl -> section_offset [i ];
5700+ sec = I40E_SECTION_HEADER (profile , sec_off );
5701+
5702+ /* Skip any non-rollback sections */
5703+ if (sec -> section .type != SECTION_TYPE_RB_MMIO )
54955704 continue ;
54965705
54975706 section_size = sec -> section .size +
54985707 sizeof (struct i40e_profile_section_header );
54995708
5500- /* Write profile */
5709+ /* Write roll-back MMIO section */
55015710 status = i40e_aq_write_ddp (hw , (void * )sec , (u16 )section_size ,
55025711 track_id , & offset , & info , NULL );
55035712 if (status ) {
55045713 i40e_debug (hw , I40E_DEBUG_PACKAGE ,
5505- "Failed to write profile: offset %d, info %d" ,
5506- offset , info );
5714+ "Failed to write profile: section %d, offset %d, info %d\n " ,
5715+ i , offset , info );
55075716 break ;
55085717 }
55095718 }
0 commit comments