Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc0c419e authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlxsw-port-mirroring'



Jiri Pirko says:

====================
mlxsw: implement port mirroring offload

This patchset introduces tc matchall classifier and its offload
to Spectrum hardware. In combination with mirred action, defined port mirroring
setup is offloaded by mlxsw/spectrum driver.

The commands used for creating mirror ports:

tc qdisc  add dev eth25 handle ffff: ingress
tc filter add dev eth25 parent ffff:            \
        matchall skip_sw                        \
        action mirred egress mirror             \
        dev eth27

tc qdisc add dev eth25 handle 1: root prio
tc filter add dev eth25 parent 1:               \
        matchall skip_sw                        \
        action mirred egress mirror             \
        dev eth27

These patches contain:
 - Resource query implementation
 - Hardware port mirorring support for spectrum.
 - Definition of the matchall traffic classifier.
 - General support for hw-offloading for that classifier.
 - Specific spectrum implementaion for matchall offloading.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bfe9b9d2 763b4b70
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ enum mlxsw_cmd_opcode {
	MLXSW_CMD_OPCODE_SW2HW_EQ		= 0x013,
	MLXSW_CMD_OPCODE_HW2SW_EQ		= 0x014,
	MLXSW_CMD_OPCODE_QUERY_EQ		= 0x015,
	MLXSW_CMD_OPCODE_QUERY_RESOURCES	= 0x101,
};

static inline const char *mlxsw_cmd_opcode_str(u16 opcode)
@@ -144,6 +145,8 @@ static inline const char *mlxsw_cmd_opcode_str(u16 opcode)
		return "HW2SW_EQ";
	case MLXSW_CMD_OPCODE_QUERY_EQ:
		return "QUERY_EQ";
	case MLXSW_CMD_OPCODE_QUERY_RESOURCES:
		return "QUERY_RESOURCES";
	default:
		return "*UNKNOWN*";
	}
@@ -500,6 +503,35 @@ static inline int mlxsw_cmd_unmap_fa(struct mlxsw_core *mlxsw_core)
	return mlxsw_cmd_exec_none(mlxsw_core, MLXSW_CMD_OPCODE_UNMAP_FA, 0, 0);
}

/* QUERY_RESOURCES - Query chip resources
 * --------------------------------------
 * OpMod == 0 (N/A) , INMmod is index
 * ----------------------------------
 * The QUERY_RESOURCES command retrieves information related to chip resources
 * by resource ID. Every command returns 32 entries. INmod is being use as base.
 * for example, index 1 will return entries 32-63. When the tables end and there
 * are no more sources in the table, will return resource id 0xFFF to indicate
 * it.
 */
static inline int mlxsw_cmd_query_resources(struct mlxsw_core *mlxsw_core,
					    char *out_mbox, int index)
{
	return mlxsw_cmd_exec_out(mlxsw_core, MLXSW_CMD_OPCODE_QUERY_RESOURCES,
				  0, index, false, out_mbox,
				  MLXSW_CMD_MBOX_SIZE);
}

/* cmd_mbox_query_resource_id
 * The resource id. 0xFFFF indicates table's end.
 */
MLXSW_ITEM32_INDEXED(cmd_mbox, query_resource, id, 0x00, 16, 16, 0x8, 0, false);

/* cmd_mbox_query_resource_data
 * The resource
 */
MLXSW_ITEM64_INDEXED(cmd_mbox, query_resource, data,
		     0x00, 0, 40, 0x8, 0, false);

/* CONFIG_PROFILE (Set) - Configure Switch Profile
 * ------------------------------
 * OpMod == 1 (Set), INMmod == 0 (N/A)
+9 −1
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ struct mlxsw_core {
	struct {
		u8 *mapping; /* lag_id+port_index to local_port mapping */
	} lag;
	struct mlxsw_resources resources;
	struct mlxsw_hwmon *hwmon;
	unsigned long driver_priv[0];
	/* driver_priv has to be always the last item */
