Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2022-08-24 (ice)

This series contains updates to ice driver only.

Marcin adds support for TC parsing on TTL and ToS fields.

Anatolli adds support for devlink port split command to allow
configuration of various port configurations.

Jake allows for passing and writing an additional NVM write activate
field by expanding current cmd_flag.

Ani makes PHY debug output more readable.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2022-08-26 11:39:00 +01:00
commit 77baa37a9b
10 changed files with 804 additions and 27 deletions

View File

@ -139,6 +139,42 @@ EMP firmware image.
The driver does not currently support reloading the driver via
``DEVLINK_RELOAD_ACTION_DRIVER_REINIT``.
Port split
==========
The ``ice`` driver supports port splitting only for port 0, as the FW has
a predefined set of available port split options for the whole device.
A system reboot is required for port split to be applied.
The following command will select the port split option with 4 ports:
.. code:: shell
$ devlink port split pci/0000:16:00.0/0 count 4
The list of all available port options will be printed to dynamic debug after
each ``split`` and ``unsplit`` command. The first option is the default.
.. code:: shell
ice 0000:16:00.0: Available port split options and max port speeds (Gbps):
ice 0000:16:00.0: Status Split Quad 0 Quad 1
ice 0000:16:00.0: count L0 L1 L2 L3 L4 L5 L6 L7
ice 0000:16:00.0: Active 2 100 - - - 100 - - -
ice 0000:16:00.0: 2 50 - 50 - - - - -
ice 0000:16:00.0: Pending 4 25 25 25 25 - - - -
ice 0000:16:00.0: 4 25 25 - - 25 25 - -
ice 0000:16:00.0: 8 10 10 10 10 10 10 10 10
ice 0000:16:00.0: 1 100 - - - - - - -
There could be multiple FW port options with the same port split count. When
the same port split count request is issued again, the next FW port option with
the same port split count will be selected.
``devlink port unsplit`` will select the option with a split count of 1. If
there is no FW option available with split count 1, you will receive an error.
Regions
=======

View File

