@@ -5448,6 +5448,163 @@ i40e_find_segment_in_package(u32 segment_type,
5448
5448
return NULL ;
5449
5449
}
5450
5450
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
+
5451
5608
/**
5452
5609
* i40e_write_profile
5453
5610
* @hw: pointer to the hardware structure
@@ -5463,47 +5620,99 @@ i40e_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
5463
5620
i40e_status status = 0 ;
5464
5621
struct i40e_section_table * sec_tbl ;
5465
5622
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 ;
5469
5624
u32 section_size = 0 ;
5470
5625
u32 offset = 0 , info = 0 ;
5626
+ u32 sec_off ;
5471
5627
u32 i ;
5472
5628
5473
- dev_cnt = profile -> device_table_count ;
5629
+ status = i40e_validate_profile (hw , profile , track_id , false);
5630
+ if (status )
5631
+ return status ;
5474
5632
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 );
5479
5646
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
+ }
5480
5667
}
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 ;
5485
5690
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 ;
5488
5694
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 );
5492
5696
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 )
5495
5704
continue ;
5496
5705
5497
5706
section_size = sec -> section .size +
5498
5707
sizeof (struct i40e_profile_section_header );
5499
5708
5500
- /* Write profile */
5709
+ /* Write roll-back MMIO section */
5501
5710
status = i40e_aq_write_ddp (hw , (void * )sec , (u16 )section_size ,
5502
5711
track_id , & offset , & info , NULL );
5503
5712
if (status ) {
5504
5713
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 );
5507
5716
break ;
5508
5717
}
5509
5718
}
0 commit comments