@@ -1110,7 +1111,8 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
		}
	}

	err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile);
	err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile,
			      &mlxsw_core->resources);
	if (err)
		goto err_bus_init;

@@ -1652,6 +1654,12 @@ void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core,
}
EXPORT_SYMBOL(mlxsw_core_lag_mapping_clear);

struct mlxsw_resources *mlxsw_core_resources_get(struct mlxsw_core *mlxsw_core)
{
	return &mlxsw_core->resources;
}
EXPORT_SYMBOL(mlxsw_core_resources_get);

int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core,
			 struct mlxsw_core_port *mlxsw_core_port, u8 local_port,
			 struct net_device *dev, bool split, u32 split_group)
+10 −1
Original line number Diff line number Diff line
@@ -215,6 +215,7 @@ struct mlxsw_config_profile {
	u32	kvd_linear_size;
	u32	kvd_hash_single_size;
	u32	kvd_hash_double_size;
	u8	resource_query_enable;
	struct mlxsw_swid_config swid_config[MLXSW_CONFIG_PROFILE_SWID_COUNT];
};

@@ -266,10 +267,18 @@ struct mlxsw_driver {
	const struct mlxsw_config_profile *profile;
};

struct mlxsw_resources {
	u8	max_span_valid:1;
	u8      max_span;
};

struct mlxsw_resources *mlxsw_core_resources_get(struct mlxsw_core *mlxsw_core);

struct mlxsw_bus {
	const char *kind;
	int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core,
		    const struct mlxsw_config_profile *profile);
		    const struct mlxsw_config_profile *profile,
		    struct mlxsw_resources *resources);
	void (*fini)(void *bus_priv);
	bool (*skb_transmit_busy)(void *bus_priv,
				  const struct mlxsw_tx_info *tx_info);
+63 −1
Original line number Diff line number Diff line
@@ -1154,6 +1154,61 @@ mlxsw_pci_config_profile_swid_config(struct mlxsw_pci *mlxsw_pci,
	mlxsw_cmd_mbox_config_profile_swid_config_mask_set(mbox, index, mask);
}

#define MLXSW_RESOURCES_TABLE_END_ID 0xffff
#define MLXSW_MAX_SPAN_ID 0x2420
#define MLXSW_RESOURCES_QUERY_MAX_QUERIES 100
#define MLXSW_RESOURCES_PER_QUERY 32

static void mlxsw_pci_resources_query_parse(int id, u64 val,
					    struct mlxsw_resources *resources)
{
	switch (id) {
	case MLXSW_MAX_SPAN_ID:
		resources->max_span = val;
		resources->max_span_valid = 1;
		break;
	default:
		break;
	}
}

static int mlxsw_pci_resources_query(struct mlxsw_pci *mlxsw_pci, char *mbox,
				     struct mlxsw_resources *resources,
				     u8 query_enabled)
{
	int index, i;
	u64 data;
	u16 id;
	int err;

	/* Not all the versions support resources query */
	if (!query_enabled)
		return 0;

	mlxsw_cmd_mbox_zero(mbox);

	for (index = 0; index < MLXSW_RESOURCES_QUERY_MAX_QUERIES; index++) {
		err = mlxsw_cmd_query_resources(mlxsw_pci->core, mbox, index);
		if (err)
			return err;

		for (i = 0; i < MLXSW_RESOURCES_PER_QUERY; i++) {
			id = mlxsw_cmd_mbox_query_resource_id_get(mbox, i);
			data = mlxsw_cmd_mbox_query_resource_data_get(mbox, i);

			if (id == MLXSW_RESOURCES_TABLE_END_ID)
				return 0;

			mlxsw_pci_resources_query_parse(id, data, resources);
		}
	}

	/* If after MLXSW_RESOURCES_QUERY_MAX_QUERIES we still didn't get
	 * MLXSW_RESOURCES_TABLE_END_ID, something went bad in the FW.
	 */
	return -EIO;
}