@ -1423,6 +1423,56 @@ struct ice_aqc_set_port_id_led {
u8 rsvd[13];
};
/* Get Port Options (indirect, 0x06EA) */
struct ice_aqc_get_port_options {
u8 lport_num;
u8 lport_num_valid;
u8 port_options_count;
#define ICE_AQC_PORT_OPT_COUNT_M GENMASK(3, 0)
#define ICE_AQC_PORT_OPT_MAX 16
u8 innermost_phy_index;
u8 port_options;
#define ICE_AQC_PORT_OPT_ACTIVE_M GENMASK(3, 0)
#define ICE_AQC_PORT_OPT_VALID BIT(7)
u8 pending_port_option_status;
#define ICE_AQC_PENDING_PORT_OPT_IDX_M GENMASK(3, 0)
#define ICE_AQC_PENDING_PORT_OPT_VALID BIT(7)
u8 rsvd[2];
__le32 addr_high;
__le32 addr_low;
};
struct ice_aqc_get_port_options_elem {
u8 pmd;
#define ICE_AQC_PORT_OPT_PMD_COUNT_M GENMASK(3, 0)
u8 max_lane_speed;
#define ICE_AQC_PORT_OPT_MAX_LANE_M GENMASK(3, 0)
#define ICE_AQC_PORT_OPT_MAX_LANE_100M 0
#define ICE_AQC_PORT_OPT_MAX_LANE_1G 1
#define ICE_AQC_PORT_OPT_MAX_LANE_2500M 2
#define ICE_AQC_PORT_OPT_MAX_LANE_5G 3
#define ICE_AQC_PORT_OPT_MAX_LANE_10G 4
#define ICE_AQC_PORT_OPT_MAX_LANE_25G 5
#define ICE_AQC_PORT_OPT_MAX_LANE_50G 6
#define ICE_AQC_PORT_OPT_MAX_LANE_100G 7
u8 global_scid[2];
u8 phy_scid[2];
u8 pf2port_cid[2];
};
/* Set Port Option (direct, 0x06EB) */
struct ice_aqc_set_port_option {
u8 lport_num;
u8 lport_num_valid;
u8 selected_port_option;
u8 rsvd[13];
};
/* Set/Get GPIO (direct, 0x06EC/0x06ED) */
struct ice_aqc_gpio {
__le16 gpio_ctrl_handle;
@ -1489,6 +1539,12 @@ struct ice_aqc_nvm {
#define ICE_AQC_NVM_PERST_FLAG 1
#define ICE_AQC_NVM_EMPR_FLAG 2
#define ICE_AQC_NVM_EMPR_ENA BIT(0) /* Write Activate reply only */
/* For Write Activate, several flags are sent as part of a separate
* flags2 field using a separate byte. For simplicity of the software
* interface, we pass the flags as a 16 bit value so these flags are
* all offset by 8 bits
*/
#define ICE_AQC_NVM_ACTIV_REQ_EMPR BIT(8) /* NVM Write Activate only */
__le16 module_typeid;
__le16 length;
#define ICE_AQC_NVM_ERASE_LEN 0xFFFF
@ -2082,6 +2138,8 @@ struct ice_aq_desc {
struct ice_aqc_gpio read_write_gpio;
struct ice_aqc_sff_eeprom read_write_sff_param;
struct ice_aqc_set_port_id_led set_port_id_led;
struct ice_aqc_get_port_options get_port_options;
struct ice_aqc_set_port_option set_port_option;
struct ice_aqc_get_sw_cfg get_sw_conf;
struct ice_aqc_set_port_params set_port_params;
struct ice_aqc_sw_rules sw_rules;
@ -2243,6 +2301,8 @@ enum ice_adminq_opc {
ice_aqc_opc_read_i2c = 0x06E2,
ice_aqc_opc_write_i2c = 0x06E3,
ice_aqc_opc_set_port_id_led = 0x06E9,
ice_aqc_opc_get_port_options = 0x06EA,
ice_aqc_opc_set_port_option = 0x06EB,
ice_aqc_opc_set_gpio = 0x06EC,
ice_aqc_opc_get_gpio = 0x06ED,
ice_aqc_opc_sff_eeprom = 0x06EE,

View File

@ -8,6 +8,108 @@
#define ICE_PF_RESET_WAIT_COUNT 300
static const char * const ice_link_mode_str_low[] = {
[0] = "100BASE_TX",
[1] = "100M_SGMII",
[2] = "1000BASE_T",
[3] = "1000BASE_SX",
[4] = "1000BASE_LX",
[5] = "1000BASE_KX",
[6] = "1G_SGMII",
[7] = "2500BASE_T",
[8] = "2500BASE_X",
[9] = "2500BASE_KX",
[10] = "5GBASE_T",
[11] = "5GBASE_KR",
[12] = "10GBASE_T",
[13] = "10G_SFI_DA",
[14] = "10GBASE_SR",
[15] = "10GBASE_LR",
[16] = "10GBASE_KR_CR1",
[17] = "10G_SFI_AOC_ACC",
[18] = "10G_SFI_C2C",
[19] = "25GBASE_T",
[20] = "25GBASE_CR",
[21] = "25GBASE_CR_S",
[22] = "25GBASE_CR1",
[23] = "25GBASE_SR",
[24] = "25GBASE_LR",
[25] = "25GBASE_KR",
[26] = "25GBASE_KR_S",
[27] = "25GBASE_KR1",
[28] = "25G_AUI_AOC_ACC",
[29] = "25G_AUI_C2C",
[30] = "40GBASE_CR4",
[31] = "40GBASE_SR4",
[32] = "40GBASE_LR4",
[33] = "40GBASE_KR4",
[34] = "40G_XLAUI_AOC_ACC",
[35] = "40G_XLAUI",
[36] = "50GBASE_CR2",
[37] = "50GBASE_SR2",
[38] = "50GBASE_LR2",
[39] = "50GBASE_KR2",
[40] = "50G_LAUI2_AOC_ACC",
[41] = "50G_LAUI2",
[42] = "50G_AUI2_AOC_ACC",
[43] = "50G_AUI2",
[44] = "50GBASE_CP",
[45] = "50GBASE_SR",
[46] = "50GBASE_FR",
[47] = "50GBASE_LR",
[48] = "50GBASE_KR_PAM4",
[49] = "50G_AUI1_AOC_ACC",
[50] = "50G_AUI1",
[51] = "100GBASE_CR4",
[52] = "100GBASE_SR4",
[53] = "100GBASE_LR4",
[54] = "100GBASE_KR4",
[55] = "100G_CAUI4_AOC_ACC",
[56] = "100G_CAUI4",
[57] = "100G_AUI4_AOC_ACC",
[58] = "100G_AUI4",
[59] = "100GBASE_CR_PAM4",
[60] = "100GBASE_KR_PAM4",
[61] = "100GBASE_CP2",
[62] = "100GBASE_SR2",
[63] = "100GBASE_DR",
};
static const char * const ice_link_mode_str_high[] = {
[0] = "100GBASE_KR2_PAM4",
[1] = "100G_CAUI2_AOC_ACC",
[2] = "100G_CAUI2",
[3] = "100G_AUI2_AOC_ACC",
[4] = "100G_AUI2",
};
/**
* ice_dump_phy_type - helper function to dump phy_type
* @hw: pointer to the HW structure
* @low: 64 bit value for phy_type_low
* @high: 64 bit value for phy_type_high
* @prefix: prefix string to differentiate multiple dumps
*/
static void
ice_dump_phy_type(struct ice_hw *hw, u64 low, u64 high, const char *prefix)
{
ice_debug(hw, ICE_DBG_PHY, "%s: phy_type_low: 0x%016llx\n", prefix, low);
for (u32 i = 0; i < BITS_PER_TYPE(typeof(low)); i++) {
if (low & BIT_ULL(i))
ice_debug(hw, ICE_DBG_PHY, "%s: bit(%d): %s\n",
prefix, i, ice_link_mode_str_low[i]);
}
ice_debug(hw, ICE_DBG_PHY, "%s: phy_type_high: 0x%016llx\n", prefix, high);
for (u32 i = 0; i < BITS_PER_TYPE(typeof(high)); i++) {
if (high & BIT_ULL(i))
ice_debug(hw, ICE_DBG_PHY, "%s: bit(%d): %s\n",
prefix, i, ice_link_mode_str_high[i]);
}
}
/**
* ice_set_mac_type - Sets MAC type
* @hw: pointer to the HW structure
@ -183,6 +285,7 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
struct ice_aqc_get_phy_caps *cmd;
u16 pcaps_size = sizeof(*pcaps);
struct ice_aq_desc desc;
const char *prefix;
struct ice_hw *hw;
int status;
@ -204,29 +307,48 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
cmd->param0 |= cpu_to_le16(report_mode);
status = ice_aq_send_cmd(hw, &desc, pcaps, pcaps_size, cd);
ice_debug(hw, ICE_DBG_LINK, "get phy caps - report_mode = 0x%x\n",
report_mode);
ice_debug(hw, ICE_DBG_LINK, " phy_type_low = 0x%llx\n",
(unsigned long long)le64_to_cpu(pcaps->phy_type_low));
ice_debug(hw, ICE_DBG_LINK, " phy_type_high = 0x%llx\n",
(unsigned long long)le64_to_cpu(pcaps->phy_type_high));
ice_debug(hw, ICE_DBG_LINK, " caps = 0x%x\n", pcaps->caps);
ice_debug(hw, ICE_DBG_LINK, " low_power_ctrl_an = 0x%x\n",
ice_debug(hw, ICE_DBG_LINK, "get phy caps dump\n");
switch (report_mode) {
case ICE_AQC_REPORT_TOPO_CAP_MEDIA:
prefix = "phy_caps_media";
break;
case ICE_AQC_REPORT_TOPO_CAP_NO_MEDIA:
prefix = "phy_caps_no_media";
break;
case ICE_AQC_REPORT_ACTIVE_CFG:
prefix = "phy_caps_active";
break;
case ICE_AQC_REPORT_DFLT_CFG:
prefix = "phy_caps_default";
break;
default:
prefix = "phy_caps_invalid";
}
ice_dump_phy_type(hw, le64_to_cpu(pcaps->phy_type_low),
le64_to_cpu(pcaps->phy_type_high), prefix);
ice_debug(hw, ICE_DBG_LINK, "%s: report_mode = 0x%x\n",
prefix, report_mode);
ice_debug(hw, ICE_DBG_LINK, "%s: caps = 0x%x\n", prefix, pcaps->caps);
ice_debug(hw, ICE_DBG_LINK, "%s: low_power_ctrl_an = 0x%x\n", prefix,
pcaps->low_power_ctrl_an);
ice_debug(hw, ICE_DBG_LINK, " eee_cap = 0x%x\n", pcaps->eee_cap);
ice_debug(hw, ICE_DBG_LINK, " eeer_value = 0x%x\n",
ice_debug(hw, ICE_DBG_LINK, "%s: eee_cap = 0x%x\n", prefix,
pcaps->eee_cap);
ice_debug(hw, ICE_DBG_LINK, "%s: eeer_value = 0x%x\n", prefix,
pcaps->eeer_value);
ice_debug(hw, ICE_DBG_LINK, " link_fec_options = 0x%x\n",
ice_debug(hw, ICE_DBG_LINK, "%s: link_fec_options = 0x%x\n", prefix,
pcaps->link_fec_options);
ice_debug(hw, ICE_DBG_LINK, " module_compliance_enforcement = 0x%x\n",
pcaps->module_compliance_enforcement);
ice_debug(hw, ICE_DBG_LINK, " extended_compliance_code = 0x%x\n",
pcaps->extended_compliance_code);
ice_debug(hw, ICE_DBG_LINK, " module_type[0] = 0x%x\n",
ice_debug(hw, ICE_DBG_LINK, "%s: module_compliance_enforcement = 0x%x\n",
prefix, pcaps->module_compliance_enforcement);
ice_debug(hw, ICE_DBG_LINK, "%s: extended_compliance_code = 0x%x\n",
prefix, pcaps->extended_compliance_code);
ice_debug(hw, ICE_DBG_LINK, "%s: module_type[0] = 0x%x\n", prefix,
pcaps->module_type[0]);
ice_debug(hw, ICE_DBG_LINK, " module_type[1] = 0x%x\n",
ice_debug(hw, ICE_DBG_LINK, "%s: module_type[1] = 0x%x\n", prefix,
pcaps->module_type[1]);
ice_debug(hw, ICE_DBG_LINK, " module_type[2] = 0x%x\n",
ice_debug(hw, ICE_DBG_LINK, "%s: module_type[2] = 0x%x\n", prefix,
pcaps->module_type[2]);
if (!status && report_mode == ICE_AQC_REPORT_TOPO_CAP_MEDIA) {
@ -3554,6 +3676,121 @@ ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode,
return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
}
/**
* ice_aq_get_port_options
* @hw: pointer to the HW struct
* @options: buffer for the resultant port options
* @option_count: input - size of the buffer in port options structures,
* output - number of returned port options
* @lport: logical port to call the command with (optional)
* @lport_valid: when false, FW uses port owned by the PF instead of lport,
* when PF owns more than 1 port it must be true
* @active_option_idx: index of active port option in returned buffer
* @active_option_valid: active option in returned buffer is valid
* @pending_option_idx: index of pending port option in returned buffer
* @pending_option_valid: pending option in returned buffer is valid
*
* Calls Get Port Options AQC (0x06ea) and verifies result.
*/
int
ice_aq_get_port_options(struct ice_hw *hw,
struct ice_aqc_get_port_options_elem *options,
u8 *option_count, u8 lport, bool lport_valid,
u8 *active_option_idx, bool *active_option_valid,
u8 *pending_option_idx, bool *pending_option_valid)
{
struct ice_aqc_get_port_options *cmd;
struct ice_aq_desc desc;
int status;
u8 i;
/* options buffer shall be able to hold max returned options */
if (*option_count < ICE_AQC_PORT_OPT_COUNT_M)
return -EINVAL;
cmd = &desc.params.get_port_options;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_port_options);
if (lport_valid)
cmd->lport_num = lport;
cmd->lport_num_valid = lport_valid;
status = ice_aq_send_cmd(hw, &desc, options,
*option_count * sizeof(*options), NULL);
if (status)
return status;
/* verify direct FW response & set output parameters */
*option_count = FIELD_GET(ICE_AQC_PORT_OPT_COUNT_M,
cmd->port_options_count);
ice_debug(hw, ICE_DBG_PHY, "options: %x\n", *option_count);
*active_option_valid = FIELD_GET(ICE_AQC_PORT_OPT_VALID,
cmd->port_options);
if (*active_option_valid) {
*active_option_idx = FIELD_GET(ICE_AQC_PORT_OPT_ACTIVE_M,
cmd->port_options);
if (*active_option_idx > (*option_count - 1))
return -EIO;
ice_debug(hw, ICE_DBG_PHY, "active idx: %x\n",
*active_option_idx);
}
*pending_option_valid = FIELD_GET(ICE_AQC_PENDING_PORT_OPT_VALID,
cmd->pending_port_option_status);
if (*pending_option_valid) {
*pending_option_idx = FIELD_GET(ICE_AQC_PENDING_PORT_OPT_IDX_M,
cmd->pending_port_option_status);
if (*pending_option_idx > (*option_count - 1))
return -EIO;
ice_debug(hw, ICE_DBG_PHY, "pending idx: %x\n",
*pending_option_idx);
}
/* mask output options fields */
for (i = 0; i < *option_count; i++) {
options[i].pmd = FIELD_GET(ICE_AQC_PORT_OPT_PMD_COUNT_M,
options[i].pmd);
options[i].max_lane_speed = FIELD_GET(ICE_AQC_PORT_OPT_MAX_LANE_M,
options[i].max_lane_speed);
ice_debug(hw, ICE_DBG_PHY, "pmds: %x max speed: %x\n",
options[i].pmd, options[i].max_lane_speed);
}
return 0;
}
/**
* ice_aq_set_port_option
* @hw: pointer to the HW struct
* @lport: logical port to call the command with
* @lport_valid: when false, FW uses port owned by the PF instead of lport,
* when PF owns more than 1 port it must be true
* @new_option: new port option to be written
*
* Calls Set Port Options AQC (0x06eb).
*/
int
ice_aq_set_port_option(struct ice_hw *hw, u8 lport, u8 lport_valid,
u8 new_option)
{
struct ice_aqc_set_port_option *cmd;
struct ice_aq_desc desc;
if (new_option > ICE_AQC_PORT_OPT_COUNT_M)
return -EINVAL;
cmd = &desc.params.set_port_option;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_option);
if (lport_valid)
cmd->lport_num = lport;
cmd->lport_num_valid = lport_valid;
cmd->selected_port_option = new_option;
return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
}
/**
* ice_aq_sff_eeprom
* @hw: pointer to the HW struct

View File

@ -151,6 +151,15 @@ int
ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode,
struct ice_sq_cd *cd);
int
ice_aq_get_port_options(struct ice_hw *hw,
struct ice_aqc_get_port_options_elem *options,
u8 *option_count, u8 lport, bool lport_valid,
u8 *active_option_idx, bool *active_option_valid,
u8 *pending_option_idx, bool *pending_option_valid);
int
ice_aq_set_port_option(struct ice_hw *hw, u8 lport, u8 lport_valid,
u8 new_option);
int
ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
u16 mem_addr, u8 page, u8 set_page, u8 *data, u8 length,
bool write, struct ice_sq_cd *cd);

View File

@ -9,6 +9,8 @@
#include "ice_eswitch.h"
#include "ice_fw_update.h"
static int ice_active_port_option = -1;
/* context for devlink info version reporting */
struct ice_info_ctx {
char buf[128];
@ -466,12 +468,259 @@ ice_devlink_reload_empr_finish(struct devlink *devlink,
return 0;
}
/**
* ice_devlink_port_opt_speed_str - convert speed to a string
* @speed: speed value
*/
static const char *ice_devlink_port_opt_speed_str(u8 speed)
{
switch (speed & ICE_AQC_PORT_OPT_MAX_LANE_M) {
case ICE_AQC_PORT_OPT_MAX_LANE_100M:
return "0.1";
case ICE_AQC_PORT_OPT_MAX_LANE_1G:
return "1";
case ICE_AQC_PORT_OPT_MAX_LANE_2500M:
return "2.5";
case ICE_AQC_PORT_OPT_MAX_LANE_5G:
return "5";
case ICE_AQC_PORT_OPT_MAX_LANE_10G:
return "10";
case ICE_AQC_PORT_OPT_MAX_LANE_25G:
return "25";
case ICE_AQC_PORT_OPT_MAX_LANE_50G:
return "50";
case ICE_AQC_PORT_OPT_MAX_LANE_100G:
return "100";
}
return "-";
}
#define ICE_PORT_OPT_DESC_LEN 50
/**
* ice_devlink_port_options_print - Print available port split options
* @pf: the PF to print split port options
*
* Prints a table with available port split options and max port speeds
*/
static void ice_devlink_port_options_print(struct ice_pf *pf)
{
u8 i, j, options_count, cnt, speed, pending_idx, active_idx;
struct ice_aqc_get_port_options_elem *options, *opt;
struct device *dev = ice_pf_to_dev(pf);
bool active_valid, pending_valid;
char desc[ICE_PORT_OPT_DESC_LEN];
const char *str;
int status;
options = kcalloc(ICE_AQC_PORT_OPT_MAX * ICE_MAX_PORT_PER_PCI_DEV,
sizeof(*options), GFP_KERNEL);
if (!options)
return;
for (i = 0; i < ICE_MAX_PORT_PER_PCI_DEV; i++) {
opt = options + i * ICE_AQC_PORT_OPT_MAX;
options_count = ICE_AQC_PORT_OPT_MAX;
active_valid = 0;
status = ice_aq_get_port_options(&pf->hw, opt, &options_count,
i, true, &active_idx,
&active_valid, &pending_idx,
&pending_valid);
if (status) {
dev_dbg(dev, "Couldn't read port option for port %d, err %d\n",
i, status);
goto err;
}
}
dev_dbg(dev, "Available port split options and max port speeds (Gbps):\n");
dev_dbg(dev, "Status Split Quad 0 Quad 1\n");
dev_dbg(dev, " count L0 L1 L2 L3 L4 L5 L6 L7\n");
for (i = 0; i < options_count; i++) {
cnt = 0;
if (i == ice_active_port_option)
str = "Active";
else if ((i == pending_idx) && pending_valid)
str = "Pending";
else
str = "";
cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt,
"%-8s", str);
cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt,
"%-6u", options[i].pmd);
for (j = 0; j < ICE_MAX_PORT_PER_PCI_DEV; ++j) {
speed = options[i + j * ICE_AQC_PORT_OPT_MAX].max_lane_speed;
str = ice_devlink_port_opt_speed_str(speed);
cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt,
"%3s ", str);
}
dev_dbg(dev, "%s\n", desc);
}
err:
kfree(options);
}
/**
* ice_devlink_aq_set_port_option - Send set port option admin queue command
* @pf: the PF to print split port options
* @option_idx: selected port option
* @extack: extended netdev ack structure
*
* Sends set port option admin queue command with selected port option and
* calls NVM write activate.
*/
static int
ice_devlink_aq_set_port_option(struct ice_pf *pf, u8 option_idx,
struct netlink_ext_ack *extack)
{
struct device *dev = ice_pf_to_dev(pf);
int status;
status = ice_aq_set_port_option(&pf->hw, 0, true, option_idx);
if (status) {
dev_dbg(dev, "ice_aq_set_port_option, err %d aq_err %d\n",
status, pf->hw.adminq.sq_last_status);
NL_SET_ERR_MSG_MOD(extack, "Port split request failed");
return -EIO;
}
status = ice_acquire_nvm(&pf->hw, ICE_RES_WRITE);
if (status) {
dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
status, pf->hw.adminq.sq_last_status);
NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
return -EIO;
}
status = ice_nvm_write_activate(&pf->hw, ICE_AQC_NVM_ACTIV_REQ_EMPR, NULL);
if (status) {
dev_dbg(dev, "ice_nvm_write_activate failed, err %d aq_err %d\n",
status, pf->hw.adminq.sq_last_status);
NL_SET_ERR_MSG_MOD(extack, "Port split request failed to save data");
ice_release_nvm(&pf->hw);
return -EIO;
}
ice_release_nvm(&pf->hw);
NL_SET_ERR_MSG_MOD(extack, "Reboot required to finish port split");
return 0;
}
/**
* ice_devlink_port_split - .port_split devlink handler
* @devlink: devlink instance structure
* @port: devlink port structure
* @count: number of ports to split to
* @extack: extended netdev ack structure
*
* Callback for the devlink .port_split operation.
*
* Unfortunately, the devlink expression of available options is limited
* to just a number, so search for an FW port option which supports
* the specified number. As there could be multiple FW port options with
* the same port split count, allow switching between them. When the same
* port split count request is issued again, switch to the next FW port
* option with the same port split count.
*
* Return: zero on success or an error code on failure.
*/
static int
ice_devlink_port_split(struct devlink *devlink, struct devlink_port *port,
unsigned int count, struct netlink_ext_ack *extack)
{
struct ice_aqc_get_port_options_elem options[ICE_AQC_PORT_OPT_MAX];
u8 i, j, active_idx, pending_idx, new_option;
struct ice_pf *pf = devlink_priv(devlink);
u8 option_count = ICE_AQC_PORT_OPT_MAX;
struct device *dev = ice_pf_to_dev(pf);
bool active_valid, pending_valid;
int status;
status = ice_aq_get_port_options(&pf->hw, options, &option_count,
0, true, &active_idx, &active_valid,
&pending_idx, &pending_valid);
if (status) {
dev_dbg(dev, "Couldn't read port split options, err = %d\n",
status);
NL_SET_ERR_MSG_MOD(extack, "Failed to get available port split options");
return -EIO;
}
new_option = ICE_AQC_PORT_OPT_MAX;
active_idx = pending_valid ? pending_idx : active_idx;
for (i = 1; i <= option_count; i++) {
/* In order to allow switching between FW port options with
* the same port split count, search for a new option starting
* from the active/pending option (with array wrap around).
*/
j = (active_idx + i) % option_count;
if (count == options[j].pmd) {
new_option = j;
break;
}
}
if (new_option == active_idx) {
dev_dbg(dev, "request to split: count: %u is already set and there are no other options\n",
count);
NL_SET_ERR_MSG_MOD(extack, "Requested split count is already set");
ice_devlink_port_options_print(pf);
return -EINVAL;
}
if (new_option == ICE_AQC_PORT_OPT_MAX) {
dev_dbg(dev, "request to split: count: %u not found\n", count);
NL_SET_ERR_MSG_MOD(extack, "Port split requested unsupported port config");
ice_devlink_port_options_print(pf);
return -EINVAL;
}
status = ice_devlink_aq_set_port_option(pf, new_option, extack);
if (status)
return status;
ice_devlink_port_options_print(pf);
return 0;
}
/**
* ice_devlink_port_unsplit - .port_unsplit devlink handler
* @devlink: devlink instance structure
* @port: devlink port structure
* @extack: extended netdev ack structure
*
* Callback for the devlink .port_unsplit operation.
* Calls ice_devlink_port_split with split count set to 1.
* There could be no FW option available with split count 1.
*
* Return: zero on success or an error code on failure.
*/
static int
ice_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port,
struct netlink_ext_ack *extack)
{
return ice_devlink_port_split(devlink, port, 1, extack);
}
static const struct devlink_ops ice_devlink_ops = {
.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK,
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE),
/* The ice driver currently does not support driver reinit */
.reload_down = ice_devlink_reload_empr_start,
.reload_up = ice_devlink_reload_empr_finish,
.port_split = ice_devlink_port_split,
.port_unsplit = ice_devlink_port_unsplit,
.eswitch_mode_get = ice_eswitch_mode_get,
.eswitch_mode_set = ice_eswitch_mode_set,
.info_get = ice_devlink_info_get,
@ -694,6 +943,39 @@ void ice_devlink_unregister_params(struct ice_pf *pf)
ARRAY_SIZE(ice_devlink_params));
}
/**
* ice_devlink_set_port_split_options - Set port split options
* @pf: the PF to set port split options
* @attrs: devlink attributes
*
* Sets devlink port split options based on available FW port options
*/
static void
ice_devlink_set_port_split_options(struct ice_pf *pf,
struct devlink_port_attrs *attrs)
{
struct ice_aqc_get_port_options_elem options[ICE_AQC_PORT_OPT_MAX];
u8 i, active_idx, pending_idx, option_count = ICE_AQC_PORT_OPT_MAX;
bool active_valid, pending_valid;
int status;
status = ice_aq_get_port_options(&pf->hw, options, &option_count,
0, true, &active_idx, &active_valid,
&pending_idx, &pending_valid);
if (status) {
dev_dbg(ice_pf_to_dev(pf), "Couldn't read port split options, err = %d\n",
status);
return;
}
/* find the biggest available port split count */
for (i = 0; i < option_count; i++)
attrs->lanes = max_t(int, attrs->lanes, options[i].pmd);
attrs->splittable = attrs->lanes ? 1 : 0;
ice_active_port_option = active_idx;
}
/**
* ice_devlink_create_pf_port - Create a devlink port for this PF
* @pf: the PF to create a devlink port for
@ -722,6 +1004,12 @@ int ice_devlink_create_pf_port(struct ice_pf *pf)
attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
attrs.phys.port_number = pf->hw.bus.func;
/* As FW supports only port split options for whole device,
* set port split options only for first PF.
*/
if (pf->hw.pf_id == 0)
ice_devlink_set_port_split_options(pf, &attrs);
ice_devlink_set_switch_id(pf, &attrs.switch_id);
devlink_port_attrs_set(devlink_port, &attrs);

