mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
Tony Nguyen says: ==================== Intel Wired LAN Driver Updates 2024-04-01 (ice) This series contains updates to ice driver only. Michal Schmidt changes flow for gettimex64 to use host-side spinlock rather than hardware semaphore for lighter-weight locking. Steven adds ability for switch recipes to be re-used when firmware supports it. Thorsten Blum removes unwanted newlines in netlink messaging. Michal Swiatkowski and Piotr re-organize devlink related code; renaming, moving, and consolidating it to a single location. Michal also simplifies the devlink init and cleanup path to occur under a single lock call. * '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue: ice: hold devlink lock for whole init/cleanup ice: move devlink port code to a separate file ice: move ice_devlink.[ch] to devlink folder ice: Remove newlines in NL_SET_ERR_MSG_MOD ice: Add switch recipe reusing feature ice: fold ice_ptp_read_time into ice_ptp_gettimex64 ice: avoid the PTP hardware semaphore in gettimex64 path ice: add ice_adapter for shared data across PFs on the same NIC ==================== Link: https://lore.kernel.org/r/20240401172421.1401696-1-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
84c41dcaae
|
|
@ -5,6 +5,7 @@
|
|||
# Makefile for the Intel(R) Ethernet Connection E800 Series Linux Driver
|
||||
#
|
||||
|
||||
subdir-ccflags-y += -I$(src)
|
||||
obj-$(CONFIG_ICE) += ice.o
|
||||
|
||||
ice-y := ice_main.o \
|
||||
|
|
@ -28,7 +29,8 @@ ice-y := ice_main.o \
|
|||
ice_flex_pipe.o \
|
||||
ice_flow.o \
|
||||
ice_idc.o \
|
||||
ice_devlink.o \
|
||||
devlink/devlink.o \
|
||||
devlink/devlink_port.o \
|
||||
ice_ddp.o \
|
||||
ice_fw_update.o \
|
||||
ice_lag.o \
|
||||
|
|
@ -36,7 +38,8 @@ ice-y := ice_main.o \
|
|||
ice_repr.o \
|
||||
ice_tc_lib.o \
|
||||
ice_fwlog.o \
|
||||
ice_debugfs.o
|
||||
ice_debugfs.o \
|
||||
ice_adapter.o
|
||||
ice-$(CONFIG_PCI_IOV) += \
|
||||
ice_sriov.o \
|
||||
ice_virtchnl.o \
|
||||
|
|
|
|||
|
|
@ -5,13 +5,11 @@
|
|||
|
||||
#include "ice.h"
|
||||
#include "ice_lib.h"
|
||||
#include "ice_devlink.h"
|
||||
#include "devlink.h"
|
||||
#include "ice_eswitch.h"
|
||||
#include "ice_fw_update.h"
|
||||
#include "ice_dcb_lib.h"
|
||||
|
||||
static int ice_active_port_option = -1;
|
||||
|
||||
/* context for devlink info version reporting */
|
||||
struct ice_info_ctx {
|
||||
char buf[128];
|
||||
|
|
@ -478,17 +476,17 @@ ice_devlink_reload_down(struct devlink *devlink, bool netns_change,
|
|||
case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
|
||||
if (ice_is_eswitch_mode_switchdev(pf)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Go to legacy mode before doing reinit\n");
|
||||
"Go to legacy mode before doing reinit");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (ice_is_adq_active(pf)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Turn off ADQ before doing reinit\n");
|
||||
"Turn off ADQ before doing reinit");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (ice_has_vfs(pf)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Remove all VFs before doing reinit\n");
|
||||
"Remove all VFs before doing reinit");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
ice_devlink_reinit_down(pf);
|
||||
|
|
@ -525,251 +523,6 @@ ice_devlink_reload_empr_finish(struct ice_pf *pf,
|
|||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_tear_down_devlink_rate_tree - removes devlink-rate exported tree
|
||||
* @pf: pf struct
|
||||
|
|
@ -1534,7 +1287,7 @@ void ice_devlink_register(struct ice_pf *pf)
|
|||
{
|
||||
struct devlink *devlink = priv_to_devlink(pf);
|
||||
|
||||
devlink_register(devlink);
|
||||
devl_register(devlink);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1545,197 +1298,21 @@ void ice_devlink_register(struct ice_pf *pf)
|
|||
*/
|
||||
void ice_devlink_unregister(struct ice_pf *pf)
|
||||
{
|
||||
devlink_unregister(priv_to_devlink(pf));
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_set_switch_id - Set unique switch id based on pci dsn
|
||||
* @pf: the PF to create a devlink port for
|
||||
* @ppid: struct with switch id information
|
||||
*/
|
||||
static void
|
||||
ice_devlink_set_switch_id(struct ice_pf *pf, struct netdev_phys_item_id *ppid)
|
||||
{
|
||||
struct pci_dev *pdev = pf->pdev;
|
||||
u64 id;
|
||||
|
||||
id = pci_get_dsn(pdev);
|
||||
|
||||
ppid->id_len = sizeof(id);
|
||||
put_unaligned_be64(id, &ppid->id);
|
||||
devl_unregister(priv_to_devlink(pf));
|
||||
}
|
||||
|
||||
int ice_devlink_register_params(struct ice_pf *pf)
|
||||
{
|
||||
struct devlink *devlink = priv_to_devlink(pf);
|
||||
|
||||
return devlink_params_register(devlink, ice_devlink_params,
|
||||
ARRAY_SIZE(ice_devlink_params));
|
||||
return devl_params_register(devlink, ice_devlink_params,
|
||||
ARRAY_SIZE(ice_devlink_params));
|
||||
}
|
||||
|
||||
void ice_devlink_unregister_params(struct ice_pf *pf)
|
||||
{
|
||||
devlink_params_unregister(priv_to_devlink(pf), ice_devlink_params,
|
||||
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;
|
||||
}
|
||||
|
||||
static const struct devlink_port_ops ice_devlink_port_ops = {
|
||||
.port_split = ice_devlink_port_split,
|
||||
.port_unsplit = ice_devlink_port_unsplit,
|
||||
};
|
||||
|
||||
/**
|
||||
* ice_devlink_create_pf_port - Create a devlink port for this PF
|
||||
* @pf: the PF to create a devlink port for
|
||||
*
|
||||
* Create and register a devlink_port for this PF.
|
||||
* This function has to be called under devl_lock.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
int ice_devlink_create_pf_port(struct ice_pf *pf)
|
||||
{
|
||||
struct devlink_port_attrs attrs = {};
|
||||
struct devlink_port *devlink_port;
|
||||
struct devlink *devlink;
|
||||
struct ice_vsi *vsi;
|
||||
struct device *dev;
|
||||
int err;
|
||||
|
||||
devlink = priv_to_devlink(pf);
|
||||
|
||||
dev = ice_pf_to_dev(pf);
|
||||
|
||||
devlink_port = &pf->devlink_port;
|
||||
|
||||
vsi = ice_get_main_vsi(pf);
|
||||
if (!vsi)
|
||||
return -EIO;
|
||||
|
||||
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);
|
||||
|
||||
err = devl_port_register_with_ops(devlink, devlink_port, vsi->idx,
|
||||
&ice_devlink_port_ops);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to create devlink port for PF %d, error %d\n",
|
||||
pf->hw.pf_id, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_destroy_pf_port - Destroy the devlink_port for this PF
|
||||
* @pf: the PF to cleanup
|
||||
*
|
||||
* Unregisters the devlink_port structure associated with this PF.
|
||||
* This function has to be called under devl_lock.
|
||||
*/
|
||||
void ice_devlink_destroy_pf_port(struct ice_pf *pf)
|
||||
{
|
||||
devl_port_unregister(&pf->devlink_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_create_vf_port - Create a devlink port for this VF
|
||||
* @vf: the VF to create a port for
|
||||
*
|
||||
* Create and register a devlink_port for this VF.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
int ice_devlink_create_vf_port(struct ice_vf *vf)
|
||||
{
|
||||
struct devlink_port_attrs attrs = {};
|
||||
struct devlink_port *devlink_port;
|
||||
struct devlink *devlink;
|
||||
struct ice_vsi *vsi;
|
||||
struct device *dev;
|
||||
struct ice_pf *pf;
|
||||
int err;
|
||||
|
||||
pf = vf->pf;
|
||||
dev = ice_pf_to_dev(pf);
|
||||
devlink_port = &vf->devlink_port;
|
||||
|
||||
vsi = ice_get_vf_vsi(vf);
|
||||
if (!vsi)
|
||||
return -EINVAL;
|
||||
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
|
||||
attrs.pci_vf.pf = pf->hw.bus.func;
|
||||
attrs.pci_vf.vf = vf->vf_id;
|
||||
|
||||
ice_devlink_set_switch_id(pf, &attrs.switch_id);
|
||||
|
||||
devlink_port_attrs_set(devlink_port, &attrs);
|
||||
devlink = priv_to_devlink(pf);
|
||||
|
||||
err = devlink_port_register(devlink, devlink_port, vsi->idx);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to create devlink port for VF %d, error %d\n",
|
||||
vf->vf_id, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_destroy_vf_port - Destroy the devlink_port for this VF
|
||||
* @vf: the VF to cleanup
|
||||
*
|
||||
* Unregisters the devlink_port structure associated with this VF.
|
||||
*/
|
||||
void ice_devlink_destroy_vf_port(struct ice_vf *vf)
|
||||
{
|
||||
devl_rate_leaf_destroy(&vf->devlink_port);
|
||||
devlink_port_unregister(&vf->devlink_port);
|
||||
devl_params_unregister(priv_to_devlink(pf), ice_devlink_params,
|
||||
ARRAY_SIZE(ice_devlink_params));
|
||||
}
|
||||
|
||||
#define ICE_DEVLINK_READ_BLK_SIZE (1024 * 1024)
|
||||
|
|
@ -1976,8 +1553,8 @@ void ice_devlink_init_regions(struct ice_pf *pf)
|
|||
u64 nvm_size, sram_size;
|
||||
|
||||
nvm_size = pf->hw.flash.flash_size;
|
||||
pf->nvm_region = devlink_region_create(devlink, &ice_nvm_region_ops, 1,
|
||||
nvm_size);
|
||||
pf->nvm_region = devl_region_create(devlink, &ice_nvm_region_ops, 1,
|
||||
nvm_size);
|
||||
if (IS_ERR(pf->nvm_region)) {
|
||||
dev_err(dev, "failed to create NVM devlink region, err %ld\n",
|
||||
PTR_ERR(pf->nvm_region));
|
||||
|
|
@ -1985,17 +1562,17 @@ void ice_devlink_init_regions(struct ice_pf *pf)
|
|||
}
|
||||
|
||||
sram_size = pf->hw.flash.sr_words * 2u;
|
||||
pf->sram_region = devlink_region_create(devlink, &ice_sram_region_ops,
|
||||
1, sram_size);
|
||||
pf->sram_region = devl_region_create(devlink, &ice_sram_region_ops,
|
||||
1, sram_size);
|
||||
if (IS_ERR(pf->sram_region)) {
|
||||
dev_err(dev, "failed to create shadow-ram devlink region, err %ld\n",
|
||||
PTR_ERR(pf->sram_region));
|
||||
pf->sram_region = NULL;
|
||||
}
|
||||
|
||||
pf->devcaps_region = devlink_region_create(devlink,
|
||||
&ice_devcaps_region_ops, 10,
|
||||
ICE_AQ_MAX_BUF_LEN);
|
||||
pf->devcaps_region = devl_region_create(devlink,
|
||||
&ice_devcaps_region_ops, 10,
|
||||
ICE_AQ_MAX_BUF_LEN);
|
||||
if (IS_ERR(pf->devcaps_region)) {
|
||||
dev_err(dev, "failed to create device-caps devlink region, err %ld\n",
|
||||
PTR_ERR(pf->devcaps_region));
|
||||
|
|
@ -2012,11 +1589,11 @@ void ice_devlink_init_regions(struct ice_pf *pf)
|
|||
void ice_devlink_destroy_regions(struct ice_pf *pf)
|
||||
{
|
||||
if (pf->nvm_region)
|
||||
devlink_region_destroy(pf->nvm_region);
|
||||
devl_region_destroy(pf->nvm_region);
|
||||
|
||||
if (pf->sram_region)
|
||||
devlink_region_destroy(pf->sram_region);
|
||||
devl_region_destroy(pf->sram_region);
|
||||
|
||||
if (pf->devcaps_region)
|
||||
devlink_region_destroy(pf->devcaps_region);
|
||||
devl_region_destroy(pf->devcaps_region);
|
||||
}
|
||||
430
drivers/net/ethernet/intel/ice/devlink/devlink_port.c
Normal file
430
drivers/net/ethernet/intel/ice/devlink/devlink_port.c
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2024, Intel Corporation. */
|
||||
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "ice.h"
|
||||
#include "devlink.h"
|
||||
|
||||
static int ice_active_port_option = -1;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
static const struct devlink_port_ops ice_devlink_port_ops = {
|
||||
.port_split = ice_devlink_port_split,
|
||||
.port_unsplit = ice_devlink_port_unsplit,
|
||||
};
|
||||
|
||||
/**
|
||||
* ice_devlink_set_switch_id - Set unique switch id based on pci dsn
|
||||
* @pf: the PF to create a devlink port for
|
||||
* @ppid: struct with switch id information
|
||||
*/
|
||||
static void
|
||||
ice_devlink_set_switch_id(struct ice_pf *pf, struct netdev_phys_item_id *ppid)
|
||||
{
|
||||
struct pci_dev *pdev = pf->pdev;
|
||||
u64 id;
|
||||
|
||||
id = pci_get_dsn(pdev);
|
||||
|
||||
ppid->id_len = sizeof(id);
|
||||
put_unaligned_be64(id, &ppid->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_create_pf_port - Create a devlink port for this PF
|
||||
* @pf: the PF to create a devlink port for
|
||||
*
|
||||
* Create and register a devlink_port for this PF.
|
||||
* This function has to be called under devl_lock.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
int ice_devlink_create_pf_port(struct ice_pf *pf)
|
||||
{
|
||||
struct devlink_port_attrs attrs = {};
|
||||
struct devlink_port *devlink_port;
|
||||
struct devlink *devlink;
|
||||
struct ice_vsi *vsi;
|
||||
struct device *dev;
|
||||
int err;
|
||||
|
||||
devlink = priv_to_devlink(pf);
|
||||
|
||||
dev = ice_pf_to_dev(pf);
|
||||
|
||||
devlink_port = &pf->devlink_port;
|
||||
|
||||
vsi = ice_get_main_vsi(pf);
|
||||
if (!vsi)
|
||||
return -EIO;
|
||||
|
||||
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);
|
||||
|
||||
err = devl_port_register_with_ops(devlink, devlink_port, vsi->idx,
|
||||
&ice_devlink_port_ops);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to create devlink port for PF %d, error %d\n",
|
||||
pf->hw.pf_id, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_destroy_pf_port - Destroy the devlink_port for this PF
|
||||
* @pf: the PF to cleanup
|
||||
*
|
||||
* Unregisters the devlink_port structure associated with this PF.
|
||||
* This function has to be called under devl_lock.
|
||||
*/
|
||||
void ice_devlink_destroy_pf_port(struct ice_pf *pf)
|
||||
{
|
||||
devl_port_unregister(&pf->devlink_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_create_vf_port - Create a devlink port for this VF
|
||||
* @vf: the VF to create a port for
|
||||
*
|
||||
* Create and register a devlink_port for this VF.
|
||||
*
|
||||
* Return: zero on success or an error code on failure.
|
||||
*/
|
||||
int ice_devlink_create_vf_port(struct ice_vf *vf)
|
||||
{
|
||||
struct devlink_port_attrs attrs = {};
|
||||
struct devlink_port *devlink_port;
|
||||
struct devlink *devlink;
|
||||
struct ice_vsi *vsi;
|
||||
struct device *dev;
|
||||
struct ice_pf *pf;
|
||||
int err;
|
||||
|
||||
pf = vf->pf;
|
||||
dev = ice_pf_to_dev(pf);
|
||||
devlink_port = &vf->devlink_port;
|
||||
|
||||
vsi = ice_get_vf_vsi(vf);
|
||||
if (!vsi)
|
||||
return -EINVAL;
|
||||
|
||||
attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
|
||||
attrs.pci_vf.pf = pf->hw.bus.func;
|
||||
attrs.pci_vf.vf = vf->vf_id;
|
||||
|
||||
ice_devlink_set_switch_id(pf, &attrs.switch_id);
|
||||
|
||||
devlink_port_attrs_set(devlink_port, &attrs);
|
||||
devlink = priv_to_devlink(pf);
|
||||
|
||||
err = devlink_port_register(devlink, devlink_port, vsi->idx);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to create devlink port for VF %d, error %d\n",
|
||||
vf->vf_id, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_devlink_destroy_vf_port - Destroy the devlink_port for this VF
|
||||
* @vf: the VF to cleanup
|
||||
*
|
||||
* Unregisters the devlink_port structure associated with this VF.
|
||||
*/
|
||||
void ice_devlink_destroy_vf_port(struct ice_vf *vf)
|
||||
{
|
||||
devl_rate_leaf_destroy(&vf->devlink_port);
|
||||
devlink_port_unregister(&vf->devlink_port);
|
||||
}
|
||||
12
drivers/net/ethernet/intel/ice/devlink/devlink_port.h
Normal file
12
drivers/net/ethernet/intel/ice/devlink/devlink_port.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2024, Intel Corporation. */
|
||||
|
||||
#ifndef _DEVLINK_PORT_H_
|
||||
#define _DEVLINK_PORT_H_
|
||||
|
||||
int ice_devlink_create_pf_port(struct ice_pf *pf);
|
||||
void ice_devlink_destroy_pf_port(struct ice_pf *pf);
|
||||
int ice_devlink_create_vf_port(struct ice_vf *vf);
|
||||
void ice_devlink_destroy_vf_port(struct ice_vf *vf);
|
||||
|
||||
#endif /* _DEVLINK_PORT_H_ */
|
||||
|
|
@ -77,6 +77,7 @@
|
|||
#include "ice_gnss.h"
|
||||
#include "ice_irq.h"
|
||||
#include "ice_dpll.h"
|
||||
#include "ice_adapter.h"
|
||||
|
||||
#define ICE_BAR0 0
|
||||
#define ICE_REQ_DESC_MULTIPLE 32
|
||||
|
|
@ -537,6 +538,7 @@ struct ice_agg_node {
|
|||
|
||||
struct ice_pf {
|
||||
struct pci_dev *pdev;
|
||||
struct ice_adapter *adapter;
|
||||
|
||||
struct devlink_region *nvm_region;
|
||||
struct devlink_region *sram_region;
|
||||
|
|
|
|||
116
drivers/net/ethernet/intel/ice/ice_adapter.c
Normal file
116
drivers/net/ethernet/intel/ice/ice_adapter.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright Red Hat
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/xarray.h>
|
||||
#include "ice_adapter.h"
|
||||
|
||||
static DEFINE_XARRAY(ice_adapters);
|
||||
|
||||
/* PCI bus number is 8 bits. Slot is 5 bits. Domain can have the rest. */
|
||||
#define INDEX_FIELD_DOMAIN GENMASK(BITS_PER_LONG - 1, 13)
|
||||
#define INDEX_FIELD_BUS GENMASK(12, 5)
|
||||
#define INDEX_FIELD_SLOT GENMASK(4, 0)
|
||||
|
||||
static unsigned long ice_adapter_index(const struct pci_dev *pdev)
|
||||
{
|
||||
unsigned int domain = pci_domain_nr(pdev->bus);
|
||||
|
||||
WARN_ON(domain > FIELD_MAX(INDEX_FIELD_DOMAIN));
|
||||
|
||||
return FIELD_PREP(INDEX_FIELD_DOMAIN, domain) |
|
||||
FIELD_PREP(INDEX_FIELD_BUS, pdev->bus->number) |
|
||||
FIELD_PREP(INDEX_FIELD_SLOT, PCI_SLOT(pdev->devfn));
|
||||
}
|
||||
|
||||
static struct ice_adapter *ice_adapter_new(void)
|
||||
{
|
||||
struct ice_adapter *adapter;
|
||||
|
||||
adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
|
||||
if (!adapter)
|
||||
return NULL;
|
||||
|
||||
spin_lock_init(&adapter->ptp_gltsyn_time_lock);
|
||||
refcount_set(&adapter->refcount, 1);
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
static void ice_adapter_free(struct ice_adapter *adapter)
|
||||
{
|
||||
kfree(adapter);
|
||||
}
|
||||
|
||||
DEFINE_FREE(ice_adapter_free, struct ice_adapter*, if (_T) ice_adapter_free(_T))
|
||||
|
||||
/**
|
||||
* ice_adapter_get - Get a shared ice_adapter structure.
|
||||
* @pdev: Pointer to the pci_dev whose driver is getting the ice_adapter.
|
||||
*
|
||||
* Gets a pointer to a shared ice_adapter structure. Physical functions (PFs)
|
||||
* of the same multi-function PCI device share one ice_adapter structure.
|
||||
* The ice_adapter is reference-counted. The PF driver must use ice_adapter_put
|
||||
* to release its reference.
|
||||
*
|
||||
* Context: Process, may sleep.
|
||||
* Return: Pointer to ice_adapter on success.
|
||||
* ERR_PTR() on error. -ENOMEM is the only possible error.
|
||||
*/
|
||||
struct ice_adapter *ice_adapter_get(const struct pci_dev *pdev)
|
||||
{
|
||||
struct ice_adapter *ret, __free(ice_adapter_free) *adapter = NULL;
|
||||
unsigned long index = ice_adapter_index(pdev);
|
||||
|
||||
adapter = ice_adapter_new();
|
||||
if (!adapter)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
xa_lock(&ice_adapters);
|
||||
ret = __xa_cmpxchg(&ice_adapters, index, NULL, adapter, GFP_KERNEL);
|
||||
if (xa_is_err(ret)) {
|
||||
ret = ERR_PTR(xa_err(ret));
|
||||
goto unlock;
|
||||
}
|
||||
if (ret) {
|
||||
refcount_inc(&ret->refcount);
|
||||
goto unlock;
|
||||
}
|
||||
ret = no_free_ptr(adapter);
|
||||
unlock:
|
||||
xa_unlock(&ice_adapters);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_adapter_put - Release a reference to the shared ice_adapter structure.
|
||||
* @pdev: Pointer to the pci_dev whose driver is releasing the ice_adapter.
|
||||
*
|
||||
* Releases the reference to ice_adapter previously obtained with
|
||||
* ice_adapter_get.
|
||||
*
|
||||
* Context: Any.
|
||||
*/
|
||||
void ice_adapter_put(const struct pci_dev *pdev)
|
||||
{
|
||||
unsigned long index = ice_adapter_index(pdev);
|
||||
struct ice_adapter *adapter;
|
||||
|
||||
xa_lock(&ice_adapters);
|
||||
adapter = xa_load(&ice_adapters, index);
|
||||
if (WARN_ON(!adapter))
|
||||
goto unlock;
|
||||
|
||||
if (!refcount_dec_and_test(&adapter->refcount))
|
||||
goto unlock;
|
||||
|
||||
WARN_ON(__xa_erase(&ice_adapters, index) != adapter);
|
||||
ice_adapter_free(adapter);
|
||||
unlock:
|
||||
xa_unlock(&ice_adapters);
|
||||
}
|
||||
28
drivers/net/ethernet/intel/ice/ice_adapter.h
Normal file
28
drivers/net/ethernet/intel/ice/ice_adapter.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* SPDX-FileCopyrightText: Copyright Red Hat */
|
||||
|
||||
#ifndef _ICE_ADAPTER_H_
|
||||
#define _ICE_ADAPTER_H_
|
||||
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/refcount_types.h>
|
||||
|
||||
struct pci_dev;
|
||||
|
||||
/**
|
||||
* struct ice_adapter - PCI adapter resources shared across PFs
|
||||
* @ptp_gltsyn_time_lock: Spinlock protecting access to the GLTSYN_TIME
|
||||
* register of the PTP clock.
|
||||
* @refcount: Reference count. struct ice_pf objects hold the references.
|
||||
*/
|
||||
struct ice_adapter {
|
||||
/* For access to the GLTSYN_TIME register */
|
||||
spinlock_t ptp_gltsyn_time_lock;
|
||||
|
||||
refcount_t refcount;
|
||||
};
|
||||
|
||||
struct ice_adapter *ice_adapter_get(const struct pci_dev *pdev);
|
||||
void ice_adapter_put(const struct pci_dev *pdev);
|
||||
|
||||
#endif /* _ICE_ADAPTER_H */
|
||||
|
|
@ -264,6 +264,8 @@ struct ice_aqc_set_port_params {
|
|||
#define ICE_AQC_RES_TYPE_FLAG_SHARED BIT(7)
|
||||
#define ICE_AQC_RES_TYPE_FLAG_SCAN_BOTTOM BIT(12)
|
||||
#define ICE_AQC_RES_TYPE_FLAG_IGNORE_INDEX BIT(13)
|
||||
#define ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_SHARED BIT(14)
|
||||
#define ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_CTL BIT(15)
|
||||
|
||||
#define ICE_AQC_RES_TYPE_FLAG_DEDICATED 0x00
|
||||
|
||||
|
|
|
|||
|
|
@ -1142,6 +1142,8 @@ int ice_init_hw(struct ice_hw *hw)
|
|||
if (status)
|
||||
goto err_unroll_fltr_mgmt_struct;
|
||||
mutex_init(&hw->tnl_lock);
|
||||
ice_init_chk_recipe_reuse_support(hw);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unroll_fltr_mgmt_struct:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "ice_dcb_lib.h"
|
||||
#include "ice_dcb_nl.h"
|
||||
#include "ice_devlink.h"
|
||||
#include "devlink/devlink.h"
|
||||
|
||||
/**
|
||||
* ice_dcb_get_ena_tc - return bitmap of enabled TCs
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include "ice_eswitch_br.h"
|
||||
#include "ice_fltr.h"
|
||||
#include "ice_repr.h"
|
||||
#include "ice_devlink.h"
|
||||
#include "devlink/devlink.h"
|
||||
#include "ice_tc_lib.h"
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#include "ice_lib.h"
|
||||
#include "ice_fltr.h"
|
||||
#include "ice_dcb_lib.h"
|
||||
#include "ice_devlink.h"
|
||||
#include "ice_vsi_vlan_ops.h"
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@
|
|||
#include "ice_fltr.h"
|
||||
#include "ice_dcb_lib.h"
|
||||
#include "ice_dcb_nl.h"
|
||||
#include "ice_devlink.h"
|
||||
#include "devlink/devlink.h"
|
||||
#include "devlink/devlink_port.h"
|
||||
#include "ice_hwmon.h"
|
||||
/* Including ice_trace.h with CREATE_TRACE_POINTS defined will generate the
|
||||
* ice tracepoint functions. This must be done exactly once across the
|
||||
|
|
@ -5093,6 +5094,7 @@ static int
|
|||
ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ice_adapter *adapter;
|
||||
struct ice_pf *pf;
|
||||
struct ice_hw *hw;
|
||||
int err;
|
||||
|
|
@ -5145,7 +5147,12 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
|||
|
||||
pci_set_master(pdev);
|
||||
|
||||
adapter = ice_adapter_get(pdev);
|
||||
if (IS_ERR(adapter))
|
||||
return PTR_ERR(adapter);
|
||||
|
||||
pf->pdev = pdev;
|
||||
pf->adapter = adapter;
|
||||
pci_set_drvdata(pdev, pf);
|
||||
set_bit(ICE_DOWN, pf->state);
|
||||
/* Disable service task until DOWN bit is cleared */
|
||||
|
|
@ -5179,23 +5186,23 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
|||
|
||||
devl_lock(priv_to_devlink(pf));
|
||||
err = ice_load(pf);
|
||||
devl_unlock(priv_to_devlink(pf));
|
||||
if (err)
|
||||
goto err_load;
|
||||
|
||||
err = ice_init_devlink(pf);
|
||||
if (err)
|
||||
goto err_init_devlink;
|
||||
devl_unlock(priv_to_devlink(pf));
|
||||
|
||||
return 0;
|
||||
|
||||
err_init_devlink:
|
||||
devl_lock(priv_to_devlink(pf));
|
||||
ice_unload(pf);
|
||||
devl_unlock(priv_to_devlink(pf));
|
||||
err_load:
|
||||
devl_unlock(priv_to_devlink(pf));
|
||||
ice_deinit(pf);
|
||||
err_init:
|
||||
ice_adapter_put(pdev);
|
||||
pci_disable_device(pdev);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -5290,9 +5297,9 @@ static void ice_remove(struct pci_dev *pdev)
|
|||
if (!ice_is_safe_mode(pf))
|
||||
ice_remove_arfs(pf);
|
||||
|
||||
devl_lock(priv_to_devlink(pf));
|
||||
ice_deinit_devlink(pf);
|
||||
|
||||
devl_lock(priv_to_devlink(pf));
|
||||
ice_unload(pf);
|
||||
devl_unlock(priv_to_devlink(pf));
|
||||
|
||||
|
|
@ -5302,6 +5309,7 @@ static void ice_remove(struct pci_dev *pdev)
|
|||
ice_setup_mc_magic_wake(pf);
|
||||
ice_set_wake(pf);
|
||||
|
||||
ice_adapter_put(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ ice_ptp_read_src_clk_reg(struct ice_pf *pf, struct ptp_system_timestamp *sts)
|
|||
u8 tmr_idx;
|
||||
|
||||
tmr_idx = ice_get_ptp_src_clock_index(hw);
|
||||
guard(spinlock)(&pf->adapter->ptp_gltsyn_time_lock);
|
||||
/* Read the system timestamp pre PHC read */
|
||||
ptp_read_system_prets(sts);
|
||||
|
||||
|
|
@ -1165,26 +1166,6 @@ static void ice_ptp_reset_cached_phctime(struct ice_pf *pf)
|
|||
ice_ptp_mark_tx_tracker_stale(&pf->ptp.port.tx);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_ptp_read_time - Read the time from the device
|
||||
* @pf: Board private structure
|
||||
* @ts: timespec structure to hold the current time value
|
||||
* @sts: Optional parameter for holding a pair of system timestamps from
|
||||
* the system clock. Will be ignored if NULL is given.
|
||||
*
|
||||
* This function reads the source clock registers and stores them in a timespec.
|
||||
* However, since the registers are 64 bits of nanoseconds, we must convert the
|
||||
* result to a timespec before we can return.
|
||||
*/
|
||||
static void
|
||||
ice_ptp_read_time(struct ice_pf *pf, struct timespec64 *ts,
|
||||
struct ptp_system_timestamp *sts)
|
||||
{
|
||||
u64 time_ns = ice_ptp_read_src_clk_reg(pf, sts);
|
||||
|
||||
*ts = ns_to_timespec64(time_ns);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_ptp_write_init - Set PHC time to provided value
|
||||
* @pf: Board private structure
|
||||
|
|
@ -1925,16 +1906,10 @@ ice_ptp_gettimex64(struct ptp_clock_info *info, struct timespec64 *ts,
|
|||
struct ptp_system_timestamp *sts)
|
||||
{
|
||||
struct ice_pf *pf = ptp_info_to_pf(info);
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
|
||||
if (!ice_ptp_lock(hw)) {
|
||||
dev_err(ice_pf_to_dev(pf), "PTP failed to get time\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ice_ptp_read_time(pf, ts, sts);
|
||||
ice_ptp_unlock(hw);
|
||||
u64 time_ns;
|
||||
|
||||
time_ns = ice_ptp_read_src_clk_reg(pf, sts);
|
||||
*ts = ns_to_timespec64(time_ns);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -274,6 +274,9 @@ void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
|
|||
*/
|
||||
static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)
|
||||
{
|
||||
struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
|
||||
|
||||
guard(spinlock)(&pf->adapter->ptp_gltsyn_time_lock);
|
||||
wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
|
||||
ice_flush(hw);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
#include "ice.h"
|
||||
#include "ice_eswitch.h"
|
||||
#include "ice_devlink.h"
|
||||
#include "devlink/devlink.h"
|
||||
#include "devlink/devlink_port.h"
|
||||
#include "ice_sriov.h"
|
||||
#include "ice_tc_lib.h"
|
||||
#include "ice_dcb_lib.h"
|
||||
|
|
|
|||
|
|
@ -2148,6 +2148,18 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 *r_assoc,
|
|||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_init_chk_recipe_reuse_support - check if recipe reuse is supported
|
||||
* @hw: pointer to the hardware structure
|
||||
*/
|
||||
void ice_init_chk_recipe_reuse_support(struct ice_hw *hw)
|
||||
{
|
||||
struct ice_nvm_info *nvm = &hw->flash.nvm;
|
||||
|
||||
hw->recp_reuse = (nvm->major == 0x4 && nvm->minor >= 0x30) ||
|
||||
nvm->major > 0x4;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_alloc_recipe - add recipe resource
|
||||
* @hw: pointer to the hardware structure
|
||||
|
|
@ -2157,12 +2169,16 @@ int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
|
|||
{
|
||||
DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
|
||||
u16 buf_len = __struct_size(sw_buf);
|
||||
u16 res_type;
|
||||
int status;
|
||||
|
||||
sw_buf->num_elems = cpu_to_le16(1);
|
||||
sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE <<
|
||||
ICE_AQC_RES_TYPE_S) |
|
||||
ICE_AQC_RES_TYPE_FLAG_SHARED);
|
||||
res_type = FIELD_PREP(ICE_AQC_RES_TYPE_M, ICE_AQC_RES_TYPE_RECIPE);
|
||||
if (hw->recp_reuse)
|
||||
res_type |= ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_SHARED;
|
||||
else
|
||||
res_type |= ICE_AQC_RES_TYPE_FLAG_SHARED;
|
||||
sw_buf->res_type = cpu_to_le16(res_type);
|
||||
status = ice_aq_alloc_free_res(hw, sw_buf, buf_len,
|
||||
ice_aqc_opc_alloc_res);
|
||||
if (!status)
|
||||
|
|
@ -2171,6 +2187,70 @@ int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
|
|||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_free_recipe_res - free recipe resource
|
||||
* @hw: pointer to the hardware structure
|
||||
* @rid: recipe ID to free
|
||||
*
|
||||
* Return: 0 on success, and others on error
|
||||
*/
|
||||
static int ice_free_recipe_res(struct ice_hw *hw, u16 rid)
|
||||
{
|
||||
return ice_free_hw_res(hw, ICE_AQC_RES_TYPE_RECIPE, 1, &rid);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_release_recipe_res - disassociate and free recipe resource
|
||||
* @hw: pointer to the hardware structure
|
||||
* @recp: the recipe struct resource to unassociate and free
|
||||
*
|
||||
* Return: 0 on success, and others on error
|
||||
*/
|
||||
static int ice_release_recipe_res(struct ice_hw *hw,
|
||||
struct ice_sw_recipe *recp)
|
||||
{
|
||||
DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
|
||||
struct ice_switch_info *sw = hw->switch_info;
|
||||
u64 recp_assoc;
|
||||
u32 rid, prof;
|
||||
int status;
|
||||
|
||||
for_each_set_bit(rid, recp->r_bitmap, ICE_MAX_NUM_RECIPES) {
|
||||
for_each_set_bit(prof, recipe_to_profile[rid],
|
||||
ICE_MAX_NUM_PROFILES) {
|
||||
status = ice_aq_get_recipe_to_profile(hw, prof,
|
||||
&recp_assoc,
|
||||
NULL);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
bitmap_from_arr64(r_bitmap, &recp_assoc,
|
||||
ICE_MAX_NUM_RECIPES);
|
||||
bitmap_andnot(r_bitmap, r_bitmap, recp->r_bitmap,
|
||||
ICE_MAX_NUM_RECIPES);
|
||||
bitmap_to_arr64(&recp_assoc, r_bitmap,
|
||||
ICE_MAX_NUM_RECIPES);
|
||||
ice_aq_map_recipe_to_profile(hw, prof,
|
||||
recp_assoc, NULL);
|
||||
|
||||
clear_bit(rid, profile_to_recipe[prof]);
|
||||
clear_bit(prof, recipe_to_profile[rid]);
|
||||
}
|
||||
|
||||
status = ice_free_recipe_res(hw, rid);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
sw->recp_list[rid].recp_created = false;
|
||||
sw->recp_list[rid].adv_rule = false;
|
||||
memset(&sw->recp_list[rid].lkup_exts, 0,
|
||||
sizeof(sw->recp_list[rid].lkup_exts));
|
||||
clear_bit(rid, recp->r_bitmap);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_get_recp_to_prof_map - updates recipe to profile mapping
|
||||
* @hw: pointer to hardware structure
|
||||
|
|
@ -2220,6 +2300,7 @@ ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf,
|
|||
* @recps: struct that we need to populate
|
||||
* @rid: recipe ID that we are populating
|
||||
* @refresh_required: true if we should get recipe to profile mapping from FW
|
||||
* @is_add: flag of adding recipe
|
||||
*
|
||||
* This function is used to populate all the necessary entries into our
|
||||
* bookkeeping so that we have a current list of all the recipes that are
|
||||
|
|
@ -2227,7 +2308,7 @@ ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf,
|
|||
*/
|
||||
static int
|
||||
ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
|
||||
bool *refresh_required)
|
||||
bool *refresh_required, bool is_add)
|
||||
{
|
||||
DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS);
|
||||
struct ice_aqc_recipe_data_elem *tmp;
|
||||
|
|
@ -2344,8 +2425,12 @@ ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
|
|||
recps[idx].chain_idx = ICE_INVAL_CHAIN_IND;
|
||||
}
|
||||
|
||||
if (!is_root)
|
||||
if (!is_root) {
|
||||
if (hw->recp_reuse && is_add)
|
||||
recps[idx].recp_created = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only do the following for root recipes entries */
|
||||
memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap,
|
||||
|
|
@ -2369,7 +2454,8 @@ ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
|
|||
|
||||
/* Copy result indexes */
|
||||
bitmap_copy(recps[rid].res_idxs, result_bm, ICE_MAX_FV_WORDS);
|
||||
recps[rid].recp_created = true;
|
||||
if (is_add)
|
||||
recps[rid].recp_created = true;
|
||||
|
||||
err_unroll:
|
||||
kfree(tmp);
|
||||
|
|
@ -4653,12 +4739,13 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
|
|||
* @hw: pointer to the hardware structure
|
||||
* @lkup_exts: extension sequence to match
|
||||
* @rinfo: information regarding the rule e.g. priority and action info
|
||||
* @is_add: flag of adding recipe
|
||||
*
|
||||
* Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.
|
||||
*/
|
||||
static u16
|
||||
ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
|
||||
const struct ice_adv_rule_info *rinfo)
|
||||
const struct ice_adv_rule_info *rinfo, bool is_add)
|
||||
{
|
||||
bool refresh_required = true;
|
||||
struct ice_sw_recipe *recp;
|
||||
|
|
@ -4672,11 +4759,12 @@ ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
|
|||
* entry update it in our SW bookkeeping and continue with the
|
||||
* matching.
|
||||
*/
|
||||
if (!recp[i].recp_created)
|
||||
if (hw->recp_reuse) {
|
||||
if (ice_get_recp_frm_fw(hw,
|
||||
hw->switch_info->recp_list, i,
|
||||
&refresh_required))
|
||||
&refresh_required, is_add))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip inverse action recipes */
|
||||
if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl &
|
||||
|
|
@ -5360,6 +5448,49 @@ ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,
|
|||
ice_get_sw_fv_bitmap(hw, prof_type, bm);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_subscribe_recipe - subscribe to an existing recipe
|
||||
* @hw: pointer to the hardware structure
|
||||
* @rid: recipe ID to subscribe to
|
||||
*
|
||||
* Return: 0 on success, and others on error
|
||||
*/
|
||||
static int ice_subscribe_recipe(struct ice_hw *hw, u16 rid)
|
||||
{
|
||||
DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
|
||||
u16 buf_len = __struct_size(sw_buf);
|
||||
u16 res_type;
|
||||
int status;
|
||||
|
||||
/* Prepare buffer to allocate resource */
|
||||
sw_buf->num_elems = cpu_to_le16(1);
|
||||
res_type = FIELD_PREP(ICE_AQC_RES_TYPE_M, ICE_AQC_RES_TYPE_RECIPE) |
|
||||
ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_SHARED |
|
||||
ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_CTL;
|
||||
sw_buf->res_type = cpu_to_le16(res_type);
|
||||
|
||||
sw_buf->elem[0].e.sw_resp = cpu_to_le16(rid);
|
||||
|
||||
status = ice_aq_alloc_free_res(hw, sw_buf, buf_len,
|
||||
ice_aqc_opc_alloc_res);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_subscribable_recp_shared - share an existing subscribable recipe
|
||||
* @hw: pointer to the hardware structure
|
||||
* @rid: recipe ID to subscribe to
|
||||
*/
|
||||
static void ice_subscribable_recp_shared(struct ice_hw *hw, u16 rid)
|
||||
{
|
||||
struct ice_sw_recipe *recps = hw->switch_info->recp_list;
|
||||
u16 sub_rid;
|
||||
|
||||
for_each_set_bit(sub_rid, recps[rid].r_bitmap, ICE_MAX_NUM_RECIPES)
|
||||
ice_subscribe_recipe(hw, sub_rid);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_add_adv_recipe - Add an advanced recipe that is not part of the default
|
||||
* @hw: pointer to hardware structure
|
||||
|
|
@ -5382,6 +5513,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
|
|||
struct ice_sw_fv_list_entry *tmp;
|
||||
struct ice_sw_recipe *rm;
|
||||
int status = 0;
|
||||
u16 rid_tmp;
|
||||
u8 i;
|
||||
|
||||
if (!lkups_cnt)
|
||||
|
|
@ -5459,10 +5591,14 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
|
|||
}
|
||||
|
||||
/* Look for a recipe which matches our requested fv / mask list */
|
||||
*rid = ice_find_recp(hw, lkup_exts, rinfo);
|
||||
if (*rid < ICE_MAX_NUM_RECIPES)
|
||||
*rid = ice_find_recp(hw, lkup_exts, rinfo, true);
|
||||
if (*rid < ICE_MAX_NUM_RECIPES) {
|
||||
/* Success if found a recipe that match the existing criteria */
|
||||
if (hw->recp_reuse)
|
||||
ice_subscribable_recp_shared(hw, *rid);
|
||||
|
||||
goto err_unroll;
|
||||
}
|
||||
|
||||
rm->tun_type = rinfo->tun_type;
|
||||
/* Recipe we need does not exist, add a recipe */
|
||||
|
|
@ -5481,14 +5617,14 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
|
|||
status = ice_aq_get_recipe_to_profile(hw, fvit->profile_id,
|
||||
&recp_assoc, NULL);
|
||||
if (status)
|
||||
goto err_unroll;
|
||||
goto err_free_recipe;
|
||||
|
||||
bitmap_from_arr64(r_bitmap, &recp_assoc, ICE_MAX_NUM_RECIPES);
|
||||
bitmap_or(r_bitmap, r_bitmap, rm->r_bitmap,
|
||||
ICE_MAX_NUM_RECIPES);
|
||||
status = ice_acquire_change_lock(hw, ICE_RES_WRITE);
|
||||
if (status)
|
||||
goto err_unroll;
|
||||
goto err_free_recipe;
|
||||
|
||||
bitmap_to_arr64(&recp_assoc, r_bitmap, ICE_MAX_NUM_RECIPES);
|
||||
status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id,
|
||||
|
|
@ -5496,7 +5632,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
|
|||
ice_release_change_lock(hw);
|
||||
|
||||
if (status)
|
||||
goto err_unroll;
|
||||
goto err_free_recipe;
|
||||
|
||||
/* Update profile to recipe bitmap array */
|
||||
bitmap_copy(profile_to_recipe[fvit->profile_id], r_bitmap,
|
||||
|
|
@ -5510,6 +5646,16 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
|
|||
*rid = rm->root_rid;
|
||||
memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts,
|
||||
sizeof(*lkup_exts));
|
||||
goto err_unroll;
|
||||
|
||||
err_free_recipe:
|
||||
if (hw->recp_reuse) {
|
||||
for_each_set_bit(rid_tmp, rm->r_bitmap, ICE_MAX_NUM_RECIPES) {
|
||||
if (!ice_free_recipe_res(hw, rid_tmp))
|
||||
clear_bit(rid_tmp, rm->r_bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
err_unroll:
|
||||
list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) {
|
||||
list_del(&r_entry->l_entry);
|
||||
|
|
@ -6529,7 +6675,7 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
rid = ice_find_recp(hw, &lkup_exts, rinfo);
|
||||
rid = ice_find_recp(hw, &lkup_exts, rinfo, false);
|
||||
/* If did not find a recipe that match the existing criteria */
|
||||
if (rid == ICE_MAX_NUM_RECIPES)
|
||||
return -EINVAL;
|
||||
|
|
@ -6573,14 +6719,21 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
|
|||
ice_aqc_opc_remove_sw_rules, NULL);
|
||||
if (!status || status == -ENOENT) {
|
||||
struct ice_switch_info *sw = hw->switch_info;
|
||||
struct ice_sw_recipe *r_list = sw->recp_list;
|
||||
|
||||
mutex_lock(rule_lock);
|
||||
list_del(&list_elem->list_entry);
|
||||
devm_kfree(ice_hw_to_dev(hw), list_elem->lkups);
|
||||
devm_kfree(ice_hw_to_dev(hw), list_elem);
|
||||
mutex_unlock(rule_lock);
|
||||
if (list_empty(&sw->recp_list[rid].filt_rules))
|
||||
sw->recp_list[rid].adv_rule = false;
|
||||
if (list_empty(&r_list[rid].filt_rules)) {
|
||||
r_list[rid].adv_rule = false;
|
||||
|
||||
/* All rules for this recipe are now removed */
|
||||
if (hw->recp_reuse)
|
||||
ice_release_recipe_res(hw,
|
||||
&r_list[rid]);
|
||||
}
|
||||
}
|
||||
kfree(s_rule);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -432,5 +432,6 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 *r_assoc,
|
|||
int
|
||||
ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 r_assoc,
|
||||
struct ice_sq_cd *cd);
|
||||
void ice_init_chk_recipe_reuse_support(struct ice_hw *hw);
|
||||
|
||||
#endif /* _ICE_SWITCH_H_ */
|
||||
|
|
|
|||
|
|
@ -848,6 +848,8 @@ struct ice_hw {
|
|||
|
||||
u16 max_burst_size; /* driver sets this value */
|
||||
|
||||
u8 recp_reuse:1; /* indicates whether FW supports recipe reuse */
|
||||
|
||||
/* Tx Scheduler values */
|
||||
u8 num_tx_sched_layers;
|
||||
u8 num_tx_sched_phys_layers;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user