static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox,
				    const struct mlxsw_config_profile *profile)
{
@@ -1404,7 +1459,8 @@ static void mlxsw_pci_mbox_free(struct mlxsw_pci *mlxsw_pci,
}

static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
			  const struct mlxsw_config_profile *profile)
			  const struct mlxsw_config_profile *profile,
			  struct mlxsw_resources *resources)
{
	struct mlxsw_pci *mlxsw_pci = bus_priv;
	struct pci_dev *pdev = mlxsw_pci->pdev;
@@ -1463,6 +1519,11 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
	if (err)
		goto err_boardinfo;

	err = mlxsw_pci_resources_query(mlxsw_pci, mbox, resources,
					profile->resource_query_enable);
	if (err)
		goto err_query_resources;

	err = mlxsw_pci_config_profile(mlxsw_pci, mbox, profile);
	if (err)
		goto err_config_profile;
@@ -1485,6 +1546,7 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
	mlxsw_pci_aqs_fini(mlxsw_pci);
err_aqs_init:
err_config_profile:
err_query_resources:
err_boardinfo:
	mlxsw_pci_fw_area_fini(mlxsw_pci);
err_fw_area_init:
+162 −0
Original line number Diff line number Diff line
@@ -4633,6 +4633,123 @@ static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp,
		mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name);
}

/* MPAT - Monitoring Port Analyzer Table
 * -------------------------------------
 * MPAT Register is used to query and configure the Switch PortAnalyzer Table.
 * For an enabled analyzer, all fields except e (enable) cannot be modified.
 */
#define MLXSW_REG_MPAT_ID 0x901A
#define MLXSW_REG_MPAT_LEN 0x78

static const struct mlxsw_reg_info mlxsw_reg_mpat = {
	.id = MLXSW_REG_MPAT_ID,
	.len = MLXSW_REG_MPAT_LEN,
};

/* reg_mpat_pa_id
 * Port Analyzer ID.
 * Access: Index
 */
MLXSW_ITEM32(reg, mpat, pa_id, 0x00, 28, 4);

/* reg_mpat_system_port
 * A unique port identifier for the final destination of the packet.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, system_port, 0x00, 0, 16);

/* reg_mpat_e
 * Enable. Indicating the Port Analyzer is enabled.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, e, 0x04, 31, 1);

/* reg_mpat_qos
 * Quality Of Service Mode.
 * 0: CONFIGURED - QoS parameters (Switch Priority, and encapsulation
 * PCP, DEI, DSCP or VL) are configured.
 * 1: MAINTAIN - QoS parameters (Switch Priority, Color) are the
 * same as in the original packet that has triggered the mirroring. For
 * SPAN also the pcp,dei are maintained.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, qos, 0x04, 26, 1);

/* reg_mpat_be
 * Best effort mode. Indicates mirroring traffic should not cause packet
 * drop or back pressure, but will discard the mirrored packets. Mirrored
 * packets will be forwarded on a best effort manner.
 * 0: Do not discard mirrored packets
 * 1: Discard mirrored packets if causing congestion
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, be, 0x04, 25, 1);

static inline void mlxsw_reg_mpat_pack(char *payload, u8 pa_id,
				       u16 system_port, bool e)
{
	MLXSW_REG_ZERO(mpat, payload);
	mlxsw_reg_mpat_pa_id_set(payload, pa_id);
	mlxsw_reg_mpat_system_port_set(payload, system_port);
	mlxsw_reg_mpat_e_set(payload, e);
	mlxsw_reg_mpat_qos_set(payload, 1);
	mlxsw_reg_mpat_be_set(payload, 1);
}

/* MPAR - Monitoring Port Analyzer Register
 * ----------------------------------------
 * MPAR register is used to query and configure the port analyzer port mirroring
 * properties.
 */
#define MLXSW_REG_MPAR_ID 0x901B
#define MLXSW_REG_MPAR_LEN 0x08

static const struct mlxsw_reg_info mlxsw_reg_mpar = {
	.id = MLXSW_REG_MPAR_ID,
	.len = MLXSW_REG_MPAR_LEN,
};