View File

@ -1114,14 +1114,18 @@ int ice_nvm_validate_checksum(struct ice_hw *hw)
* Update the control word with the required banks' validity bits
* and dumps the Shadow RAM to flash (0x0707)
*
* cmd_flags controls which banks to activate, and the preservation level to
* use when activating the NVM bank.
* cmd_flags controls which banks to activate, the preservation level to use
* when activating the NVM bank, and whether an EMP reset is required for
* activation.
*
* Note that the 16bit cmd_flags value is split between two separate 1 byte
* flag values in the descriptor.
*
* On successful return of the firmware command, the response_flags variable
* is updated with the flags reported by firmware indicating certain status,
* such as whether EMP reset is enabled.
*/
int ice_nvm_write_activate(struct ice_hw *hw, u8 cmd_flags, u8 *response_flags)
int ice_nvm_write_activate(struct ice_hw *hw, u16 cmd_flags, u8 *response_flags)
{
struct ice_aqc_nvm *cmd;
struct ice_aq_desc desc;
@ -1130,7 +1134,8 @@ int ice_nvm_write_activate(struct ice_hw *hw, u8 cmd_flags, u8 *response_flags)
cmd = &desc.params.nvm;
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_write_activate);
cmd->cmd_flags = cmd_flags;
cmd->cmd_flags = (u8)(cmd_flags & 0xFF);
cmd->offset_high = (u8)((cmd_flags >> 8) & 0xFF);
err = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
if (!err && response_flags)

