| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
|---|
| 2 | 2 | /* Copyright(c) 2013 - 2018 Intel Corporation. */ |
|---|
| 3 | 3 | |
|---|
| 4 | +#include "i40e.h" |
|---|
| 4 | 5 | #include "i40e_type.h" |
|---|
| 5 | 6 | #include "i40e_adminq.h" |
|---|
| 6 | 7 | #include "i40e_prototype.h" |
|---|
| .. | .. |
|---|
| 13 | 14 | * This function sets the mac type of the adapter based on the |
|---|
| 14 | 15 | * vendor ID and device ID stored in the hw structure. |
|---|
| 15 | 16 | **/ |
|---|
| 16 | | -static i40e_status i40e_set_mac_type(struct i40e_hw *hw) |
|---|
| 17 | +i40e_status i40e_set_mac_type(struct i40e_hw *hw) |
|---|
| 17 | 18 | { |
|---|
| 18 | 19 | i40e_status status = 0; |
|---|
| 19 | 20 | |
|---|
| .. | .. |
|---|
| 26 | 27 | case I40E_DEV_ID_QSFP_A: |
|---|
| 27 | 28 | case I40E_DEV_ID_QSFP_B: |
|---|
| 28 | 29 | case I40E_DEV_ID_QSFP_C: |
|---|
| 30 | + case I40E_DEV_ID_5G_BASE_T_BC: |
|---|
| 29 | 31 | case I40E_DEV_ID_10G_BASE_T: |
|---|
| 30 | 32 | case I40E_DEV_ID_10G_BASE_T4: |
|---|
| 33 | + case I40E_DEV_ID_10G_BASE_T_BC: |
|---|
| 34 | + case I40E_DEV_ID_10G_B: |
|---|
| 35 | + case I40E_DEV_ID_10G_SFP: |
|---|
| 31 | 36 | case I40E_DEV_ID_20G_KR2: |
|---|
| 32 | 37 | case I40E_DEV_ID_20G_KR2_A: |
|---|
| 33 | 38 | case I40E_DEV_ID_25G_B: |
|---|
| 34 | 39 | case I40E_DEV_ID_25G_SFP28: |
|---|
| 40 | + case I40E_DEV_ID_X710_N3000: |
|---|
| 41 | + case I40E_DEV_ID_XXV710_N3000: |
|---|
| 35 | 42 | hw->mac.type = I40E_MAC_XL710; |
|---|
| 36 | 43 | break; |
|---|
| 37 | 44 | case I40E_DEV_ID_KX_X722: |
|---|
| .. | .. |
|---|
| 277 | 284 | void *buffer, u16 buf_len) |
|---|
| 278 | 285 | { |
|---|
| 279 | 286 | struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc; |
|---|
| 287 | + u32 effective_mask = hw->debug_mask & mask; |
|---|
| 288 | + char prefix[27]; |
|---|
| 280 | 289 | u16 len; |
|---|
| 281 | 290 | u8 *buf = (u8 *)buffer; |
|---|
| 282 | 291 | |
|---|
| 283 | | - if ((!(mask & hw->debug_mask)) || (desc == NULL)) |
|---|
| 292 | + if (!effective_mask || !desc) |
|---|
| 284 | 293 | return; |
|---|
| 285 | 294 | |
|---|
| 286 | 295 | len = le16_to_cpu(aq_desc->datalen); |
|---|
| 287 | 296 | |
|---|
| 288 | | - i40e_debug(hw, mask, |
|---|
| 297 | + i40e_debug(hw, mask & I40E_DEBUG_AQ_DESCRIPTOR, |
|---|
| 289 | 298 | "AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n", |
|---|
| 290 | 299 | le16_to_cpu(aq_desc->opcode), |
|---|
| 291 | 300 | le16_to_cpu(aq_desc->flags), |
|---|
| 292 | 301 | le16_to_cpu(aq_desc->datalen), |
|---|
| 293 | 302 | le16_to_cpu(aq_desc->retval)); |
|---|
| 294 | | - i40e_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n", |
|---|
| 303 | + i40e_debug(hw, mask & I40E_DEBUG_AQ_DESCRIPTOR, |
|---|
| 304 | + "\tcookie (h,l) 0x%08X 0x%08X\n", |
|---|
| 295 | 305 | le32_to_cpu(aq_desc->cookie_high), |
|---|
| 296 | 306 | le32_to_cpu(aq_desc->cookie_low)); |
|---|
| 297 | | - i40e_debug(hw, mask, "\tparam (0,1) 0x%08X 0x%08X\n", |
|---|
| 307 | + i40e_debug(hw, mask & I40E_DEBUG_AQ_DESCRIPTOR, |
|---|
| 308 | + "\tparam (0,1) 0x%08X 0x%08X\n", |
|---|
| 298 | 309 | le32_to_cpu(aq_desc->params.internal.param0), |
|---|
| 299 | 310 | le32_to_cpu(aq_desc->params.internal.param1)); |
|---|
| 300 | | - i40e_debug(hw, mask, "\taddr (h,l) 0x%08X 0x%08X\n", |
|---|
| 311 | + i40e_debug(hw, mask & I40E_DEBUG_AQ_DESCRIPTOR, |
|---|
| 312 | + "\taddr (h,l) 0x%08X 0x%08X\n", |
|---|
| 301 | 313 | le32_to_cpu(aq_desc->params.external.addr_high), |
|---|
| 302 | 314 | le32_to_cpu(aq_desc->params.external.addr_low)); |
|---|
| 303 | 315 | |
|---|
| 304 | | - if ((buffer != NULL) && (aq_desc->datalen != 0)) { |
|---|
| 316 | + if (buffer && buf_len != 0 && len != 0 && |
|---|
| 317 | + (effective_mask & I40E_DEBUG_AQ_DESC_BUFFER)) { |
|---|
| 305 | 318 | i40e_debug(hw, mask, "AQ CMD Buffer:\n"); |
|---|
| 306 | 319 | if (buf_len < len) |
|---|
| 307 | 320 | len = buf_len; |
|---|
| 308 | | - /* write the full 16-byte chunks */ |
|---|
| 309 | | - if (hw->debug_mask & mask) { |
|---|
| 310 | | - char prefix[27]; |
|---|
| 311 | 321 | |
|---|
| 312 | | - snprintf(prefix, sizeof(prefix), |
|---|
| 313 | | - "i40e %02x:%02x.%x: \t0x", |
|---|
| 314 | | - hw->bus.bus_id, |
|---|
| 315 | | - hw->bus.device, |
|---|
| 316 | | - hw->bus.func); |
|---|
| 322 | + snprintf(prefix, sizeof(prefix), |
|---|
| 323 | + "i40e %02x:%02x.%x: \t0x", |
|---|
| 324 | + hw->bus.bus_id, |
|---|
| 325 | + hw->bus.device, |
|---|
| 326 | + hw->bus.func); |
|---|
| 317 | 327 | |
|---|
| 318 | | - print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, |
|---|
| 319 | | - 16, 1, buf, len, false); |
|---|
| 320 | | - } |
|---|
| 328 | + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, |
|---|
| 329 | + 16, 1, buf, len, false); |
|---|
| 321 | 330 | } |
|---|
| 322 | 331 | } |
|---|
| 323 | 332 | |
|---|
| .. | .. |
|---|
| 926 | 935 | else |
|---|
| 927 | 936 | hw->pf_id = (u8)(func_rid & 0x7); |
|---|
| 928 | 937 | |
|---|
| 929 | | - if (hw->mac.type == I40E_MAC_X722) |
|---|
| 930 | | - hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE | |
|---|
| 931 | | - I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK; |
|---|
| 932 | | - |
|---|
| 933 | 938 | status = i40e_init_nvm(hw); |
|---|
| 934 | 939 | return status; |
|---|
| 935 | 940 | } |
|---|
| .. | .. |
|---|
| 1109 | 1114 | */ |
|---|
| 1110 | 1115 | pba_size--; |
|---|
| 1111 | 1116 | if (pba_num_size < (((u32)pba_size * 2) + 1)) { |
|---|
| 1112 | | - hw_dbg(hw, "Buffer to small for PBA data.\n"); |
|---|
| 1117 | + hw_dbg(hw, "Buffer too small for PBA data.\n"); |
|---|
| 1113 | 1118 | return I40E_ERR_PARAM; |
|---|
| 1114 | 1119 | } |
|---|
| 1115 | 1120 | |
|---|
| .. | .. |
|---|
| 1149 | 1154 | break; |
|---|
| 1150 | 1155 | case I40E_PHY_TYPE_100BASE_TX: |
|---|
| 1151 | 1156 | case I40E_PHY_TYPE_1000BASE_T: |
|---|
| 1157 | + case I40E_PHY_TYPE_2_5GBASE_T_LINK_STATUS: |
|---|
| 1158 | + case I40E_PHY_TYPE_5GBASE_T_LINK_STATUS: |
|---|
| 1152 | 1159 | case I40E_PHY_TYPE_10GBASE_T: |
|---|
| 1153 | 1160 | media = I40E_MEDIA_TYPE_BASET; |
|---|
| 1154 | 1161 | break; |
|---|
| .. | .. |
|---|
| 1432 | 1439 | u32 gpio_val = 0; |
|---|
| 1433 | 1440 | u32 port; |
|---|
| 1434 | 1441 | |
|---|
| 1435 | | - if (!hw->func_caps.led[idx]) |
|---|
| 1442 | + if (!I40E_IS_X710TL_DEVICE(hw->device_id) && |
|---|
| 1443 | + !hw->func_caps.led[idx]) |
|---|
| 1436 | 1444 | return 0; |
|---|
| 1437 | | - |
|---|
| 1438 | 1445 | gpio_val = rd32(hw, I40E_GLGEN_GPIO_CTL(idx)); |
|---|
| 1439 | 1446 | port = (gpio_val & I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK) >> |
|---|
| 1440 | 1447 | I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT; |
|---|
| .. | .. |
|---|
| 1449 | 1456 | return gpio_val; |
|---|
| 1450 | 1457 | } |
|---|
| 1451 | 1458 | |
|---|
| 1452 | | -#define I40E_COMBINED_ACTIVITY 0xA |
|---|
| 1453 | | -#define I40E_FILTER_ACTIVITY 0xE |
|---|
| 1454 | | -#define I40E_LINK_ACTIVITY 0xC |
|---|
| 1455 | | -#define I40E_MAC_ACTIVITY 0xD |
|---|
| 1459 | +#define I40E_FW_LED BIT(4) |
|---|
| 1460 | +#define I40E_LED_MODE_VALID (I40E_GLGEN_GPIO_CTL_LED_MODE_MASK >> \ |
|---|
| 1461 | + I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) |
|---|
| 1462 | + |
|---|
| 1456 | 1463 | #define I40E_LED0 22 |
|---|
| 1464 | + |
|---|
| 1465 | +#define I40E_PIN_FUNC_SDP 0x0 |
|---|
| 1466 | +#define I40E_PIN_FUNC_LED 0x1 |
|---|
| 1457 | 1467 | |
|---|
| 1458 | 1468 | /** |
|---|
| 1459 | 1469 | * i40e_led_get - return current on/off mode |
|---|
| .. | .. |
|---|
| 1466 | 1476 | **/ |
|---|
| 1467 | 1477 | u32 i40e_led_get(struct i40e_hw *hw) |
|---|
| 1468 | 1478 | { |
|---|
| 1469 | | - u32 current_mode = 0; |
|---|
| 1470 | 1479 | u32 mode = 0; |
|---|
| 1471 | 1480 | int i; |
|---|
| 1472 | 1481 | |
|---|
| .. | .. |
|---|
| 1478 | 1487 | |
|---|
| 1479 | 1488 | if (!gpio_val) |
|---|
| 1480 | 1489 | continue; |
|---|
| 1481 | | - |
|---|
| 1482 | | - /* ignore gpio LED src mode entries related to the activity |
|---|
| 1483 | | - * LEDs |
|---|
| 1484 | | - */ |
|---|
| 1485 | | - current_mode = ((gpio_val & I40E_GLGEN_GPIO_CTL_LED_MODE_MASK) |
|---|
| 1486 | | - >> I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT); |
|---|
| 1487 | | - switch (current_mode) { |
|---|
| 1488 | | - case I40E_COMBINED_ACTIVITY: |
|---|
| 1489 | | - case I40E_FILTER_ACTIVITY: |
|---|
| 1490 | | - case I40E_MAC_ACTIVITY: |
|---|
| 1491 | | - case I40E_LINK_ACTIVITY: |
|---|
| 1492 | | - continue; |
|---|
| 1493 | | - default: |
|---|
| 1494 | | - break; |
|---|
| 1495 | | - } |
|---|
| 1496 | 1490 | |
|---|
| 1497 | 1491 | mode = (gpio_val & I40E_GLGEN_GPIO_CTL_LED_MODE_MASK) >> |
|---|
| 1498 | 1492 | I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT; |
|---|
| .. | .. |
|---|
| 1513 | 1507 | **/ |
|---|
| 1514 | 1508 | void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink) |
|---|
| 1515 | 1509 | { |
|---|
| 1516 | | - u32 current_mode = 0; |
|---|
| 1517 | 1510 | int i; |
|---|
| 1518 | 1511 | |
|---|
| 1519 | | - if (mode & 0xfffffff0) |
|---|
| 1512 | + if (mode & ~I40E_LED_MODE_VALID) { |
|---|
| 1520 | 1513 | hw_dbg(hw, "invalid mode passed in %X\n", mode); |
|---|
| 1514 | + return; |
|---|
| 1515 | + } |
|---|
| 1521 | 1516 | |
|---|
| 1522 | 1517 | /* as per the documentation GPIO 22-29 are the LED |
|---|
| 1523 | 1518 | * GPIO pins named LED0..LED7 |
|---|
| .. | .. |
|---|
| 1528 | 1523 | if (!gpio_val) |
|---|
| 1529 | 1524 | continue; |
|---|
| 1530 | 1525 | |
|---|
| 1531 | | - /* ignore gpio LED src mode entries related to the activity |
|---|
| 1532 | | - * LEDs |
|---|
| 1533 | | - */ |
|---|
| 1534 | | - current_mode = ((gpio_val & I40E_GLGEN_GPIO_CTL_LED_MODE_MASK) |
|---|
| 1535 | | - >> I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT); |
|---|
| 1536 | | - switch (current_mode) { |
|---|
| 1537 | | - case I40E_COMBINED_ACTIVITY: |
|---|
| 1538 | | - case I40E_FILTER_ACTIVITY: |
|---|
| 1539 | | - case I40E_MAC_ACTIVITY: |
|---|
| 1540 | | - case I40E_LINK_ACTIVITY: |
|---|
| 1541 | | - continue; |
|---|
| 1542 | | - default: |
|---|
| 1543 | | - break; |
|---|
| 1544 | | - } |
|---|
| 1526 | + if (I40E_IS_X710TL_DEVICE(hw->device_id)) { |
|---|
| 1527 | + u32 pin_func = 0; |
|---|
| 1545 | 1528 | |
|---|
| 1529 | + if (mode & I40E_FW_LED) |
|---|
| 1530 | + pin_func = I40E_PIN_FUNC_SDP; |
|---|
| 1531 | + else |
|---|
| 1532 | + pin_func = I40E_PIN_FUNC_LED; |
|---|
| 1533 | + |
|---|
| 1534 | + gpio_val &= ~I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK; |
|---|
| 1535 | + gpio_val |= ((pin_func << |
|---|
| 1536 | + I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT) & |
|---|
| 1537 | + I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK); |
|---|
| 1538 | + } |
|---|
| 1546 | 1539 | gpio_val &= ~I40E_GLGEN_GPIO_CTL_LED_MODE_MASK; |
|---|
| 1547 | 1540 | /* this & is a bit of paranoia, but serves as a range check */ |
|---|
| 1548 | 1541 | gpio_val |= ((mode << I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) & |
|---|
| .. | .. |
|---|
| 1602 | 1595 | status = i40e_asq_send_command(hw, &desc, abilities, |
|---|
| 1603 | 1596 | abilities_size, cmd_details); |
|---|
| 1604 | 1597 | |
|---|
| 1605 | | - if (status) |
|---|
| 1606 | | - break; |
|---|
| 1607 | | - |
|---|
| 1608 | | - if (hw->aq.asq_last_status == I40E_AQ_RC_EIO) { |
|---|
| 1598 | + switch (hw->aq.asq_last_status) { |
|---|
| 1599 | + case I40E_AQ_RC_EIO: |
|---|
| 1609 | 1600 | status = I40E_ERR_UNKNOWN_PHY; |
|---|
| 1610 | 1601 | break; |
|---|
| 1611 | | - } else if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN) { |
|---|
| 1602 | + case I40E_AQ_RC_EAGAIN: |
|---|
| 1612 | 1603 | usleep_range(1000, 2000); |
|---|
| 1613 | 1604 | total_delay++; |
|---|
| 1614 | 1605 | status = I40E_ERR_TIMEOUT; |
|---|
| 1606 | + break; |
|---|
| 1607 | + /* also covers I40E_AQ_RC_OK */ |
|---|
| 1608 | + default: |
|---|
| 1609 | + break; |
|---|
| 1615 | 1610 | } |
|---|
| 1616 | | - } while ((hw->aq.asq_last_status != I40E_AQ_RC_OK) && |
|---|
| 1617 | | - (total_delay < max_delay)); |
|---|
| 1611 | + |
|---|
| 1612 | + } while ((hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN) && |
|---|
| 1613 | + (total_delay < max_delay)); |
|---|
| 1618 | 1614 | |
|---|
| 1619 | 1615 | if (status) |
|---|
| 1620 | 1616 | return status; |
|---|
| .. | .. |
|---|
| 1897 | 1893 | hw->aq.fw_min_ver < 40)) && hw_link_info->phy_type == 0xE) |
|---|
| 1898 | 1894 | hw_link_info->phy_type = I40E_PHY_TYPE_10GBASE_SFPP_CU; |
|---|
| 1899 | 1895 | |
|---|
| 1900 | | - if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && |
|---|
| 1901 | | - hw->aq.api_min_ver >= 7) { |
|---|
| 1896 | + if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE && |
|---|
| 1897 | + hw->mac.type != I40E_MAC_X722) { |
|---|
| 1902 | 1898 | __le32 tmp; |
|---|
| 1903 | 1899 | |
|---|
| 1904 | 1900 | memcpy(&tmp, resp->link_type, sizeof(tmp)); |
|---|
| .. | .. |
|---|
| 2611 | 2607 | if (status) |
|---|
| 2612 | 2608 | return status; |
|---|
| 2613 | 2609 | |
|---|
| 2614 | | - hw->phy.link_info.req_fec_info = |
|---|
| 2615 | | - abilities.fec_cfg_curr_mod_ext_info & |
|---|
| 2616 | | - (I40E_AQ_REQUEST_FEC_KR | I40E_AQ_REQUEST_FEC_RS); |
|---|
| 2610 | + if (abilities.fec_cfg_curr_mod_ext_info & |
|---|
| 2611 | + I40E_AQ_ENABLE_FEC_AUTO) |
|---|
| 2612 | + hw->phy.link_info.req_fec_info = |
|---|
| 2613 | + (I40E_AQ_REQUEST_FEC_KR | |
|---|
| 2614 | + I40E_AQ_REQUEST_FEC_RS); |
|---|
| 2615 | + else |
|---|
| 2616 | + hw->phy.link_info.req_fec_info = |
|---|
| 2617 | + abilities.fec_cfg_curr_mod_ext_info & |
|---|
| 2618 | + (I40E_AQ_REQUEST_FEC_KR | |
|---|
| 2619 | + I40E_AQ_REQUEST_FEC_RS); |
|---|
| 2617 | 2620 | |
|---|
| 2618 | 2621 | memcpy(hw->phy.link_info.module_type, &abilities.module_type, |
|---|
| 2619 | 2622 | sizeof(hw->phy.link_info.module_type)); |
|---|
| .. | .. |
|---|
| 3687 | 3690 | } |
|---|
| 3688 | 3691 | |
|---|
| 3689 | 3692 | /** |
|---|
| 3693 | + * i40e_aq_restore_lldp |
|---|
| 3694 | + * @hw: pointer to the hw struct |
|---|
| 3695 | + * @setting: pointer to factory setting variable or NULL |
|---|
| 3696 | + * @restore: True if factory settings should be restored |
|---|
| 3697 | + * @cmd_details: pointer to command details structure or NULL |
|---|
| 3698 | + * |
|---|
| 3699 | + * Restore LLDP Agent factory settings if @restore set to True. In other case |
|---|
| 3700 | + * only returns factory setting in AQ response. |
|---|
| 3701 | + **/ |
|---|
| 3702 | +enum i40e_status_code |
|---|
| 3703 | +i40e_aq_restore_lldp(struct i40e_hw *hw, u8 *setting, bool restore, |
|---|
| 3704 | + struct i40e_asq_cmd_details *cmd_details) |
|---|
| 3705 | +{ |
|---|
| 3706 | + struct i40e_aq_desc desc; |
|---|
| 3707 | + struct i40e_aqc_lldp_restore *cmd = |
|---|
| 3708 | + (struct i40e_aqc_lldp_restore *)&desc.params.raw; |
|---|
| 3709 | + i40e_status status; |
|---|
| 3710 | + |
|---|
| 3711 | + if (!(hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT)) { |
|---|
| 3712 | + i40e_debug(hw, I40E_DEBUG_ALL, |
|---|
| 3713 | + "Restore LLDP not supported by current FW version.\n"); |
|---|
| 3714 | + return I40E_ERR_DEVICE_NOT_SUPPORTED; |
|---|
| 3715 | + } |
|---|
| 3716 | + |
|---|
| 3717 | + i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_lldp_restore); |
|---|
| 3718 | + |
|---|
| 3719 | + if (restore) |
|---|
| 3720 | + cmd->command |= I40E_AQ_LLDP_AGENT_RESTORE; |
|---|
| 3721 | + |
|---|
| 3722 | + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); |
|---|
| 3723 | + |
|---|
| 3724 | + if (setting) |
|---|
| 3725 | + *setting = cmd->command & 1; |
|---|
| 3726 | + |
|---|
| 3727 | + return status; |
|---|
| 3728 | +} |
|---|
| 3729 | + |
|---|
| 3730 | +/** |
|---|
| 3690 | 3731 | * i40e_aq_stop_lldp |
|---|
| 3691 | 3732 | * @hw: pointer to the hw struct |
|---|
| 3692 | 3733 | * @shutdown_agent: True if LLDP Agent needs to be Shutdown |
|---|
| 3734 | + * @persist: True if stop of LLDP should be persistent across power cycles |
|---|
| 3693 | 3735 | * @cmd_details: pointer to command details structure or NULL |
|---|
| 3694 | 3736 | * |
|---|
| 3695 | 3737 | * Stop or Shutdown the embedded LLDP Agent |
|---|
| 3696 | 3738 | **/ |
|---|
| 3697 | 3739 | i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent, |
|---|
| 3740 | + bool persist, |
|---|
| 3698 | 3741 | struct i40e_asq_cmd_details *cmd_details) |
|---|
| 3699 | 3742 | { |
|---|
| 3700 | 3743 | struct i40e_aq_desc desc; |
|---|
| .. | .. |
|---|
| 3707 | 3750 | if (shutdown_agent) |
|---|
| 3708 | 3751 | cmd->command |= I40E_AQ_LLDP_AGENT_SHUTDOWN; |
|---|
| 3709 | 3752 | |
|---|
| 3753 | + if (persist) { |
|---|
| 3754 | + if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) |
|---|
| 3755 | + cmd->command |= I40E_AQ_LLDP_AGENT_STOP_PERSIST; |
|---|
| 3756 | + else |
|---|
| 3757 | + i40e_debug(hw, I40E_DEBUG_ALL, |
|---|
| 3758 | + "Persistent Stop LLDP not supported by current FW version.\n"); |
|---|
| 3759 | + } |
|---|
| 3760 | + |
|---|
| 3710 | 3761 | status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); |
|---|
| 3711 | 3762 | |
|---|
| 3712 | 3763 | return status; |
|---|
| .. | .. |
|---|
| 3715 | 3766 | /** |
|---|
| 3716 | 3767 | * i40e_aq_start_lldp |
|---|
| 3717 | 3768 | * @hw: pointer to the hw struct |
|---|
| 3718 | | - * @buff: buffer for result |
|---|
| 3719 | | - * @buff_size: buffer size |
|---|
| 3769 | + * @persist: True if start of LLDP should be persistent across power cycles |
|---|
| 3720 | 3770 | * @cmd_details: pointer to command details structure or NULL |
|---|
| 3721 | 3771 | * |
|---|
| 3722 | 3772 | * Start the embedded LLDP Agent on all ports. |
|---|
| 3723 | 3773 | **/ |
|---|
| 3724 | | -i40e_status i40e_aq_start_lldp(struct i40e_hw *hw, |
|---|
| 3725 | | - struct i40e_asq_cmd_details *cmd_details) |
|---|
| 3774 | +i40e_status i40e_aq_start_lldp(struct i40e_hw *hw, bool persist, |
|---|
| 3775 | + struct i40e_asq_cmd_details *cmd_details) |
|---|
| 3726 | 3776 | { |
|---|
| 3727 | 3777 | struct i40e_aq_desc desc; |
|---|
| 3728 | 3778 | struct i40e_aqc_lldp_start *cmd = |
|---|
| .. | .. |
|---|
| 3732 | 3782 | i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_lldp_start); |
|---|
| 3733 | 3783 | |
|---|
| 3734 | 3784 | cmd->command = I40E_AQ_LLDP_AGENT_START; |
|---|
| 3785 | + |
|---|
| 3786 | + if (persist) { |
|---|
| 3787 | + if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) |
|---|
| 3788 | + cmd->command |= I40E_AQ_LLDP_AGENT_START_PERSIST; |
|---|
| 3789 | + else |
|---|
| 3790 | + i40e_debug(hw, I40E_DEBUG_ALL, |
|---|
| 3791 | + "Persistent Start LLDP not supported by current FW version.\n"); |
|---|
| 3792 | + } |
|---|
| 3793 | + |
|---|
| 3735 | 3794 | status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); |
|---|
| 3736 | 3795 | |
|---|
| 3737 | 3796 | return status; |
|---|
| .. | .. |
|---|
| 3752 | 3811 | struct i40e_aqc_set_dcb_parameters *cmd = |
|---|
| 3753 | 3812 | (struct i40e_aqc_set_dcb_parameters *)&desc.params.raw; |
|---|
| 3754 | 3813 | i40e_status status; |
|---|
| 3814 | + |
|---|
| 3815 | + if (!(hw->flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE)) |
|---|
| 3816 | + return I40E_ERR_DEVICE_NOT_SUPPORTED; |
|---|
| 3755 | 3817 | |
|---|
| 3756 | 3818 | i40e_fill_default_direct_cmd_desc(&desc, |
|---|
| 3757 | 3819 | i40e_aqc_opc_set_dcb_parameters); |
|---|
| .. | .. |
|---|
| 4862 | 4924 | status = i40e_write_phy_register_clause22(hw, reg, phy_addr, |
|---|
| 4863 | 4925 | value); |
|---|
| 4864 | 4926 | break; |
|---|
| 4927 | + case I40E_DEV_ID_5G_BASE_T_BC: |
|---|
| 4865 | 4928 | case I40E_DEV_ID_10G_BASE_T: |
|---|
| 4866 | 4929 | case I40E_DEV_ID_10G_BASE_T4: |
|---|
| 4930 | + case I40E_DEV_ID_10G_BASE_T_BC: |
|---|
| 4867 | 4931 | case I40E_DEV_ID_10G_BASE_T_X722: |
|---|
| 4868 | 4932 | case I40E_DEV_ID_25G_B: |
|---|
| 4869 | 4933 | case I40E_DEV_ID_25G_SFP28: |
|---|
| .. | .. |
|---|
| 4898 | 4962 | status = i40e_read_phy_register_clause22(hw, reg, phy_addr, |
|---|
| 4899 | 4963 | value); |
|---|
| 4900 | 4964 | break; |
|---|
| 4965 | + case I40E_DEV_ID_5G_BASE_T_BC: |
|---|
| 4901 | 4966 | case I40E_DEV_ID_10G_BASE_T: |
|---|
| 4902 | 4967 | case I40E_DEV_ID_10G_BASE_T4: |
|---|
| 4968 | + case I40E_DEV_ID_10G_BASE_T_BC: |
|---|
| 4903 | 4969 | case I40E_DEV_ID_10G_BASE_T_X722: |
|---|
| 4904 | 4970 | case I40E_DEV_ID_25G_B: |
|---|
| 4905 | 4971 | case I40E_DEV_ID_25G_SFP28: |
|---|
| .. | .. |
|---|
| 5022 | 5088 | status = |
|---|
| 5023 | 5089 | i40e_aq_get_phy_register(hw, |
|---|
| 5024 | 5090 | I40E_AQ_PHY_REG_ACCESS_EXTERNAL, |
|---|
| 5025 | | - I40E_PHY_COM_REG_PAGE, |
|---|
| 5091 | + I40E_PHY_COM_REG_PAGE, true, |
|---|
| 5026 | 5092 | I40E_PHY_LED_PROV_REG_1, |
|---|
| 5027 | 5093 | reg_val, NULL); |
|---|
| 5028 | 5094 | } else { |
|---|
| .. | .. |
|---|
| 5055 | 5121 | status = |
|---|
| 5056 | 5122 | i40e_aq_set_phy_register(hw, |
|---|
| 5057 | 5123 | I40E_AQ_PHY_REG_ACCESS_EXTERNAL, |
|---|
| 5058 | | - I40E_PHY_COM_REG_PAGE, |
|---|
| 5124 | + I40E_PHY_COM_REG_PAGE, true, |
|---|
| 5059 | 5125 | I40E_PHY_LED_PROV_REG_1, |
|---|
| 5060 | 5126 | reg_val, NULL); |
|---|
| 5061 | 5127 | } else { |
|---|
| .. | .. |
|---|
| 5094 | 5160 | status = |
|---|
| 5095 | 5161 | i40e_aq_get_phy_register(hw, |
|---|
| 5096 | 5162 | I40E_AQ_PHY_REG_ACCESS_EXTERNAL, |
|---|
| 5097 | | - I40E_PHY_COM_REG_PAGE, |
|---|
| 5163 | + I40E_PHY_COM_REG_PAGE, true, |
|---|
| 5098 | 5164 | I40E_PHY_LED_PROV_REG_1, |
|---|
| 5099 | 5165 | ®_val_aq, NULL); |
|---|
| 5100 | 5166 | if (status == I40E_SUCCESS) |
|---|
| .. | .. |
|---|
| 5299 | 5365 | } |
|---|
| 5300 | 5366 | |
|---|
| 5301 | 5367 | /** |
|---|
| 5302 | | - * i40e_aq_set_phy_register |
|---|
| 5368 | + * i40e_mdio_if_number_selection - MDIO I/F number selection |
|---|
| 5369 | + * @hw: pointer to the hw struct |
|---|
| 5370 | + * @set_mdio: use MDIO I/F number specified by mdio_num |
|---|
| 5371 | + * @mdio_num: MDIO I/F number |
|---|
| 5372 | + * @cmd: pointer to PHY Register command structure |
|---|
| 5373 | + **/ |
|---|
| 5374 | +static void i40e_mdio_if_number_selection(struct i40e_hw *hw, bool set_mdio, |
|---|
| 5375 | + u8 mdio_num, |
|---|
| 5376 | + struct i40e_aqc_phy_register_access *cmd) |
|---|
| 5377 | +{ |
|---|
| 5378 | + if (set_mdio && cmd->phy_interface == I40E_AQ_PHY_REG_ACCESS_EXTERNAL) { |
|---|
| 5379 | + if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED) |
|---|
| 5380 | + cmd->cmd_flags |= |
|---|
| 5381 | + I40E_AQ_PHY_REG_ACCESS_SET_MDIO_IF_NUMBER | |
|---|
| 5382 | + ((mdio_num << |
|---|
| 5383 | + I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_SHIFT) & |
|---|
| 5384 | + I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_MASK); |
|---|
| 5385 | + else |
|---|
| 5386 | + i40e_debug(hw, I40E_DEBUG_PHY, |
|---|
| 5387 | + "MDIO I/F number selection not supported by current FW version.\n"); |
|---|
| 5388 | + } |
|---|
| 5389 | +} |
|---|
| 5390 | + |
|---|
| 5391 | +/** |
|---|
| 5392 | + * i40e_aq_set_phy_register_ext |
|---|
| 5303 | 5393 | * @hw: pointer to the hw struct |
|---|
| 5304 | 5394 | * @phy_select: select which phy should be accessed |
|---|
| 5305 | 5395 | * @dev_addr: PHY device address |
|---|
| 5396 | + * @page_change: flag to indicate if phy page should be updated |
|---|
| 5397 | + * @set_mdio: use MDIO I/F number specified by mdio_num |
|---|
| 5398 | + * @mdio_num: MDIO I/F number |
|---|
| 5306 | 5399 | * @reg_addr: PHY register address |
|---|
| 5307 | 5400 | * @reg_val: new register value |
|---|
| 5308 | 5401 | * @cmd_details: pointer to command details structure or NULL |
|---|
| 5309 | 5402 | * |
|---|
| 5310 | 5403 | * Write the external PHY register. |
|---|
| 5404 | + * NOTE: In common cases MDIO I/F number should not be changed, thats why you |
|---|
| 5405 | + * may use simple wrapper i40e_aq_set_phy_register. |
|---|
| 5311 | 5406 | **/ |
|---|
| 5312 | | -i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw, |
|---|
| 5313 | | - u8 phy_select, u8 dev_addr, |
|---|
| 5314 | | - u32 reg_addr, u32 reg_val, |
|---|
| 5315 | | - struct i40e_asq_cmd_details *cmd_details) |
|---|
| 5407 | +enum i40e_status_code i40e_aq_set_phy_register_ext(struct i40e_hw *hw, |
|---|
| 5408 | + u8 phy_select, u8 dev_addr, bool page_change, |
|---|
| 5409 | + bool set_mdio, u8 mdio_num, |
|---|
| 5410 | + u32 reg_addr, u32 reg_val, |
|---|
| 5411 | + struct i40e_asq_cmd_details *cmd_details) |
|---|
| 5316 | 5412 | { |
|---|
| 5317 | 5413 | struct i40e_aq_desc desc; |
|---|
| 5318 | 5414 | struct i40e_aqc_phy_register_access *cmd = |
|---|
| .. | .. |
|---|
| 5327 | 5423 | cmd->reg_address = cpu_to_le32(reg_addr); |
|---|
| 5328 | 5424 | cmd->reg_value = cpu_to_le32(reg_val); |
|---|
| 5329 | 5425 | |
|---|
| 5426 | + i40e_mdio_if_number_selection(hw, set_mdio, mdio_num, cmd); |
|---|
| 5427 | + |
|---|
| 5428 | + if (!page_change) |
|---|
| 5429 | + cmd->cmd_flags = I40E_AQ_PHY_REG_ACCESS_DONT_CHANGE_QSFP_PAGE; |
|---|
| 5430 | + |
|---|
| 5330 | 5431 | status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); |
|---|
| 5331 | 5432 | |
|---|
| 5332 | 5433 | return status; |
|---|
| 5333 | 5434 | } |
|---|
| 5334 | 5435 | |
|---|
| 5335 | 5436 | /** |
|---|
| 5336 | | - * i40e_aq_get_phy_register |
|---|
| 5437 | + * i40e_aq_get_phy_register_ext |
|---|
| 5337 | 5438 | * @hw: pointer to the hw struct |
|---|
| 5338 | 5439 | * @phy_select: select which phy should be accessed |
|---|
| 5339 | 5440 | * @dev_addr: PHY device address |
|---|
| 5441 | + * @page_change: flag to indicate if phy page should be updated |
|---|
| 5442 | + * @set_mdio: use MDIO I/F number specified by mdio_num |
|---|
| 5443 | + * @mdio_num: MDIO I/F number |
|---|
| 5340 | 5444 | * @reg_addr: PHY register address |
|---|
| 5341 | 5445 | * @reg_val: read register value |
|---|
| 5342 | 5446 | * @cmd_details: pointer to command details structure or NULL |
|---|
| 5343 | 5447 | * |
|---|
| 5344 | 5448 | * Read the external PHY register. |
|---|
| 5449 | + * NOTE: In common cases MDIO I/F number should not be changed, thats why you |
|---|
| 5450 | + * may use simple wrapper i40e_aq_get_phy_register. |
|---|
| 5345 | 5451 | **/ |
|---|
| 5346 | | -i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw, |
|---|
| 5347 | | - u8 phy_select, u8 dev_addr, |
|---|
| 5348 | | - u32 reg_addr, u32 *reg_val, |
|---|
| 5349 | | - struct i40e_asq_cmd_details *cmd_details) |
|---|
| 5452 | +enum i40e_status_code i40e_aq_get_phy_register_ext(struct i40e_hw *hw, |
|---|
| 5453 | + u8 phy_select, u8 dev_addr, bool page_change, |
|---|
| 5454 | + bool set_mdio, u8 mdio_num, |
|---|
| 5455 | + u32 reg_addr, u32 *reg_val, |
|---|
| 5456 | + struct i40e_asq_cmd_details *cmd_details) |
|---|
| 5350 | 5457 | { |
|---|
| 5351 | 5458 | struct i40e_aq_desc desc; |
|---|
| 5352 | 5459 | struct i40e_aqc_phy_register_access *cmd = |
|---|
| .. | .. |
|---|
| 5359 | 5466 | cmd->phy_interface = phy_select; |
|---|
| 5360 | 5467 | cmd->dev_address = dev_addr; |
|---|
| 5361 | 5468 | cmd->reg_address = cpu_to_le32(reg_addr); |
|---|
| 5469 | + |
|---|
| 5470 | + i40e_mdio_if_number_selection(hw, set_mdio, mdio_num, cmd); |
|---|
| 5471 | + |
|---|
| 5472 | + if (!page_change) |
|---|
| 5473 | + cmd->cmd_flags = I40E_AQ_PHY_REG_ACCESS_DONT_CHANGE_QSFP_PAGE; |
|---|
| 5362 | 5474 | |
|---|
| 5363 | 5475 | status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); |
|---|
| 5364 | 5476 | if (!status) |
|---|
| .. | .. |
|---|
| 5475 | 5587 | return NULL; |
|---|
| 5476 | 5588 | } |
|---|
| 5477 | 5589 | |
|---|
| 5590 | +/* Get section table in profile */ |
|---|
| 5591 | +#define I40E_SECTION_TABLE(profile, sec_tbl) \ |
|---|
| 5592 | + do { \ |
|---|
| 5593 | + struct i40e_profile_segment *p = (profile); \ |
|---|
| 5594 | + u32 count; \ |
|---|
| 5595 | + u32 *nvm; \ |
|---|
| 5596 | + count = p->device_table_count; \ |
|---|
| 5597 | + nvm = (u32 *)&p->device_table[count]; \ |
|---|
| 5598 | + sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1]; \ |
|---|
| 5599 | + } while (0) |
|---|
| 5600 | + |
|---|
| 5601 | +/* Get section header in profile */ |
|---|
| 5602 | +#define I40E_SECTION_HEADER(profile, offset) \ |
|---|
| 5603 | + (struct i40e_profile_section_header *)((u8 *)(profile) + (offset)) |
|---|
| 5604 | + |
|---|
| 5605 | +/** |
|---|
| 5606 | + * i40e_find_section_in_profile |
|---|
| 5607 | + * @section_type: the section type to search for (i.e., SECTION_TYPE_NOTE) |
|---|
| 5608 | + * @profile: pointer to the i40e segment header to be searched |
|---|
| 5609 | + * |
|---|
| 5610 | + * This function searches i40e segment for a particular section type. On |
|---|
| 5611 | + * success it returns a pointer to the section header, otherwise it will |
|---|
| 5612 | + * return NULL. |
|---|
| 5613 | + **/ |
|---|
| 5614 | +struct i40e_profile_section_header * |
|---|
| 5615 | +i40e_find_section_in_profile(u32 section_type, |
|---|
| 5616 | + struct i40e_profile_segment *profile) |
|---|
| 5617 | +{ |
|---|
| 5618 | + struct i40e_profile_section_header *sec; |
|---|
| 5619 | + struct i40e_section_table *sec_tbl; |
|---|
| 5620 | + u32 sec_off; |
|---|
| 5621 | + u32 i; |
|---|
| 5622 | + |
|---|
| 5623 | + if (profile->header.type != SEGMENT_TYPE_I40E) |
|---|
| 5624 | + return NULL; |
|---|
| 5625 | + |
|---|
| 5626 | + I40E_SECTION_TABLE(profile, sec_tbl); |
|---|
| 5627 | + |
|---|
| 5628 | + for (i = 0; i < sec_tbl->section_count; i++) { |
|---|
| 5629 | + sec_off = sec_tbl->section_offset[i]; |
|---|
| 5630 | + sec = I40E_SECTION_HEADER(profile, sec_off); |
|---|
| 5631 | + if (sec->section.type == section_type) |
|---|
| 5632 | + return sec; |
|---|
| 5633 | + } |
|---|
| 5634 | + |
|---|
| 5635 | + return NULL; |
|---|
| 5636 | +} |
|---|
| 5637 | + |
|---|
| 5638 | +/** |
|---|
| 5639 | + * i40e_ddp_exec_aq_section - Execute generic AQ for DDP |
|---|
| 5640 | + * @hw: pointer to the hw struct |
|---|
| 5641 | + * @aq: command buffer containing all data to execute AQ |
|---|
| 5642 | + **/ |
|---|
| 5643 | +static enum |
|---|
| 5644 | +i40e_status_code i40e_ddp_exec_aq_section(struct i40e_hw *hw, |
|---|
| 5645 | + struct i40e_profile_aq_section *aq) |
|---|
| 5646 | +{ |
|---|
| 5647 | + i40e_status status; |
|---|
| 5648 | + struct i40e_aq_desc desc; |
|---|
| 5649 | + u8 *msg = NULL; |
|---|
| 5650 | + u16 msglen; |
|---|
| 5651 | + |
|---|
| 5652 | + i40e_fill_default_direct_cmd_desc(&desc, aq->opcode); |
|---|
| 5653 | + desc.flags |= cpu_to_le16(aq->flags); |
|---|
| 5654 | + memcpy(desc.params.raw, aq->param, sizeof(desc.params.raw)); |
|---|
| 5655 | + |
|---|
| 5656 | + msglen = aq->datalen; |
|---|
| 5657 | + if (msglen) { |
|---|
| 5658 | + desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | |
|---|
| 5659 | + I40E_AQ_FLAG_RD)); |
|---|
| 5660 | + if (msglen > I40E_AQ_LARGE_BUF) |
|---|
| 5661 | + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB); |
|---|
| 5662 | + desc.datalen = cpu_to_le16(msglen); |
|---|
| 5663 | + msg = &aq->data[0]; |
|---|
| 5664 | + } |
|---|
| 5665 | + |
|---|
| 5666 | + status = i40e_asq_send_command(hw, &desc, msg, msglen, NULL); |
|---|
| 5667 | + |
|---|
| 5668 | + if (status) { |
|---|
| 5669 | + i40e_debug(hw, I40E_DEBUG_PACKAGE, |
|---|
| 5670 | + "unable to exec DDP AQ opcode %u, error %d\n", |
|---|
| 5671 | + aq->opcode, status); |
|---|
| 5672 | + return status; |
|---|
| 5673 | + } |
|---|
| 5674 | + |
|---|
| 5675 | + /* copy returned desc to aq_buf */ |
|---|
| 5676 | + memcpy(aq->param, desc.params.raw, sizeof(desc.params.raw)); |
|---|
| 5677 | + |
|---|
| 5678 | + return 0; |
|---|
| 5679 | +} |
|---|
| 5680 | + |
|---|
| 5681 | +/** |
|---|
| 5682 | + * i40e_validate_profile |
|---|
| 5683 | + * @hw: pointer to the hardware structure |
|---|
| 5684 | + * @profile: pointer to the profile segment of the package to be validated |
|---|
| 5685 | + * @track_id: package tracking id |
|---|
| 5686 | + * @rollback: flag if the profile is for rollback. |
|---|
| 5687 | + * |
|---|
| 5688 | + * Validates supported devices and profile's sections. |
|---|
| 5689 | + */ |
|---|
| 5690 | +static enum i40e_status_code |
|---|
| 5691 | +i40e_validate_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile, |
|---|
| 5692 | + u32 track_id, bool rollback) |
|---|
| 5693 | +{ |
|---|
| 5694 | + struct i40e_profile_section_header *sec = NULL; |
|---|
| 5695 | + i40e_status status = 0; |
|---|
| 5696 | + struct i40e_section_table *sec_tbl; |
|---|
| 5697 | + u32 vendor_dev_id; |
|---|
| 5698 | + u32 dev_cnt; |
|---|
| 5699 | + u32 sec_off; |
|---|
| 5700 | + u32 i; |
|---|
| 5701 | + |
|---|
| 5702 | + if (track_id == I40E_DDP_TRACKID_INVALID) { |
|---|
| 5703 | + i40e_debug(hw, I40E_DEBUG_PACKAGE, "Invalid track_id\n"); |
|---|
| 5704 | + return I40E_NOT_SUPPORTED; |
|---|
| 5705 | + } |
|---|
| 5706 | + |
|---|
| 5707 | + dev_cnt = profile->device_table_count; |
|---|
| 5708 | + for (i = 0; i < dev_cnt; i++) { |
|---|
| 5709 | + vendor_dev_id = profile->device_table[i].vendor_dev_id; |
|---|
| 5710 | + if ((vendor_dev_id >> 16) == PCI_VENDOR_ID_INTEL && |
|---|
| 5711 | + hw->device_id == (vendor_dev_id & 0xFFFF)) |
|---|
| 5712 | + break; |
|---|
| 5713 | + } |
|---|
| 5714 | + if (dev_cnt && i == dev_cnt) { |
|---|
| 5715 | + i40e_debug(hw, I40E_DEBUG_PACKAGE, |
|---|
| 5716 | + "Device doesn't support DDP\n"); |
|---|
| 5717 | + return I40E_ERR_DEVICE_NOT_SUPPORTED; |
|---|
| 5718 | + } |
|---|
| 5719 | + |
|---|
| 5720 | + I40E_SECTION_TABLE(profile, sec_tbl); |
|---|
| 5721 | + |
|---|
| 5722 | + /* Validate sections types */ |
|---|
| 5723 | + for (i = 0; i < sec_tbl->section_count; i++) { |
|---|
| 5724 | + sec_off = sec_tbl->section_offset[i]; |
|---|
| 5725 | + sec = I40E_SECTION_HEADER(profile, sec_off); |
|---|
| 5726 | + if (rollback) { |
|---|
| 5727 | + if (sec->section.type == SECTION_TYPE_MMIO || |
|---|
| 5728 | + sec->section.type == SECTION_TYPE_AQ || |
|---|
| 5729 | + sec->section.type == SECTION_TYPE_RB_AQ) { |
|---|
| 5730 | + i40e_debug(hw, I40E_DEBUG_PACKAGE, |
|---|
| 5731 | + "Not a roll-back package\n"); |
|---|
| 5732 | + return I40E_NOT_SUPPORTED; |
|---|
| 5733 | + } |
|---|
| 5734 | + } else { |
|---|
| 5735 | + if (sec->section.type == SECTION_TYPE_RB_AQ || |
|---|
| 5736 | + sec->section.type == SECTION_TYPE_RB_MMIO) { |
|---|
| 5737 | + i40e_debug(hw, I40E_DEBUG_PACKAGE, |
|---|
| 5738 | + "Not an original package\n"); |
|---|
| 5739 | + return I40E_NOT_SUPPORTED; |
|---|
| 5740 | + } |
|---|
| 5741 | + } |
|---|
| 5742 | + } |
|---|
| 5743 | + |
|---|
| 5744 | + return status; |
|---|
| 5745 | +} |
|---|
| 5746 | + |
|---|
| 5478 | 5747 | /** |
|---|
| 5479 | 5748 | * i40e_write_profile |
|---|
| 5480 | 5749 | * @hw: pointer to the hardware structure |
|---|
| .. | .. |
|---|
| 5490 | 5759 | i40e_status status = 0; |
|---|
| 5491 | 5760 | struct i40e_section_table *sec_tbl; |
|---|
| 5492 | 5761 | struct i40e_profile_section_header *sec = NULL; |
|---|
| 5493 | | - u32 dev_cnt; |
|---|
| 5494 | | - u32 vendor_dev_id; |
|---|
| 5495 | | - u32 *nvm; |
|---|
| 5762 | + struct i40e_profile_aq_section *ddp_aq; |
|---|
| 5496 | 5763 | u32 section_size = 0; |
|---|
| 5497 | 5764 | u32 offset = 0, info = 0; |
|---|
| 5765 | + u32 sec_off; |
|---|
| 5498 | 5766 | u32 i; |
|---|
| 5499 | 5767 | |
|---|
| 5500 | | - dev_cnt = profile->device_table_count; |
|---|
| 5768 | + status = i40e_validate_profile(hw, profile, track_id, false); |
|---|
| 5769 | + if (status) |
|---|
| 5770 | + return status; |
|---|
| 5501 | 5771 | |
|---|
| 5502 | | - for (i = 0; i < dev_cnt; i++) { |
|---|
| 5503 | | - vendor_dev_id = profile->device_table[i].vendor_dev_id; |
|---|
| 5504 | | - if ((vendor_dev_id >> 16) == PCI_VENDOR_ID_INTEL) |
|---|
| 5505 | | - if (hw->device_id == (vendor_dev_id & 0xFFFF)) |
|---|
| 5506 | | - break; |
|---|
| 5507 | | - } |
|---|
| 5508 | | - if (i == dev_cnt) { |
|---|
| 5509 | | - i40e_debug(hw, I40E_DEBUG_PACKAGE, "Device doesn't support DDP"); |
|---|
| 5510 | | - return I40E_ERR_DEVICE_NOT_SUPPORTED; |
|---|
| 5511 | | - } |
|---|
| 5512 | | - |
|---|
| 5513 | | - nvm = (u32 *)&profile->device_table[dev_cnt]; |
|---|
| 5514 | | - sec_tbl = (struct i40e_section_table *)&nvm[nvm[0] + 1]; |
|---|
| 5772 | + I40E_SECTION_TABLE(profile, sec_tbl); |
|---|
| 5515 | 5773 | |
|---|
| 5516 | 5774 | for (i = 0; i < sec_tbl->section_count; i++) { |
|---|
| 5517 | | - sec = (struct i40e_profile_section_header *)((u8 *)profile + |
|---|
| 5518 | | - sec_tbl->section_offset[i]); |
|---|
| 5775 | + sec_off = sec_tbl->section_offset[i]; |
|---|
| 5776 | + sec = I40E_SECTION_HEADER(profile, sec_off); |
|---|
| 5777 | + /* Process generic admin command */ |
|---|
| 5778 | + if (sec->section.type == SECTION_TYPE_AQ) { |
|---|
| 5779 | + ddp_aq = (struct i40e_profile_aq_section *)&sec[1]; |
|---|
| 5780 | + status = i40e_ddp_exec_aq_section(hw, ddp_aq); |
|---|
| 5781 | + if (status) { |
|---|
| 5782 | + i40e_debug(hw, I40E_DEBUG_PACKAGE, |
|---|
| 5783 | + "Failed to execute aq: section %d, opcode %u\n", |
|---|
| 5784 | + i, ddp_aq->opcode); |
|---|
| 5785 | + break; |
|---|
| 5786 | + } |
|---|
| 5787 | + sec->section.type = SECTION_TYPE_RB_AQ; |
|---|
| 5788 | + } |
|---|
| 5519 | 5789 | |
|---|
| 5520 | | - /* Skip 'AQ', 'note' and 'name' sections */ |
|---|
| 5790 | + /* Skip any non-mmio sections */ |
|---|
| 5521 | 5791 | if (sec->section.type != SECTION_TYPE_MMIO) |
|---|
| 5522 | 5792 | continue; |
|---|
| 5523 | 5793 | |
|---|
| 5524 | 5794 | section_size = sec->section.size + |
|---|
| 5525 | 5795 | sizeof(struct i40e_profile_section_header); |
|---|
| 5526 | 5796 | |
|---|
| 5527 | | - /* Write profile */ |
|---|
| 5797 | + /* Write MMIO section */ |
|---|
| 5528 | 5798 | status = i40e_aq_write_ddp(hw, (void *)sec, (u16)section_size, |
|---|
| 5529 | 5799 | track_id, &offset, &info, NULL); |
|---|
| 5530 | 5800 | if (status) { |
|---|
| 5531 | 5801 | i40e_debug(hw, I40E_DEBUG_PACKAGE, |
|---|
| 5532 | | - "Failed to write profile: offset %d, info %d", |
|---|
| 5533 | | - offset, info); |
|---|
| 5802 | + "Failed to write profile: section %d, offset %d, info %d\n", |
|---|
| 5803 | + i, offset, info); |
|---|
| 5804 | + break; |
|---|
| 5805 | + } |
|---|
| 5806 | + } |
|---|
| 5807 | + return status; |
|---|
| 5808 | +} |
|---|
| 5809 | + |
|---|
| 5810 | +/** |
|---|
| 5811 | + * i40e_rollback_profile |
|---|
| 5812 | + * @hw: pointer to the hardware structure |
|---|
| 5813 | + * @profile: pointer to the profile segment of the package to be removed |
|---|
| 5814 | + * @track_id: package tracking id |
|---|
| 5815 | + * |
|---|
| 5816 | + * Rolls back previously loaded package. |
|---|
| 5817 | + */ |
|---|
| 5818 | +enum i40e_status_code |
|---|
| 5819 | +i40e_rollback_profile(struct i40e_hw *hw, struct i40e_profile_segment *profile, |
|---|
| 5820 | + u32 track_id) |
|---|
| 5821 | +{ |
|---|
| 5822 | + struct i40e_profile_section_header *sec = NULL; |
|---|
| 5823 | + i40e_status status = 0; |
|---|
| 5824 | + struct i40e_section_table *sec_tbl; |
|---|
| 5825 | + u32 offset = 0, info = 0; |
|---|
| 5826 | + u32 section_size = 0; |
|---|
| 5827 | + u32 sec_off; |
|---|
| 5828 | + int i; |
|---|
| 5829 | + |
|---|
| 5830 | + status = i40e_validate_profile(hw, profile, track_id, true); |
|---|
| 5831 | + if (status) |
|---|
| 5832 | + return status; |
|---|
| 5833 | + |
|---|
| 5834 | + I40E_SECTION_TABLE(profile, sec_tbl); |
|---|
| 5835 | + |
|---|
| 5836 | + /* For rollback write sections in reverse */ |
|---|
| 5837 | + for (i = sec_tbl->section_count - 1; i >= 0; i--) { |
|---|
| 5838 | + sec_off = sec_tbl->section_offset[i]; |
|---|
| 5839 | + sec = I40E_SECTION_HEADER(profile, sec_off); |
|---|
| 5840 | + |
|---|
| 5841 | + /* Skip any non-rollback sections */ |
|---|
| 5842 | + if (sec->section.type != SECTION_TYPE_RB_MMIO) |
|---|
| 5843 | + continue; |
|---|
| 5844 | + |
|---|
| 5845 | + section_size = sec->section.size + |
|---|
| 5846 | + sizeof(struct i40e_profile_section_header); |
|---|
| 5847 | + |
|---|
| 5848 | + /* Write roll-back MMIO section */ |
|---|
| 5849 | + status = i40e_aq_write_ddp(hw, (void *)sec, (u16)section_size, |
|---|
| 5850 | + track_id, &offset, &info, NULL); |
|---|
| 5851 | + if (status) { |
|---|
| 5852 | + i40e_debug(hw, I40E_DEBUG_PACKAGE, |
|---|
| 5853 | + "Failed to write profile: section %d, offset %d, info %d\n", |
|---|
| 5854 | + i, offset, info); |
|---|
| 5534 | 5855 | break; |
|---|
| 5535 | 5856 | } |
|---|
| 5536 | 5857 | } |
|---|