aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel/i40e/i40e_common.c
diff options
context:
space:
mode:
authorAleksandr Loktionov <aleksandr.loktionov@intel.com>2019-02-06 18:08:16 -0500
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2019-04-16 18:10:21 -0400
commitcdc594e00370e153c323cf8aa9c43b66679e09a0 (patch)
tree0aec23f6666a5ec1b2d0fb5253a39bb17ca48bd2 /drivers/net/ethernet/intel/i40e/i40e_common.c
parent3e957b377bf4262aec2dd424f28ece94e36814d4 (diff)
i40e: Implement DDP support in i40e driver
This patch introduces DDP (Dynamic Device Personalization) which allows loading profiles that change the way internal parser interprets processed frames. To load DDP profiles it utilizes ethtool flash feature. The files with recipes must be located in /var/lib/firmware directory. Afterwards the recipe can be loaded by invoking: ethtool -f <if_name> <file_name> 100 ethtool -f <if_name> - 100 See further details of this feature in the i40e documentation, or visit https://www.intel.com/content/www/us/en/architecture-and-technology/ethernet/dynamic-device-personalization-brief.html The driver shall verify DDP profile can be loaded in accordance with the rules: * Package with Group ID 0 are exclusive and can only be loaded the first. * Packages with Group ID 0x01-0xFE can only be loaded simultaneously with the packages from the same group. * Packages with Group ID 0xFF are compatible with all other packages. Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_common.c')
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_common.c253
1 files changed, 231 insertions, 22 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index 97a9b1fb4763..486a406789b8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -5448,6 +5448,163 @@ i40e_find_segment_in_package(u32 segment_type,
5448 return NULL; 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 **/
5475struct i40e_profile_section_header *
5476i40e_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 **/
5504static enum
5505i40e_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 */
5551static enum i40e_status_code
5552i40e_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 * i40e_write_profile 5609 * i40e_write_profile
5453 * @hw: pointer to the hardware structure 5610 * @hw: pointer to the hardware structure
@@ -5463,47 +5620,99 @@ i40e_write_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile,
5463 i40e_status status = 0; 5620 i40e_status status = 0;
5464 struct i40e_section_table *sec_tbl; 5621 struct i40e_section_table *sec_tbl;
5465 struct i40e_profile_section_header *sec = NULL; 5622 struct i40e_profile_section_header *sec = NULL;
5466 u32 dev_cnt; 5623 struct i40e_profile_aq_section *ddp_aq;
5467 u32 vendor_dev_id;
5468 u32 *nvm;
5469 u32 section_size = 0; 5624 u32 section_size = 0;
5470 u32 offset = 0, info = 0; 5625 u32 offset = 0, info = 0;
5626 u32 sec_off;
5471 u32 i; 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++) { 5633 I40E_SECTION_TABLE(profile, sec_tbl);
5476 vendor_dev_id = profile->device_table[i].vendor_dev_id; 5634
5477 if ((vendor_dev_id >> 16) == PCI_VENDOR_ID_INTEL) 5635 for (i = 0; i < sec_tbl->section_count; i++) {
5478 if (hw->device_id == (vendor_dev_id & 0xFFFF)) 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 break; 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) { 5668 return status;
5482 i40e_debug(hw, I40E_DEBUG_PACKAGE, "Device doesn't support DDP"); 5669}
5483 return I40E_ERR_DEVICE_NOT_SUPPORTED; 5670
5484 } 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 */
5679enum i40e_status_code
5680i40e_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]; 5691 status = i40e_validate_profile(hw, profile, track_id, true);
5487 sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1]; 5692 if (status)
5693 return status;
5488 5694
5489 for (i = 0; i < sec_tbl->section_count; i++) { 5695 I40E_SECTION_TABLE(profile, sec_tbl);
5490 sec = (struct i40e_profile_section_header *)((u8 *)profile +
5491 sec_tbl->section_offset[i]);
5492 5696
5493 /* Skip 'AQ', 'note' and 'name' sections */ 5697 /* For rollback write sections in reverse */
5494 if (sec->section.type != SECTION_TYPE_MMIO) 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 continue; 5704 continue;
5496 5705
5497 section_size = sec->section.size + 5706 section_size = sec->section.size +
5498 sizeof(struct i40e_profile_section_header); 5707 sizeof(struct i40e_profile_section_header);
5499 5708
5500 /* Write profile */ 5709 /* Write roll-back MMIO section */
5501 status = i40e_aq_write_ddp(hw, (void *)sec, (u16)section_size, 5710 status = i40e_aq_write_ddp(hw, (void *)sec, (u16)section_size,
5502 track_id, &offset, &info, NULL); 5711 track_id, &offset, &info, NULL);
5503 if (status) { 5712 if (status) {
5504 i40e_debug(hw, I40E_DEBUG_PACKAGE, 5713 i40e_debug(hw, I40E_DEBUG_PACKAGE,
5505 "Failed to write profile: offset %d, info %d", 5714 "Failed to write profile: section %d, offset %d, info %d\n",
5506 offset, info); 5715 i, offset, info);
5507 break; 5716 break;
5508 } 5717 }
5509 } 5718 }