View File

@ -34,7 +34,7 @@ ice_aq_update_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset,
int
ice_aq_erase_nvm(struct ice_hw *hw, u16 module_typeid, struct ice_sq_cd *cd);
int ice_nvm_validate_checksum(struct ice_hw *hw);
int ice_nvm_write_activate(struct ice_hw *hw, u8 cmd_flags, u8 *response_flags);
int ice_nvm_write_activate(struct ice_hw *hw, u16 cmd_flags, u8 *response_flags);
int ice_aq_nvm_update_empr(struct ice_hw *hw);
int
ice_nvm_set_pkg_data(struct ice_hw *hw, bool del_pkg_data_flag, u8 *data,

View File

@ -36,6 +36,10 @@ ice_tc_count_lkups(u32 flags, struct ice_tc_flower_lyr_2_4_hdrs *headers,
ICE_TC_FLWR_FIELD_ENC_DEST_IPV6))
lkups_cnt++;
if (flags & (ICE_TC_FLWR_FIELD_ENC_IP_TOS |
ICE_TC_FLWR_FIELD_ENC_IP_TTL))
lkups_cnt++;
if (flags & ICE_TC_FLWR_FIELD_ENC_DEST_L4_PORT)
lkups_cnt++;
@ -64,6 +68,9 @@ ice_tc_count_lkups(u32 flags, struct ice_tc_flower_lyr_2_4_hdrs *headers,
ICE_TC_FLWR_FIELD_DEST_IPV6 | ICE_TC_FLWR_FIELD_SRC_IPV6))
lkups_cnt++;
if (flags & (ICE_TC_FLWR_FIELD_IP_TOS | ICE_TC_FLWR_FIELD_IP_TTL))
lkups_cnt++;
/* is L4 (TCP/UDP/any other L4 protocol fields) specified? */
if (flags & (ICE_TC_FLWR_FIELD_DEST_L4_PORT |
ICE_TC_FLWR_FIELD_SRC_L4_PORT))
@ -257,6 +264,50 @@ ice_tc_fill_tunnel_outer(u32 flags, struct ice_tc_flower_fltr *fltr,
i++;
}
if (fltr->inner_headers.l2_key.n_proto == htons(ETH_P_IP) &&
(flags & (ICE_TC_FLWR_FIELD_ENC_IP_TOS |
ICE_TC_FLWR_FIELD_ENC_IP_TTL))) {
list[i].type = ice_proto_type_from_ipv4(false);
if (flags & ICE_TC_FLWR_FIELD_ENC_IP_TOS) {
list[i].h_u.ipv4_hdr.tos = hdr->l3_key.tos;
list[i].m_u.ipv4_hdr.tos = hdr->l3_mask.tos;
}
if (flags & ICE_TC_FLWR_FIELD_ENC_IP_TTL) {
list[i].h_u.ipv4_hdr.time_to_live = hdr->l3_key.ttl;
list[i].m_u.ipv4_hdr.time_to_live = hdr->l3_mask.ttl;
}
i++;
}
if (fltr->inner_headers.l2_key.n_proto == htons(ETH_P_IPV6) &&
(flags & (ICE_TC_FLWR_FIELD_ENC_IP_TOS |
ICE_TC_FLWR_FIELD_ENC_IP_TTL))) {
struct ice_ipv6_hdr *hdr_h, *hdr_m;
hdr_h = &list[i].h_u.ipv6_hdr;
hdr_m = &list[i].m_u.ipv6_hdr;
list[i].type = ice_proto_type_from_ipv6(false);
if (flags & ICE_TC_FLWR_FIELD_ENC_IP_TOS) {
be32p_replace_bits(&hdr_h->be_ver_tc_flow,
hdr->l3_key.tos,
ICE_IPV6_HDR_TC_MASK);
be32p_replace_bits(&hdr_m->be_ver_tc_flow,
hdr->l3_mask.tos,
ICE_IPV6_HDR_TC_MASK);
}
if (flags & ICE_TC_FLWR_FIELD_ENC_IP_TTL) {
hdr_h->hop_limit = hdr->l3_key.ttl;
hdr_m->hop_limit = hdr->l3_mask.ttl;
}
i++;
}
if ((flags & ICE_TC_FLWR_FIELD_ENC_DEST_L4_PORT) &&
hdr->l3_key.ip_proto == IPPROTO_UDP) {
list[i].type = ICE_UDP_OF;
@ -420,6 +471,50 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
i++;
}
if (headers->l2_key.n_proto == htons(ETH_P_IP) &&
(flags & (ICE_TC_FLWR_FIELD_IP_TOS | ICE_TC_FLWR_FIELD_IP_TTL))) {
list[i].type = ice_proto_type_from_ipv4(inner);
if (flags & ICE_TC_FLWR_FIELD_IP_TOS) {
list[i].h_u.ipv4_hdr.tos = headers->l3_key.tos;
list[i].m_u.ipv4_hdr.tos = headers->l3_mask.tos;
}
if (flags & ICE_TC_FLWR_FIELD_IP_TTL) {
list[i].h_u.ipv4_hdr.time_to_live =
headers->l3_key.ttl;
list[i].m_u.ipv4_hdr.time_to_live =
headers->l3_mask.ttl;
}
i++;
}
if (headers->l2_key.n_proto == htons(ETH_P_IPV6) &&
(flags & (ICE_TC_FLWR_FIELD_IP_TOS | ICE_TC_FLWR_FIELD_IP_TTL))) {
struct ice_ipv6_hdr *hdr_h, *hdr_m;
hdr_h = &list[i].h_u.ipv6_hdr;
hdr_m = &list[i].m_u.ipv6_hdr;
list[i].type = ice_proto_type_from_ipv6(inner);
if (flags & ICE_TC_FLWR_FIELD_IP_TOS) {
be32p_replace_bits(&hdr_h->be_ver_tc_flow,
headers->l3_key.tos,
ICE_IPV6_HDR_TC_MASK);
be32p_replace_bits(&hdr_m->be_ver_tc_flow,
headers->l3_mask.tos,
ICE_IPV6_HDR_TC_MASK);
}
if (flags & ICE_TC_FLWR_FIELD_IP_TTL) {
hdr_h->hop_limit = headers->l3_key.ttl;
hdr_m->hop_limit = headers->l3_mask.ttl;
}
i++;
}
/* copy L4 (src, dest) port */
if (flags & (ICE_TC_FLWR_FIELD_DEST_L4_PORT |
ICE_TC_FLWR_FIELD_SRC_L4_PORT)) {
@ -838,6 +933,40 @@ ice_tc_set_ipv6(struct flow_match_ipv6_addrs *match,
return 0;
}
/**
* ice_tc_set_tos_ttl - Parse IP ToS/TTL from TC flower filter
* @match: Pointer to flow match structure
* @fltr: Pointer to filter structure
* @headers: inner or outer header fields
* @is_encap: set true for tunnel
*/
static void
ice_tc_set_tos_ttl(struct flow_match_ip *match,
struct ice_tc_flower_fltr *fltr,
struct ice_tc_flower_lyr_2_4_hdrs *headers,
bool is_encap)
{
if (match->mask->tos) {
if (is_encap)
fltr->flags |= ICE_TC_FLWR_FIELD_ENC_IP_TOS;
else
fltr->flags |= ICE_TC_FLWR_FIELD_IP_TOS;
headers->l3_key.tos = match->key->tos;
headers->l3_mask.tos = match->mask->tos;
}
if (match->mask->ttl) {
if (is_encap)
fltr->flags |= ICE_TC_FLWR_FIELD_ENC_IP_TTL;
else
fltr->flags |= ICE_TC_FLWR_FIELD_IP_TTL;
headers->l3_key.ttl = match->key->ttl;
headers->l3_mask.ttl = match->mask->ttl;
}
}
/**
* ice_tc_set_port - Parse ports from TC flower filter
* @match: Flow match structure
@ -967,10 +1096,7 @@ ice_parse_tunnel_attr(struct net_device *dev, struct flow_rule *rule,
struct flow_match_ip match;
flow_rule_match_enc_ip(rule, &match);
headers->l3_key.tos = match.key->tos;
headers->l3_key.ttl = match.key->ttl;
headers->l3_mask.tos = match.mask->tos;
headers->l3_mask.ttl = match.mask->ttl;
ice_tc_set_tos_ttl(&match, fltr, headers, true);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS) &&
@ -1039,6 +1165,7 @@ ice_parse_cls_flower(struct net_device *filter_dev, struct ice_vsi *vsi,
BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) |
BIT(FLOW_DISSECTOR_KEY_ENC_OPTS) |
BIT(FLOW_DISSECTOR_KEY_IP) |
BIT(FLOW_DISSECTOR_KEY_ENC_IP) |
BIT(FLOW_DISSECTOR_KEY_PORTS) |
BIT(FLOW_DISSECTOR_KEY_PPPOE))) {
@ -1217,6 +1344,13 @@ ice_parse_cls_flower(struct net_device *filter_dev, struct ice_vsi *vsi,
return -EINVAL;
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
struct flow_match_ip match;
flow_rule_match_ip(rule, &match);
ice_tc_set_tos_ttl(&match, fltr, headers, false);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_match_ports match;

View File

@ -26,9 +26,15 @@
#define ICE_TC_FLWR_FIELD_CVLAN BIT(19)
#define ICE_TC_FLWR_FIELD_PPPOE_SESSID BIT(20)
#define ICE_TC_FLWR_FIELD_PPP_PROTO BIT(21)
#define ICE_TC_FLWR_FIELD_IP_TOS BIT(22)
#define ICE_TC_FLWR_FIELD_IP_TTL BIT(23)
#define ICE_TC_FLWR_FIELD_ENC_IP_TOS BIT(24)
#define ICE_TC_FLWR_FIELD_ENC_IP_TTL BIT(25)
#define ICE_TC_FLOWER_MASK_32 0xFFFFFFFF
#define ICE_IPV6_HDR_TC_MASK 0xFF00000
struct ice_indr_block_priv {
struct net_device *netdev;
struct ice_netdev_priv *np;

View File

@ -564,6 +564,8 @@ enum ice_rl_type {
#define ICE_SCHED_INVAL_PROF_ID 0xFFFF
#define ICE_SCHED_DFLT_BURST_SIZE (15 * 1024) /* in bytes (15k) */
#define ICE_MAX_PORT_PER_PCI_DEV 8
/* Data structure for saving BW information */
enum ice_bw_type {
ICE_BW_TYPE_PRIO,