/* reg_mpar_local_port
 * The local port to mirror the packets from.
 * Access: Index
 */
MLXSW_ITEM32(reg, mpar, local_port, 0x00, 16, 8);

enum mlxsw_reg_mpar_i_e {
	MLXSW_REG_MPAR_TYPE_EGRESS,
	MLXSW_REG_MPAR_TYPE_INGRESS,
};

/* reg_mpar_i_e
 * Ingress/Egress
 * Access: Index
 */
MLXSW_ITEM32(reg, mpar, i_e, 0x00, 0, 4);

/* reg_mpar_enable
 * Enable mirroring
 * By default, port mirroring is disabled for all ports.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpar, enable, 0x04, 31, 1);

/* reg_mpar_pa_id
 * Port Analyzer ID.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpar, pa_id, 0x04, 0, 4);

static inline void mlxsw_reg_mpar_pack(char *payload, u8 local_port,
				       enum mlxsw_reg_mpar_i_e i_e,
				       bool enable, u8 pa_id)
{
	MLXSW_REG_ZERO(mpar, payload);
	mlxsw_reg_mpar_local_port_set(payload, local_port);
	mlxsw_reg_mpar_enable_set(payload, enable);
	mlxsw_reg_mpar_i_e_set(payload, i_e);
	mlxsw_reg_mpar_pa_id_set(payload, pa_id);
}

/* MLCR - Management LED Control Register
 * --------------------------------------
 * Controls the system LEDs.
@@ -5062,6 +5179,45 @@ static inline void mlxsw_reg_sbsr_rec_unpack(char *payload, int rec_index,
		mlxsw_reg_sbsr_rec_max_buff_occupancy_get(payload, rec_index);
}

/* SBIB - Shared Buffer Internal Buffer Register
 * ---------------------------------------------
 * The SBIB register configures per port buffers for internal use. The internal
 * buffers consume memory on the port buffers (note that the port buffers are
 * used also by PBMC).
 *
 * For Spectrum this is used for egress mirroring.
 */
#define MLXSW_REG_SBIB_ID 0xB006
#define MLXSW_REG_SBIB_LEN 0x10

static const struct mlxsw_reg_info mlxsw_reg_sbib = {
	.id = MLXSW_REG_SBIB_ID,
	.len = MLXSW_REG_SBIB_LEN,
};

/* reg_sbib_local_port
 * Local port number
 * Not supported for CPU port and router port
 * Access: Index
 */
MLXSW_ITEM32(reg, sbib, local_port, 0x00, 16, 8);

/* reg_sbib_buff_size
 * Units represented in cells
 * Allowed range is 0 to (cap_max_headroom_size - 1)
 * Default is 0
 * Access: RW
 */
MLXSW_ITEM32(reg, sbib, buff_size, 0x08, 0, 24);

static inline void mlxsw_reg_sbib_pack(char *payload, u8 local_port,
				       u32 buff_size)
{
	MLXSW_REG_ZERO(sbib, payload);
	mlxsw_reg_sbib_local_port_set(payload, local_port);
	mlxsw_reg_sbib_buff_size_set(payload, buff_size);
}

static inline const char *mlxsw_reg_id_str(u16 reg_id)
{
	switch (reg_id) {
@@ -5165,6 +5321,10 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id)
		return "MFSM";
	case MLXSW_REG_MTCAP_ID:
		return "MTCAP";
	case MLXSW_REG_MPAT_ID:
		return "MPAT";
	case MLXSW_REG_MPAR_ID:
		return "MPAR";
	case MLXSW_REG_MTMP_ID:
		return "MTMP";
	case MLXSW_REG_MLCR_ID:
@@ -5179,6 +5339,8 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id)
		return "SBMM";
	case MLXSW_REG_SBSR_ID:
		return "SBSR";
	case MLXSW_REG_SBIB_ID:
		return "SBIB";
	default:
		return "*UNKNOWN*";
	}
Loading