diff options
Diffstat (limited to 'drivers/staging/fsl-dpaa2')
-rw-r--r-- | drivers/staging/fsl-dpaa2/Kconfig | 20 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/Makefile | 6 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/Makefile | 10 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/README | 106 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/TODO | 13 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 458 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/dpsw.c | 1486 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/dpsw.h | 751 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c | 189 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 2901 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/ethsw.h | 178 |
11 files changed, 0 insertions, 6118 deletions
diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig deleted file mode 100644 index 7cb005b6e7ab..000000000000 --- a/drivers/staging/fsl-dpaa2/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Freescale DataPath Acceleration Architecture Gen2 (DPAA2) drivers -# - -config FSL_DPAA2 - bool "Freescale DPAA2 devices" - depends on FSL_MC_BUS - help - Build drivers for Freescale DataPath Acceleration - Architecture (DPAA2) family of SoCs. - -config FSL_DPAA2_ETHSW - tristate "Freescale DPAA2 Ethernet Switch" - depends on BRIDGE || BRIDGE=n - depends on FSL_DPAA2 - depends on NET_SWITCHDEV - help - Driver for Freescale DPAA2 Ethernet Switch. Select - BRIDGE to have support for bridge tools. diff --git a/drivers/staging/fsl-dpaa2/Makefile b/drivers/staging/fsl-dpaa2/Makefile deleted file mode 100644 index 9645db7689c9..000000000000 --- a/drivers/staging/fsl-dpaa2/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Freescale DataPath Acceleration Architecture Gen2 (DPAA2) drivers -# - -obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/ diff --git a/drivers/staging/fsl-dpaa2/ethsw/Makefile b/drivers/staging/fsl-dpaa2/ethsw/Makefile deleted file mode 100644 index f6f2cf798faf..000000000000 --- a/drivers/staging/fsl-dpaa2/ethsw/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the Freescale DPAA2 Ethernet Switch -# -# Copyright 2014-2017 Freescale Semiconductor Inc. -# Copyright 2017-2018 NXP - -obj-$(CONFIG_FSL_DPAA2_ETHSW) += dpaa2-ethsw.o - -dpaa2-ethsw-objs := ethsw.o ethsw-ethtool.o dpsw.o diff --git a/drivers/staging/fsl-dpaa2/ethsw/README b/drivers/staging/fsl-dpaa2/ethsw/README deleted file mode 100644 index b48dcbf7c5fb..000000000000 --- a/drivers/staging/fsl-dpaa2/ethsw/README +++ /dev/null @@ -1,106 +0,0 @@ -DPAA2 Ethernet Switch driver -============================ - -This file provides documentation for the DPAA2 Ethernet Switch driver - - -Contents -======== - Supported Platforms - Architecture Overview - Creating an Ethernet Switch - Features - - - Supported Platforms -=================== -This driver provides networking support for Freescale LS2085A, LS2088A -DPAA2 SoCs. - - -Architecture Overview -===================== -The Ethernet Switch in the DPAA2 architecture consists of several hardware -resources that provide the functionality. These are allocated and -configured via the Management Complex (MC) portals. MC abstracts most of -these resources as DPAA2 objects and exposes ABIs through which they can -be configured and controlled. - -For a more detailed description of the DPAA2 architecture and its object -abstractions see: - drivers/staging/fsl-mc/README.txt - -The Ethernet Switch is built on top of a Datapath Switch (DPSW) object. - -Configuration interface: - - --------------------- - | DPAA2 Switch driver | - --------------------- - . - . - ---------- - | DPSW API | - ---------- - . software - ================= . ============== - . hardware - --------------------- - | MC hardware portals | - --------------------- - . - . - ------ - | DPSW | - ------ - -Driver uses the switch device driver model and exposes each switch port as -a network interface, which can be included in a bridge. Traffic switched -between ports is offloaded into the hardware. Exposed network interfaces -are not used for I/O, they are used just for configuration. This -limitation is going to be addressed in the future. - -The DPSW can have ports connected to DPNIs or to PHYs via DPMACs. - - - [ethA] [ethB] [ethC] [ethD] [ethE] [ethF] - : : : : : : - : : : : : : -[eth drv] [eth drv] [ ethsw drv ] - : : : : : : kernel -======================================================================== - : : : : : : hardware - [DPNI] [DPNI] [============= DPSW =================] - | | | | | | - | ---------- | [DPMAC] [DPMAC] - ------------------------------- | | - | | - [PHY] [PHY] - -For a more detailed description of the Ethernet switch device driver model -see: - Documentation/networking/switchdev.rst - -Creating an Ethernet Switch -=========================== -A device is created for the switch objects probed on the MC bus. Each DPSW -has a number of properties which determine the configuration options and -associated hardware resources. - -A DPSW object (and the other DPAA2 objects needed for a DPAA2 switch) can -be added to a container on the MC bus in one of two ways: statically, -through a Datapath Layout Binary file (DPL) that is parsed by MC at boot -time; or created dynamically at runtime, via the DPAA2 objects APIs. - -Features -======== -Driver configures DPSW to perform hardware switching offload of -unicast/multicast/broadcast (VLAN tagged or untagged) traffic between its -ports. - -It allows configuration of hardware learning, flooding, multicast groups, -port VLAN configuration and STP state. - -Static entries can be added/removed from the FDB. - -Hardware statistics for each port are provided through ethtool -S option. diff --git a/drivers/staging/fsl-dpaa2/ethsw/TODO b/drivers/staging/fsl-dpaa2/ethsw/TODO deleted file mode 100644 index 4d46857b0b2b..000000000000 --- a/drivers/staging/fsl-dpaa2/ethsw/TODO +++ /dev/null @@ -1,13 +0,0 @@ -* Add I/O capabilities on switch port netdevices. This will allow control -traffic to reach the CPU. -* Add ACL to redirect control traffic to CPU. -* Add support for multiple FDBs and switch port partitioning -* MC firmware uprev; the DPAA2 objects used by the Ethernet Switch driver -need to be kept in sync with binary interface changes in MC -* refine README file -* cleanup - -NOTE: At least first three of the above are required before getting the -DPAA2 Ethernet Switch driver out of staging. Another requirement is that -dpio driver is moved to drivers/soc (this is required for I/O). - diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h deleted file mode 100644 index eb620e832412..000000000000 --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h +++ /dev/null @@ -1,458 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2017-2021 NXP - * - */ - -#ifndef __FSL_DPSW_CMD_H -#define __FSL_DPSW_CMD_H - -#include "dpsw.h" - -/* DPSW Version */ -#define DPSW_VER_MAJOR 8 -#define DPSW_VER_MINOR 9 - -#define DPSW_CMD_BASE_VERSION 1 -#define DPSW_CMD_VERSION_2 2 -#define DPSW_CMD_ID_OFFSET 4 - -#define DPSW_CMD_ID(id) (((id) << DPSW_CMD_ID_OFFSET) | DPSW_CMD_BASE_VERSION) -#define DPSW_CMD_V2(id) (((id) << DPSW_CMD_ID_OFFSET) | DPSW_CMD_VERSION_2) - -/* Command IDs */ -#define DPSW_CMDID_CLOSE DPSW_CMD_ID(0x800) -#define DPSW_CMDID_OPEN DPSW_CMD_ID(0x802) - -#define DPSW_CMDID_GET_API_VERSION DPSW_CMD_ID(0xa02) - -#define DPSW_CMDID_ENABLE DPSW_CMD_ID(0x002) -#define DPSW_CMDID_DISABLE DPSW_CMD_ID(0x003) -#define DPSW_CMDID_GET_ATTR DPSW_CMD_V2(0x004) -#define DPSW_CMDID_RESET DPSW_CMD_ID(0x005) - -#define DPSW_CMDID_SET_IRQ_ENABLE DPSW_CMD_ID(0x012) - -#define DPSW_CMDID_SET_IRQ_MASK DPSW_CMD_ID(0x014) - -#define DPSW_CMDID_GET_IRQ_STATUS DPSW_CMD_ID(0x016) -#define DPSW_CMDID_CLEAR_IRQ_STATUS DPSW_CMD_ID(0x017) - -#define DPSW_CMDID_IF_SET_TCI DPSW_CMD_ID(0x030) -#define DPSW_CMDID_IF_SET_STP DPSW_CMD_ID(0x031) - -#define DPSW_CMDID_IF_GET_COUNTER DPSW_CMD_V2(0x034) - -#define DPSW_CMDID_IF_ENABLE DPSW_CMD_ID(0x03D) -#define DPSW_CMDID_IF_DISABLE DPSW_CMD_ID(0x03E) - -#define DPSW_CMDID_IF_GET_ATTR DPSW_CMD_ID(0x042) - -#define DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH DPSW_CMD_ID(0x044) - -#define DPSW_CMDID_IF_GET_LINK_STATE DPSW_CMD_ID(0x046) - -#define DPSW_CMDID_IF_GET_TCI DPSW_CMD_ID(0x04A) - -#define DPSW_CMDID_IF_SET_LINK_CFG DPSW_CMD_ID(0x04C) - -#define DPSW_CMDID_VLAN_ADD DPSW_CMD_ID(0x060) -#define DPSW_CMDID_VLAN_ADD_IF DPSW_CMD_V2(0x061) -#define DPSW_CMDID_VLAN_ADD_IF_UNTAGGED DPSW_CMD_ID(0x062) - -#define DPSW_CMDID_VLAN_REMOVE_IF DPSW_CMD_ID(0x064) -#define DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED DPSW_CMD_ID(0x065) -#define DPSW_CMDID_VLAN_REMOVE_IF_FLOODING DPSW_CMD_ID(0x066) -#define DPSW_CMDID_VLAN_REMOVE DPSW_CMD_ID(0x067) - -#define DPSW_CMDID_FDB_ADD DPSW_CMD_ID(0x082) -#define DPSW_CMDID_FDB_REMOVE DPSW_CMD_ID(0x083) -#define DPSW_CMDID_FDB_ADD_UNICAST DPSW_CMD_ID(0x084) -#define DPSW_CMDID_FDB_REMOVE_UNICAST DPSW_CMD_ID(0x085) -#define DPSW_CMDID_FDB_ADD_MULTICAST DPSW_CMD_ID(0x086) -#define DPSW_CMDID_FDB_REMOVE_MULTICAST DPSW_CMD_ID(0x087) -#define DPSW_CMDID_FDB_DUMP DPSW_CMD_ID(0x08A) - -#define DPSW_CMDID_IF_GET_PORT_MAC_ADDR DPSW_CMD_ID(0x0A7) -#define DPSW_CMDID_IF_GET_PRIMARY_MAC_ADDR DPSW_CMD_ID(0x0A8) -#define DPSW_CMDID_IF_SET_PRIMARY_MAC_ADDR DPSW_CMD_ID(0x0A9) - -#define DPSW_CMDID_CTRL_IF_GET_ATTR DPSW_CMD_ID(0x0A0) -#define DPSW_CMDID_CTRL_IF_SET_POOLS DPSW_CMD_ID(0x0A1) -#define DPSW_CMDID_CTRL_IF_ENABLE DPSW_CMD_ID(0x0A2) -#define DPSW_CMDID_CTRL_IF_DISABLE DPSW_CMD_ID(0x0A3) -#define DPSW_CMDID_CTRL_IF_SET_QUEUE DPSW_CMD_ID(0x0A6) - -#define DPSW_CMDID_SET_EGRESS_FLOOD DPSW_CMD_ID(0x0AC) - -/* Macros for accessing command fields smaller than 1byte */ -#define DPSW_MASK(field) \ - GENMASK(DPSW_##field##_SHIFT + DPSW_##field##_SIZE - 1, \ - DPSW_##field##_SHIFT) -#define dpsw_set_field(var, field, val) \ - ((var) |= (((val) << DPSW_##field##_SHIFT) & DPSW_MASK(field))) -#define dpsw_get_field(var, field) \ - (((var) & DPSW_MASK(field)) >> DPSW_##field##_SHIFT) -#define dpsw_get_bit(var, bit) \ - (((var) >> (bit)) & GENMASK(0, 0)) - -#pragma pack(push, 1) -struct dpsw_cmd_open { - __le32 dpsw_id; -}; - -#define DPSW_COMPONENT_TYPE_SHIFT 0 -#define DPSW_COMPONENT_TYPE_SIZE 4 - -struct dpsw_cmd_create { - /* cmd word 0 */ - __le16 num_ifs; - u8 max_fdbs; - u8 max_meters_per_if; - /* from LSB: only the first 4 bits */ - u8 component_type; - u8 pad[3]; - /* cmd word 1 */ - __le16 max_vlans; - __le16 max_fdb_entries; - __le16 fdb_aging_time; - __le16 max_fdb_mc_groups; - /* cmd word 2 */ - __le64 options; -}; - -struct dpsw_cmd_destroy { - __le32 dpsw_id; -}; - -#define DPSW_ENABLE_SHIFT 0 -#define DPSW_ENABLE_SIZE 1 - -struct dpsw_rsp_is_enabled { - /* from LSB: enable:1 */ - u8 enabled; -}; - -struct dpsw_cmd_set_irq_enable { - u8 enable_state; - u8 pad[3]; - u8 irq_index; -}; - -struct dpsw_cmd_get_irq_enable { - __le32 pad; - u8 irq_index; -}; - -struct dpsw_rsp_get_irq_enable { - u8 enable_state; -}; - -struct dpsw_cmd_set_irq_mask { - __le32 mask; - u8 irq_index; -}; - -struct dpsw_cmd_get_irq_mask { - __le32 pad; - u8 irq_index; -}; - -struct dpsw_rsp_get_irq_mask { - __le32 mask; -}; - -struct dpsw_cmd_get_irq_status { - __le32 status; - u8 irq_index; -}; - -struct dpsw_rsp_get_irq_status { - __le32 status; -}; - -struct dpsw_cmd_clear_irq_status { - __le32 status; - u8 irq_index; -}; - -#define DPSW_COMPONENT_TYPE_SHIFT 0 -#define DPSW_COMPONENT_TYPE_SIZE 4 - -#define DPSW_FLOODING_CFG_SHIFT 0 -#define DPSW_FLOODING_CFG_SIZE 4 - -#define DPSW_BROADCAST_CFG_SHIFT 4 -#define DPSW_BROADCAST_CFG_SIZE 4 - -struct dpsw_rsp_get_attr { - /* cmd word 0 */ - __le16 num_ifs; - u8 max_fdbs; - u8 num_fdbs; - __le16 max_vlans; - __le16 num_vlans; - /* cmd word 1 */ - __le16 max_fdb_entries; - __le16 fdb_aging_time; - __le32 dpsw_id; - /* cmd word 2 */ - __le16 mem_size; - __le16 max_fdb_mc_groups; - u8 max_meters_per_if; - /* from LSB only the first 4 bits */ - u8 component_type; - /* [0:3] - flooding configuration - * [4:7] - broadcast configuration - */ - u8 repl_cfg; - u8 pad; - /* cmd word 3 */ - __le64 options; -}; - -#define DPSW_VLAN_ID_SHIFT 0 -#define DPSW_VLAN_ID_SIZE 12 -#define DPSW_DEI_SHIFT 12 -#define DPSW_DEI_SIZE 1 -#define DPSW_PCP_SHIFT 13 -#define DPSW_PCP_SIZE 3 - -struct dpsw_cmd_if_set_tci { - __le16 if_id; - /* from LSB: VLAN_ID:12 DEI:1 PCP:3 */ - __le16 conf; -}; - -struct dpsw_cmd_if_get_tci { - __le16 if_id; -}; - -struct dpsw_rsp_if_get_tci { - __le16 pad; - __le16 vlan_id; - u8 dei; - u8 pcp; -}; - -#define DPSW_STATE_SHIFT 0 -#define DPSW_STATE_SIZE 4 - -struct dpsw_cmd_if_set_stp { - __le16 if_id; - __le16 vlan_id; - /* only the first LSB 4 bits */ - u8 state; -}; - -#define DPSW_COUNTER_TYPE_SHIFT 0 -#define DPSW_COUNTER_TYPE_SIZE 5 - -struct dpsw_cmd_if_get_counter { - __le16 if_id; - /* from LSB: type:5 */ - u8 type; -}; - -struct dpsw_rsp_if_get_counter { - __le64 pad; - __le64 counter; -}; - -struct dpsw_cmd_if { - __le16 if_id; -}; - -#define DPSW_ADMIT_UNTAGGED_SHIFT 0 -#define DPSW_ADMIT_UNTAGGED_SIZE 4 -#define DPSW_ENABLED_SHIFT 5 -#define DPSW_ENABLED_SIZE 1 -#define DPSW_ACCEPT_ALL_VLAN_SHIFT 6 -#define DPSW_ACCEPT_ALL_VLAN_SIZE 1 - -struct dpsw_rsp_if_get_attr { - /* cmd word 0 */ - /* from LSB: admit_untagged:4 enabled:1 accept_all_vlan:1 */ - u8 conf; - u8 pad1; - u8 num_tcs; - u8 pad2; - __le16 qdid; - /* cmd word 1 */ - __le32 options; - __le32 pad3; - /* cmd word 2 */ - __le32 rate; -}; - -struct dpsw_cmd_if_set_max_frame_length { - __le16 if_id; - __le16 frame_length; -}; - -struct dpsw_cmd_if_set_link_cfg { - /* cmd word 0 */ - __le16 if_id; - u8 pad[6]; - /* cmd word 1 */ - __le32 rate; - __le32 pad1; - /* cmd word 2 */ - __le64 options; -}; - -struct dpsw_cmd_if_get_link_state { - __le16 if_id; -}; - -#define DPSW_UP_SHIFT 0 -#define DPSW_UP_SIZE 1 - -struct dpsw_rsp_if_get_link_state { - /* cmd word 0 */ - __le32 pad0; - u8 up; - u8 pad1[3]; - /* cmd word 1 */ - __le32 rate; - __le32 pad2; - /* cmd word 2 */ - __le64 options; -}; - -struct dpsw_vlan_add { - __le16 fdb_id; - __le16 vlan_id; -}; - -struct dpsw_cmd_vlan_add_if { - /* cmd word 0 */ - __le16 options; - __le16 vlan_id; - __le16 fdb_id; - __le16 pad0; - /* cmd word 1-4 */ - __le64 if_id; -}; - -struct dpsw_cmd_vlan_manage_if { - /* cmd word 0 */ - __le16 pad0; - __le16 vlan_id; - __le32 pad1; - /* cmd word 1-4 */ - __le64 if_id[4]; -}; - -struct dpsw_cmd_vlan_remove { - __le16 pad; - __le16 vlan_id; -}; - -struct dpsw_cmd_fdb_add { - __le32 pad; - __le16 fdb_ageing_time; - __le16 num_fdb_entries; -}; - -struct dpsw_rsp_fdb_add { - __le16 fdb_id; -}; - -struct dpsw_cmd_fdb_remove { - __le16 fdb_id; -}; - -#define DPSW_ENTRY_TYPE_SHIFT 0 -#define DPSW_ENTRY_TYPE_SIZE 4 - -struct dpsw_cmd_fdb_unicast_op { - /* cmd word 0 */ - __le16 fdb_id; - u8 mac_addr[6]; - /* cmd word 1 */ - __le16 if_egress; - /* only the first 4 bits from LSB */ - u8 type; -}; - -struct dpsw_cmd_fdb_multicast_op { - /* cmd word 0 */ - __le16 fdb_id; - __le16 num_ifs; - /* only the first 4 bits from LSB */ - u8 type; - u8 pad[3]; - /* cmd word 1 */ - u8 mac_addr[6]; - __le16 pad2; - /* cmd word 2-5 */ - __le64 if_id[4]; -}; - -struct dpsw_cmd_fdb_dump { - __le16 fdb_id; - __le16 pad0; - __le32 pad1; - __le64 iova_addr; - __le32 iova_size; -}; - -struct dpsw_rsp_fdb_dump { - __le16 num_entries; -}; - -struct dpsw_rsp_ctrl_if_get_attr { - __le64 pad; - __le32 rx_fqid; - __le32 rx_err_fqid; - __le32 tx_err_conf_fqid; -}; - -#define DPSW_BACKUP_POOL(val, order) (((val) & 0x1) << (order)) -struct dpsw_cmd_ctrl_if_set_pools { - u8 num_dpbp; - u8 backup_pool_mask; - __le16 pad; - __le32 dpbp_id[DPSW_MAX_DPBP]; - __le16 buffer_size[DPSW_MAX_DPBP]; -}; - -#define DPSW_DEST_TYPE_SHIFT 0 -#define DPSW_DEST_TYPE_SIZE 4 - -struct dpsw_cmd_ctrl_if_set_queue { - __le32 dest_id; - u8 dest_priority; - u8 pad; - /* from LSB: dest_type:4 */ - u8 dest_type; - u8 qtype; - __le64 user_ctx; - __le32 options; -}; - -struct dpsw_rsp_get_api_version { - __le16 version_major; - __le16 version_minor; -}; - -struct dpsw_rsp_if_get_mac_addr { - __le16 pad; - u8 mac_addr[6]; -}; - -struct dpsw_cmd_if_set_mac_addr { - __le16 if_id; - u8 mac_addr[6]; -}; - -struct dpsw_cmd_set_egress_flood { - __le16 fdb_id; - u8 flood_type; - u8 pad[5]; - __le64 if_id; -}; -#pragma pack(pop) -#endif /* __FSL_DPSW_CMD_H */ diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c deleted file mode 100644 index 5189f156100e..000000000000 --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c +++ /dev/null @@ -1,1486 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2017-2021 NXP - * - */ - -#include <linux/fsl/mc.h> -#include "dpsw.h" -#include "dpsw-cmd.h" - -static void build_if_id_bitmap(__le64 *bmap, - const u16 *id, - const u16 num_ifs) -{ - int i; - - for (i = 0; (i < num_ifs) && (i < DPSW_MAX_IF); i++) { - if (id[i] < DPSW_MAX_IF) - bmap[id[i] / 64] |= cpu_to_le64(BIT_MASK(id[i] % 64)); - } -} - -/** - * dpsw_open() - Open a control session for the specified object - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @dpsw_id: DPSW unique ID - * @token: Returned token; use in subsequent API calls - * - * This function can be used to open a control session for an - * already created object; an object may have been declared in - * the DPL or by calling the dpsw_create() function. - * This function returns a unique authentication token, - * associated with the specific object ID and the specific MC - * portal; this token must be used in all subsequent commands for - * this specific object - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_open(struct fsl_mc_io *mc_io, - u32 cmd_flags, - int dpsw_id, - u16 *token) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_open *cmd_params; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_OPEN, - cmd_flags, - 0); - cmd_params = (struct dpsw_cmd_open *)cmd.params; - cmd_params->dpsw_id = cpu_to_le32(dpsw_id); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - *token = mc_cmd_hdr_read_token(&cmd); - - return 0; -} - -/** - * dpsw_close() - Close the control session of the object - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * - * After this function is called, no further operations are - * allowed on the object without opening a new control session. - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_close(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token) -{ - struct fsl_mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLOSE, - cmd_flags, - token); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_enable() - Enable DPSW functionality - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token) -{ - struct fsl_mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_ENABLE, - cmd_flags, - token); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_disable() - Disable DPSW functionality - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_disable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token) -{ - struct fsl_mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_DISABLE, - cmd_flags, - token); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_reset() - Reset the DPSW, returns the object to initial state. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_reset(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token) -{ - struct fsl_mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_RESET, - cmd_flags, - token); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_set_irq_enable() - Set overall interrupt state. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPCI object - * @irq_index: The interrupt index to configure - * @en: Interrupt state - enable = 1, disable = 0 - * - * Allows GPP software to control when interrupts are generated. - * Each interrupt can have up to 32 causes. The enable/disable control's the - * overall interrupt state. if the interrupt is disabled no causes will cause - * an interrupt - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_set_irq_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u8 en) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_set_irq_enable *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_ENABLE, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_set_irq_enable *)cmd.params; - dpsw_set_field(cmd_params->enable_state, ENABLE, en); - cmd_params->irq_index = irq_index; - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_set_irq_mask() - Set interrupt mask. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPCI object - * @irq_index: The interrupt index to configure - * @mask: Event mask to trigger interrupt; - * each bit: - * 0 = ignore event - * 1 = consider event for asserting IRQ - * - * Every interrupt can have up to 32 causes and the interrupt model supports - * masking/unmasking each cause independently - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_set_irq_mask(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 mask) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_set_irq_mask *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_MASK, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_set_irq_mask *)cmd.params; - cmd_params->mask = cpu_to_le32(mask); - cmd_params->irq_index = irq_index; - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_get_irq_status() - Get the current status of any pending interrupts - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @irq_index: The interrupt index to configure - * @status: Returned interrupts status - one bit per cause: - * 0 = no interrupt pending - * 1 = interrupt pending - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_get_irq_status(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 *status) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_get_irq_status *cmd_params; - struct dpsw_rsp_get_irq_status *rsp_params; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_IRQ_STATUS, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_get_irq_status *)cmd.params; - cmd_params->status = cpu_to_le32(*status); - cmd_params->irq_index = irq_index; - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - rsp_params = (struct dpsw_rsp_get_irq_status *)cmd.params; - *status = le32_to_cpu(rsp_params->status); - - return 0; -} - -/** - * dpsw_clear_irq_status() - Clear a pending interrupt's status - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPCI object - * @irq_index: The interrupt index to configure - * @status: bits to clear (W1C) - one bit per cause: - * 0 = don't change - * 1 = clear status bit - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_clear_irq_status(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 status) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_clear_irq_status *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLEAR_IRQ_STATUS, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_clear_irq_status *)cmd.params; - cmd_params->status = cpu_to_le32(status); - cmd_params->irq_index = irq_index; - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_get_attributes() - Retrieve DPSW attributes - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @attr: Returned DPSW attributes - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_get_attributes(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - struct dpsw_attr *attr) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_rsp_get_attr *rsp_params; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_ATTR, - cmd_flags, - token); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - rsp_params = (struct dpsw_rsp_get_attr *)cmd.params; - attr->num_ifs = le16_to_cpu(rsp_params->num_ifs); - attr->max_fdbs = rsp_params->max_fdbs; - attr->num_fdbs = rsp_params->num_fdbs; - attr->max_vlans = le16_to_cpu(rsp_params->max_vlans); - attr->num_vlans = le16_to_cpu(rsp_params->num_vlans); - attr->max_fdb_entries = le16_to_cpu(rsp_params->max_fdb_entries); - attr->fdb_aging_time = le16_to_cpu(rsp_params->fdb_aging_time); - attr->id = le32_to_cpu(rsp_params->dpsw_id); - attr->mem_size = le16_to_cpu(rsp_params->mem_size); - attr->max_fdb_mc_groups = le16_to_cpu(rsp_params->max_fdb_mc_groups); - attr->max_meters_per_if = rsp_params->max_meters_per_if; - attr->options = le64_to_cpu(rsp_params->options); - attr->component_type = dpsw_get_field(rsp_params->component_type, COMPONENT_TYPE); - attr->flooding_cfg = dpsw_get_field(rsp_params->repl_cfg, FLOODING_CFG); - attr->broadcast_cfg = dpsw_get_field(rsp_params->repl_cfg, BROADCAST_CFG); - return 0; -} - -/** - * dpsw_if_set_link_cfg() - Set the link configuration. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface id - * @cfg: Link configuration - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - struct dpsw_link_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if_set_link_cfg *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_LINK_CFG, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if_set_link_cfg *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - cmd_params->rate = cpu_to_le32(cfg->rate); - cmd_params->options = cpu_to_le64(cfg->options); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_if_get_link_state - Return the link state - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface id - * @state: Link state 1 - linkup, 0 - link down or disconnected - * - * @Return '0' on Success; Error code otherwise. - */ -int dpsw_if_get_link_state(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - struct dpsw_link_state *state) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if_get_link_state *cmd_params; - struct dpsw_rsp_if_get_link_state *rsp_params; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_LINK_STATE, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if_get_link_state *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - rsp_params = (struct dpsw_rsp_if_get_link_state *)cmd.params; - state->rate = le32_to_cpu(rsp_params->rate); - state->options = le64_to_cpu(rsp_params->options); - state->up = dpsw_get_field(rsp_params->up, UP); - - return 0; -} - -/** - * dpsw_if_set_tci() - Set default VLAN Tag Control Information (TCI) - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * @cfg: Tag Control Information Configuration - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_set_tci(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - const struct dpsw_tci_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if_set_tci *cmd_params; - u16 tmp_conf = 0; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_TCI, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if_set_tci *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - dpsw_set_field(tmp_conf, VLAN_ID, cfg->vlan_id); - dpsw_set_field(tmp_conf, DEI, cfg->dei); - dpsw_set_field(tmp_conf, PCP, cfg->pcp); - cmd_params->conf = cpu_to_le16(tmp_conf); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_if_get_tci() - Get default VLAN Tag Control Information (TCI) - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * @cfg: Tag Control Information Configuration - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_get_tci(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - struct dpsw_tci_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if_get_tci *cmd_params; - struct dpsw_rsp_if_get_tci *rsp_params; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_TCI, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if_get_tci *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - rsp_params = (struct dpsw_rsp_if_get_tci *)cmd.params; - cfg->pcp = rsp_params->pcp; - cfg->dei = rsp_params->dei; - cfg->vlan_id = le16_to_cpu(rsp_params->vlan_id); - - return 0; -} - -/** - * dpsw_if_set_stp() - Function sets Spanning Tree Protocol (STP) state. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * @cfg: STP State configuration parameters - * - * The following STP states are supported - - * blocking, listening, learning, forwarding and disabled. - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_set_stp(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - const struct dpsw_stp_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if_set_stp *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_STP, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if_set_stp *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - cmd_params->vlan_id = cpu_to_le16(cfg->vlan_id); - dpsw_set_field(cmd_params->state, STATE, cfg->state); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_if_get_counter() - Get specific counter of particular interface - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * @type: Counter type - * @counter: return value - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_get_counter(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - enum dpsw_counter type, - u64 *counter) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if_get_counter *cmd_params; - struct dpsw_rsp_if_get_counter *rsp_params; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_COUNTER, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if_get_counter *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - dpsw_set_field(cmd_params->type, COUNTER_TYPE, type); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - rsp_params = (struct dpsw_rsp_if_get_counter *)cmd.params; - *counter = le64_to_cpu(rsp_params->counter); - - return 0; -} - -/** - * dpsw_if_enable() - Enable Interface - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_ENABLE, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_if_disable() - Disable Interface - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_disable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_DISABLE, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_if_get_attributes() - Function obtains attributes of interface - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * @attr: Returned interface attributes - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - u16 if_id, struct dpsw_if_attr *attr) -{ - struct dpsw_rsp_if_get_attr *rsp_params; - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if *cmd_params; - int err; - - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_ATTR, cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dpsw_rsp_if_get_attr *)cmd.params; - attr->num_tcs = rsp_params->num_tcs; - attr->rate = le32_to_cpu(rsp_params->rate); - attr->options = le32_to_cpu(rsp_params->options); - attr->qdid = le16_to_cpu(rsp_params->qdid); - attr->enabled = dpsw_get_field(rsp_params->conf, ENABLED); - attr->accept_all_vlan = dpsw_get_field(rsp_params->conf, - ACCEPT_ALL_VLAN); - attr->admit_untagged = dpsw_get_field(rsp_params->conf, - ADMIT_UNTAGGED); - - return 0; -} - -/** - * dpsw_if_set_max_frame_length() - Set Maximum Receive frame length. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * @frame_length: Maximum Frame Length - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - u16 frame_length) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if_set_max_frame_length *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if_set_max_frame_length *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - cmd_params->frame_length = cpu_to_le16(frame_length); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_vlan_add() - Adding new VLAN to DPSW. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @vlan_id: VLAN Identifier - * @cfg: VLAN configuration - * - * Only VLAN ID and FDB ID are required parameters here. - * 12 bit VLAN ID is defined in IEEE802.1Q. - * Adding a duplicate VLAN ID is not allowed. - * FDB ID can be shared across multiple VLANs. Shared learning - * is obtained by calling dpsw_vlan_add for multiple VLAN IDs - * with same fdb_id - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_vlan_add(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_vlan_add *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD, - cmd_flags, - token); - cmd_params = (struct dpsw_vlan_add *)cmd.params; - cmd_params->fdb_id = cpu_to_le16(cfg->fdb_id); - cmd_params->vlan_id = cpu_to_le16(vlan_id); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_vlan_add_if() - Adding a set of interfaces to an existing VLAN. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @vlan_id: VLAN Identifier - * @cfg: Set of interfaces to add - * - * It adds only interfaces not belonging to this VLAN yet, - * otherwise an error is generated and an entire command is - * ignored. This function can be called numerous times always - * providing required interfaces delta. - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_vlan_add_if(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_if_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_vlan_manage_if *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; - cmd_params->vlan_id = cpu_to_le16(vlan_id); - build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_vlan_add_if_untagged() - Defining a set of interfaces that should be - * transmitted as untagged. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @vlan_id: VLAN Identifier - * @cfg: Set of interfaces that should be transmitted as untagged - * - * These interfaces should already belong to this VLAN. - * By default all interfaces are transmitted as tagged. - * Providing un-existing interface or untagged interface that is - * configured untagged already generates an error and the entire - * command is ignored. - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_if_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_vlan_manage_if *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF_UNTAGGED, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; - cmd_params->vlan_id = cpu_to_le16(vlan_id); - build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_vlan_remove_if() - Remove interfaces from an existing VLAN. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @vlan_id: VLAN Identifier - * @cfg: Set of interfaces that should be removed - * - * Interfaces must belong to this VLAN, otherwise an error - * is returned and an the command is ignored - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_if_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_vlan_manage_if *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; - cmd_params->vlan_id = cpu_to_le16(vlan_id); - build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_vlan_remove_if_untagged() - Define a set of interfaces that should be - * converted from transmitted as untagged to transmit as tagged. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @vlan_id: VLAN Identifier - * @cfg: Set of interfaces that should be removed - * - * Interfaces provided by API have to belong to this VLAN and - * configured untagged, otherwise an error is returned and the - * command is ignored - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_if_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_vlan_manage_if *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; - cmd_params->vlan_id = cpu_to_le16(vlan_id); - build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_vlan_remove() - Remove an entire VLAN - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @vlan_id: VLAN Identifier - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_vlan_remove(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_vlan_remove *cmd_params; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_vlan_remove *)cmd.params; - cmd_params->vlan_id = cpu_to_le16(vlan_id); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_fdb_add() - Add FDB to switch and Returns handle to FDB table for - * the reference - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @fdb_id: Returned Forwarding Database Identifier - * @cfg: FDB Configuration - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_fdb_add(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u16 *fdb_id, - const struct dpsw_fdb_cfg *cfg) -{ - struct dpsw_cmd_fdb_add *cmd_params; - struct dpsw_rsp_fdb_add *rsp_params; - struct fsl_mc_command cmd = { 0 }; - int err; - - cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_fdb_add *)cmd.params; - cmd_params->fdb_ageing_time = cpu_to_le16(cfg->fdb_ageing_time); - cmd_params->num_fdb_entries = cpu_to_le16(cfg->num_fdb_entries); - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dpsw_rsp_fdb_add *)cmd.params; - *fdb_id = le16_to_cpu(rsp_params->fdb_id); - - return 0; -} - -/** - * dpsw_fdb_remove() - Remove FDB from switch - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @fdb_id: Forwarding Database Identifier - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_fdb_remove(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u16 fdb_id) -{ - struct dpsw_cmd_fdb_remove *cmd_params; - struct fsl_mc_command cmd = { 0 }; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_fdb_remove *)cmd.params; - cmd_params->fdb_id = cpu_to_le16(fdb_id); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_fdb_add_unicast() - Function adds an unicast entry into MAC lookup table - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @fdb_id: Forwarding Database Identifier - * @cfg: Unicast entry configuration - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - const struct dpsw_fdb_unicast_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_fdb_unicast_op *cmd_params; - int i; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_UNICAST, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_fdb_unicast_op *)cmd.params; - cmd_params->fdb_id = cpu_to_le16(fdb_id); - cmd_params->if_egress = cpu_to_le16(cfg->if_egress); - for (i = 0; i < 6; i++) - cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; - dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_fdb_dump() - Dump the content of FDB table into memory. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @fdb_id: Forwarding Database Identifier - * @iova_addr: Data will be stored here as an array of struct fdb_dump_entry - * @iova_size: Memory size allocated at iova_addr - * @num_entries:Number of entries written at iova_addr - * - * Return: Completion status. '0' on Success; Error code otherwise. - * - * The memory allocated at iova_addr must be initialized with zero before - * command execution. If the FDB table does not fit into memory MC will stop - * after the memory is filled up. - * The struct fdb_dump_entry array must be parsed until the end of memory - * area or until an entry with mac_addr set to zero is found. - */ -int dpsw_fdb_dump(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - u64 iova_addr, - u32 iova_size, - u16 *num_entries) -{ - struct dpsw_cmd_fdb_dump *cmd_params; - struct dpsw_rsp_fdb_dump *rsp_params; - struct fsl_mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_DUMP, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_fdb_dump *)cmd.params; - cmd_params->fdb_id = cpu_to_le16(fdb_id); - cmd_params->iova_addr = cpu_to_le64(iova_addr); - cmd_params->iova_size = cpu_to_le32(iova_size); - - /* send command to mc */ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dpsw_rsp_fdb_dump *)cmd.params; - *num_entries = le16_to_cpu(rsp_params->num_entries); - - return 0; -} - -/** - * dpsw_fdb_remove_unicast() - removes an entry from MAC lookup table - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @fdb_id: Forwarding Database Identifier - * @cfg: Unicast entry configuration - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - const struct dpsw_fdb_unicast_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_fdb_unicast_op *cmd_params; - int i; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_UNICAST, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_fdb_unicast_op *)cmd.params; - cmd_params->fdb_id = cpu_to_le16(fdb_id); - for (i = 0; i < 6; i++) - cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; - cmd_params->if_egress = cpu_to_le16(cfg->if_egress); - dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_fdb_add_multicast() - Add a set of egress interfaces to multi-cast group - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @fdb_id: Forwarding Database Identifier - * @cfg: Multicast entry configuration - * - * If group doesn't exist, it will be created. - * It adds only interfaces not belonging to this multicast group - * yet, otherwise error will be generated and the command is - * ignored. - * This function may be called numerous times always providing - * required interfaces delta. - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - const struct dpsw_fdb_multicast_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_fdb_multicast_op *cmd_params; - int i; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_MULTICAST, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_fdb_multicast_op *)cmd.params; - cmd_params->fdb_id = cpu_to_le16(fdb_id); - cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); - dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); - build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); - for (i = 0; i < 6; i++) - cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_fdb_remove_multicast() - Removing interfaces from an existing multicast - * group. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @fdb_id: Forwarding Database Identifier - * @cfg: Multicast entry configuration - * - * Interfaces provided by this API have to exist in the group, - * otherwise an error will be returned and an entire command - * ignored. If there is no interface left in the group, - * an entire group is deleted - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - const struct dpsw_fdb_multicast_cfg *cfg) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_fdb_multicast_op *cmd_params; - int i; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_MULTICAST, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_fdb_multicast_op *)cmd.params; - cmd_params->fdb_id = cpu_to_le16(fdb_id); - cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); - dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); - build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); - for (i = 0; i < 6; i++) - cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_ctrl_if_get_attributes() - Obtain control interface attributes - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @attr: Returned control interface attributes - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_ctrl_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, - u16 token, struct dpsw_ctrl_if_attr *attr) -{ - struct dpsw_rsp_ctrl_if_get_attr *rsp_params; - struct fsl_mc_command cmd = { 0 }; - int err; - - cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_GET_ATTR, - cmd_flags, token); - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dpsw_rsp_ctrl_if_get_attr *)cmd.params; - attr->rx_fqid = le32_to_cpu(rsp_params->rx_fqid); - attr->rx_err_fqid = le32_to_cpu(rsp_params->rx_err_fqid); - attr->tx_err_conf_fqid = le32_to_cpu(rsp_params->tx_err_conf_fqid); - - return 0; -} - -/** - * dpsw_ctrl_if_set_pools() - Set control interface buffer pools - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @cfg: Buffer pools configuration - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_ctrl_if_set_pools(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - const struct dpsw_ctrl_if_pools_cfg *cfg) -{ - struct dpsw_cmd_ctrl_if_set_pools *cmd_params; - struct fsl_mc_command cmd = { 0 }; - int i; - - cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_SET_POOLS, - cmd_flags, token); - cmd_params = (struct dpsw_cmd_ctrl_if_set_pools *)cmd.params; - cmd_params->num_dpbp = cfg->num_dpbp; - for (i = 0; i < DPSW_MAX_DPBP; i++) { - cmd_params->dpbp_id[i] = cpu_to_le32(cfg->pools[i].dpbp_id); - cmd_params->buffer_size[i] = - cpu_to_le16(cfg->pools[i].buffer_size); - cmd_params->backup_pool_mask |= - DPSW_BACKUP_POOL(cfg->pools[i].backup_pool, i); - } - - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_ctrl_if_set_queue() - Set Rx queue configuration - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of dpsw object - * @qtype: dpsw_queue_type of the targeted queue - * @cfg: Rx queue configuration - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_ctrl_if_set_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - enum dpsw_queue_type qtype, - const struct dpsw_ctrl_if_queue_cfg *cfg) -{ - struct dpsw_cmd_ctrl_if_set_queue *cmd_params; - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_SET_QUEUE, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_ctrl_if_set_queue *)cmd.params; - cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id); - cmd_params->dest_priority = cfg->dest_cfg.priority; - cmd_params->qtype = qtype; - cmd_params->user_ctx = cpu_to_le64(cfg->user_ctx); - cmd_params->options = cpu_to_le32(cfg->options); - dpsw_set_field(cmd_params->dest_type, - DEST_TYPE, - cfg->dest_cfg.dest_type); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_get_api_version() - Get Data Path Switch API version - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @major_ver: Major version of data path switch API - * @minor_ver: Minor version of data path switch API - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver) -{ - struct fsl_mc_command cmd = { 0 }; - struct dpsw_rsp_get_api_version *rsp_params; - int err; - - cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_API_VERSION, - cmd_flags, - 0); - - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - rsp_params = (struct dpsw_rsp_get_api_version *)cmd.params; - *major_ver = le16_to_cpu(rsp_params->version_major); - *minor_ver = le16_to_cpu(rsp_params->version_minor); - - return 0; -} - -/** - * dpsw_if_get_port_mac_addr() - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * @mac_addr: MAC address of the physical port, if any, otherwise 0 - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_get_port_mac_addr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - u16 if_id, u8 mac_addr[6]) -{ - struct dpsw_rsp_if_get_mac_addr *rsp_params; - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if *cmd_params; - int err, i; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_PORT_MAC_ADDR, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - rsp_params = (struct dpsw_rsp_if_get_mac_addr *)cmd.params; - for (i = 0; i < 6; i++) - mac_addr[5 - i] = rsp_params->mac_addr[i]; - - return 0; -} - -/** - * dpsw_if_get_primary_mac_addr() - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * @mac_addr: MAC address of the physical port, if any, otherwise 0 - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_get_primary_mac_addr(struct fsl_mc_io *mc_io, u32 cmd_flags, - u16 token, u16 if_id, u8 mac_addr[6]) -{ - struct dpsw_rsp_if_get_mac_addr *rsp_params; - struct fsl_mc_command cmd = { 0 }; - struct dpsw_cmd_if *cmd_params; - int err, i; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_PRIMARY_MAC_ADDR, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - rsp_params = (struct dpsw_rsp_if_get_mac_addr *)cmd.params; - for (i = 0; i < 6; i++) - mac_addr[5 - i] = rsp_params->mac_addr[i]; - - return 0; -} - -/** - * dpsw_if_set_primary_mac_addr() - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @if_id: Interface Identifier - * @mac_addr: MAC address of the physical port, if any, otherwise 0 - * - * Return: Completion status. '0' on Success; Error code otherwise. - */ -int dpsw_if_set_primary_mac_addr(struct fsl_mc_io *mc_io, u32 cmd_flags, - u16 token, u16 if_id, u8 mac_addr[6]) -{ - struct dpsw_cmd_if_set_mac_addr *cmd_params; - struct fsl_mc_command cmd = { 0 }; - int i; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_PRIMARY_MAC_ADDR, - cmd_flags, - token); - cmd_params = (struct dpsw_cmd_if_set_mac_addr *)cmd.params; - cmd_params->if_id = cpu_to_le16(if_id); - for (i = 0; i < 6; i++) - cmd_params->mac_addr[i] = mac_addr[5 - i]; - - /* send command to mc*/ - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_ctrl_if_enable() - Enable control interface - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_ctrl_if_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) -{ - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_ENABLE, cmd_flags, - token); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_ctrl_if_disable() - Function disables control interface - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_ctrl_if_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) -{ - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_DISABLE, - cmd_flags, - token); - - return mc_send_command(mc_io, &cmd); -} - -/** - * dpsw_set_egress_flood() - Set egress parameters associated with an FDB ID - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPSW object - * @cfg: Egress flooding configuration - * - * Return: '0' on Success; Error code otherwise. - */ -int dpsw_set_egress_flood(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - const struct dpsw_egress_flood_cfg *cfg) -{ - struct dpsw_cmd_set_egress_flood *cmd_params; - struct fsl_mc_command cmd = { 0 }; - - cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_EGRESS_FLOOD, cmd_flags, token); - cmd_params = (struct dpsw_cmd_set_egress_flood *)cmd.params; - cmd_params->fdb_id = cpu_to_le16(cfg->fdb_id); - cmd_params->flood_type = cfg->flood_type; - build_if_id_bitmap(&cmd_params->if_id, cfg->if_id, cfg->num_ifs); - - return mc_send_command(mc_io, &cmd); -} diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h deleted file mode 100644 index 9e04350f3277..000000000000 --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h +++ /dev/null @@ -1,751 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2017-2021 NXP - * - */ - -#ifndef __FSL_DPSW_H -#define __FSL_DPSW_H - -/* Data Path L2-Switch API - * Contains API for handling DPSW topology and functionality - */ - -struct fsl_mc_io; - -/** - * DPSW general definitions - */ - -/** - * Maximum number of traffic class priorities - */ -#define DPSW_MAX_PRIORITIES 8 -/** - * Maximum number of interfaces - */ -#define DPSW_MAX_IF 64 - -int dpsw_open(struct fsl_mc_io *mc_io, - u32 cmd_flags, - int dpsw_id, - u16 *token); - -int dpsw_close(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -/** - * DPSW options - */ - -/** - * Disable flooding - */ -#define DPSW_OPT_FLOODING_DIS 0x0000000000000001ULL -/** - * Disable Multicast - */ -#define DPSW_OPT_MULTICAST_DIS 0x0000000000000004ULL -/** - * Support control interface - */ -#define DPSW_OPT_CTRL_IF_DIS 0x0000000000000010ULL -/** - * Disable flooding metering - */ -#define DPSW_OPT_FLOODING_METERING_DIS 0x0000000000000020ULL -/** - * Enable metering - */ -#define DPSW_OPT_METERING_EN 0x0000000000000040ULL - -/** - * enum dpsw_component_type - component type of a bridge - * @DPSW_COMPONENT_TYPE_C_VLAN: A C-VLAN component of an - * enterprise VLAN bridge or of a Provider Bridge used - * to process C-tagged frames - * @DPSW_COMPONENT_TYPE_S_VLAN: An S-VLAN component of a - * Provider Bridge - * - */ -enum dpsw_component_type { - DPSW_COMPONENT_TYPE_C_VLAN = 0, - DPSW_COMPONENT_TYPE_S_VLAN -}; - -/** - * enum dpsw_flooding_cfg - flooding configuration requested - * @DPSW_FLOODING_PER_VLAN: Flooding replicators are allocated per VLAN and - * interfaces present in each of them can be configured using - * dpsw_vlan_add_if_flooding()/dpsw_vlan_remove_if_flooding(). - * This is the default configuration. - * - * @DPSW_FLOODING_PER_FDB: Flooding replicators are allocated per FDB and - * interfaces present in each of them can be configured using - * dpsw_set_egress_flood(). - */ -enum dpsw_flooding_cfg { - DPSW_FLOODING_PER_VLAN = 0, - DPSW_FLOODING_PER_FDB, -}; - -/** - * enum dpsw_broadcast_cfg - broadcast configuration requested - * @DPSW_BROADCAST_PER_OBJECT: There is only one broadcast replicator per DPSW - * object. This is the default configuration. - * @DPSW_BROADCAST_PER_FDB: Broadcast replicators are allocated per FDB and - * interfaces present in each of them can be configured using - * dpsw_set_egress_flood(). - */ -enum dpsw_broadcast_cfg { - DPSW_BROADCAST_PER_OBJECT = 0, - DPSW_BROADCAST_PER_FDB, -}; - -int dpsw_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dpsw_disable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dpsw_reset(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -/** - * DPSW IRQ Index and Events - */ - -#define DPSW_IRQ_INDEX_IF 0x0000 -#define DPSW_IRQ_INDEX_L2SW 0x0001 - -/** - * IRQ event - Indicates that the link state changed - */ -#define DPSW_IRQ_EVENT_LINK_CHANGED 0x0001 - -/** - * struct dpsw_irq_cfg - IRQ configuration - * @addr: Address that must be written to signal a message-based interrupt - * @val: Value to write into irq_addr address - * @irq_num: A user defined number associated with this IRQ - */ -struct dpsw_irq_cfg { - u64 addr; - u32 val; - int irq_num; -}; - -int dpsw_set_irq_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u8 en); - -int dpsw_set_irq_mask(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 mask); - -int dpsw_get_irq_status(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 *status); - -int dpsw_clear_irq_status(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u8 irq_index, - u32 status); - -/** - * struct dpsw_attr - Structure representing DPSW attributes - * @id: DPSW object ID - * @options: Enable/Disable DPSW features - * @max_vlans: Maximum Number of VLANs - * @max_meters_per_if: Number of meters per interface - * @max_fdbs: Maximum Number of FDBs - * @max_fdb_entries: Number of FDB entries for default FDB table; - * 0 - indicates default 1024 entries. - * @fdb_aging_time: Default FDB aging time for default FDB table; - * 0 - indicates default 300 seconds - * @max_fdb_mc_groups: Number of multicast groups in each FDB table; - * 0 - indicates default 32 - * @mem_size: DPSW frame storage memory size - * @num_ifs: Number of interfaces - * @num_vlans: Current number of VLANs - * @num_fdbs: Current number of FDBs - * @component_type: Component type of this bridge - * @flooding_cfg: Flooding configuration (PER_VLAN - default, PER_FDB) - * @broadcast_cfg: Broadcast configuration (PER_OBJECT - default, PER_FDB) - */ -struct dpsw_attr { - int id; - u64 options; - u16 max_vlans; - u8 max_meters_per_if; - u8 max_fdbs; - u16 max_fdb_entries; - u16 fdb_aging_time; - u16 max_fdb_mc_groups; - u16 num_ifs; - u16 mem_size; - u16 num_vlans; - u8 num_fdbs; - enum dpsw_component_type component_type; - enum dpsw_flooding_cfg flooding_cfg; - enum dpsw_broadcast_cfg broadcast_cfg; -}; - -int dpsw_get_attributes(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - struct dpsw_attr *attr); - -/** - * struct dpsw_ctrl_if_attr - Control interface attributes - * @rx_fqid: Receive FQID - * @rx_err_fqid: Receive error FQID - * @tx_err_conf_fqid: Transmit error and confirmation FQID - */ -struct dpsw_ctrl_if_attr { - u32 rx_fqid; - u32 rx_err_fqid; - u32 tx_err_conf_fqid; -}; - -int dpsw_ctrl_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, - u16 token, struct dpsw_ctrl_if_attr *attr); - -enum dpsw_queue_type { - DPSW_QUEUE_RX, - DPSW_QUEUE_TX_ERR_CONF, - DPSW_QUEUE_RX_ERR, -}; - -/** - * Maximum number of DPBP - */ -#define DPSW_MAX_DPBP 8 - -/** - * struct dpsw_ctrl_if_pools_cfg - Control interface buffer pools configuration - * @num_dpbp: Number of DPBPs - * @pools: Array of buffer pools parameters; The number of valid entries - * must match 'num_dpbp' value - * @pools.dpbp_id: DPBP object ID - * @pools.buffer_size: Buffer size - * @pools.backup_pool: Backup pool - */ -struct dpsw_ctrl_if_pools_cfg { - u8 num_dpbp; - struct { - int dpbp_id; - u16 buffer_size; - int backup_pool; - } pools[DPSW_MAX_DPBP]; -}; - -int dpsw_ctrl_if_set_pools(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - const struct dpsw_ctrl_if_pools_cfg *cfg); - -#define DPSW_CTRL_IF_QUEUE_OPT_USER_CTX 0x00000001 -#define DPSW_CTRL_IF_QUEUE_OPT_DEST 0x00000002 - -enum dpsw_ctrl_if_dest { - DPSW_CTRL_IF_DEST_NONE = 0, - DPSW_CTRL_IF_DEST_DPIO = 1, -}; - -struct dpsw_ctrl_if_dest_cfg { - enum dpsw_ctrl_if_dest dest_type; - int dest_id; - u8 priority; -}; - -struct dpsw_ctrl_if_queue_cfg { - u32 options; - u64 user_ctx; - struct dpsw_ctrl_if_dest_cfg dest_cfg; -}; - -int dpsw_ctrl_if_set_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - enum dpsw_queue_type qtype, - const struct dpsw_ctrl_if_queue_cfg *cfg); - -int dpsw_ctrl_if_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); - -int dpsw_ctrl_if_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); - -/** - * enum dpsw_action - Action selection for special/control frames - * @DPSW_ACTION_DROP: Drop frame - * @DPSW_ACTION_REDIRECT: Redirect frame to control port - */ -enum dpsw_action { - DPSW_ACTION_DROP = 0, - DPSW_ACTION_REDIRECT = 1 -}; - -/** - * Enable auto-negotiation - */ -#define DPSW_LINK_OPT_AUTONEG 0x0000000000000001ULL -/** - * Enable half-duplex mode - */ -#define DPSW_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL -/** - * Enable pause frames - */ -#define DPSW_LINK_OPT_PAUSE 0x0000000000000004ULL -/** - * Enable a-symmetric pause frames - */ -#define DPSW_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL - -/** - * struct dpsw_link_cfg - Structure representing DPSW link configuration - * @rate: Rate - * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values - */ -struct dpsw_link_cfg { - u32 rate; - u64 options; -}; - -int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - struct dpsw_link_cfg *cfg); -/** - * struct dpsw_link_state - Structure representing DPSW link state - * @rate: Rate - * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values - * @up: 0 - covers two cases: down and disconnected, 1 - up - */ -struct dpsw_link_state { - u32 rate; - u64 options; - u8 up; -}; - -int dpsw_if_get_link_state(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - struct dpsw_link_state *state); - -/** - * struct dpsw_tci_cfg - Tag Control Information (TCI) configuration - * @pcp: Priority Code Point (PCP): a 3-bit field which refers - * to the IEEE 802.1p priority - * @dei: Drop Eligible Indicator (DEI): a 1-bit field. May be used - * separately or in conjunction with PCP to indicate frames - * eligible to be dropped in the presence of congestion - * @vlan_id: VLAN Identifier (VID): a 12-bit field specifying the VLAN - * to which the frame belongs. The hexadecimal values - * of 0x000 and 0xFFF are reserved; - * all other values may be used as VLAN identifiers, - * allowing up to 4,094 VLANs - */ -struct dpsw_tci_cfg { - u8 pcp; - u8 dei; - u16 vlan_id; -}; - -int dpsw_if_set_tci(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - const struct dpsw_tci_cfg *cfg); - -int dpsw_if_get_tci(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - struct dpsw_tci_cfg *cfg); - -/** - * enum dpsw_stp_state - Spanning Tree Protocol (STP) states - * @DPSW_STP_STATE_BLOCKING: Blocking state - * @DPSW_STP_STATE_LISTENING: Listening state - * @DPSW_STP_STATE_LEARNING: Learning state - * @DPSW_STP_STATE_FORWARDING: Forwarding state - * - */ -enum dpsw_stp_state { - DPSW_STP_STATE_DISABLED = 0, - DPSW_STP_STATE_LISTENING = 1, - DPSW_STP_STATE_LEARNING = 2, - DPSW_STP_STATE_FORWARDING = 3, - DPSW_STP_STATE_BLOCKING = 0 -}; - -/** - * struct dpsw_stp_cfg - Spanning Tree Protocol (STP) Configuration - * @vlan_id: VLAN ID STP state - * @state: STP state - */ -struct dpsw_stp_cfg { - u16 vlan_id; - enum dpsw_stp_state state; -}; - -int dpsw_if_set_stp(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - const struct dpsw_stp_cfg *cfg); - -/** - * enum dpsw_accepted_frames - Types of frames to accept - * @DPSW_ADMIT_ALL: The device accepts VLAN tagged, untagged and - * priority tagged frames - * @DPSW_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or - * Priority-Tagged frames received on this interface. - * - */ -enum dpsw_accepted_frames { - DPSW_ADMIT_ALL = 1, - DPSW_ADMIT_ONLY_VLAN_TAGGED = 3 -}; - -/** - * enum dpsw_counter - Counters types - * @DPSW_CNT_ING_FRAME: Counts ingress frames - * @DPSW_CNT_ING_BYTE: Counts ingress bytes - * @DPSW_CNT_ING_FLTR_FRAME: Counts filtered ingress frames - * @DPSW_CNT_ING_FRAME_DISCARD: Counts discarded ingress frame - * @DPSW_CNT_ING_MCAST_FRAME: Counts ingress multicast frames - * @DPSW_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes - * @DPSW_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames - * @DPSW_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes - * @DPSW_CNT_EGR_FRAME: Counts egress frames - * @DPSW_CNT_EGR_BYTE: Counts egress bytes - * @DPSW_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames - * @DPSW_CNT_EGR_STP_FRAME_DISCARD: Counts egress STP discarded frames - * @DPSW_CNT_ING_NO_BUFF_DISCARD: Counts ingress no buffer discarded frames - */ -enum dpsw_counter { - DPSW_CNT_ING_FRAME = 0x0, - DPSW_CNT_ING_BYTE = 0x1, - DPSW_CNT_ING_FLTR_FRAME = 0x2, - DPSW_CNT_ING_FRAME_DISCARD = 0x3, - DPSW_CNT_ING_MCAST_FRAME = 0x4, - DPSW_CNT_ING_MCAST_BYTE = 0x5, - DPSW_CNT_ING_BCAST_FRAME = 0x6, - DPSW_CNT_ING_BCAST_BYTES = 0x7, - DPSW_CNT_EGR_FRAME = 0x8, - DPSW_CNT_EGR_BYTE = 0x9, - DPSW_CNT_EGR_FRAME_DISCARD = 0xa, - DPSW_CNT_EGR_STP_FRAME_DISCARD = 0xb, - DPSW_CNT_ING_NO_BUFF_DISCARD = 0xc, -}; - -int dpsw_if_get_counter(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - enum dpsw_counter type, - u64 *counter); - -int dpsw_if_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id); - -int dpsw_if_disable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id); - -/** - * struct dpsw_if_attr - Structure representing DPSW interface attributes - * @num_tcs: Number of traffic classes - * @rate: Transmit rate in bits per second - * @options: Interface configuration options (bitmap) - * @enabled: Indicates if interface is enabled - * @accept_all_vlan: The device discards/accepts incoming frames - * for VLANs that do not include this interface - * @admit_untagged: When set to 'DPSW_ADMIT_ONLY_VLAN_TAGGED', the device - * discards untagged frames or priority-tagged frames received on - * this interface; - * When set to 'DPSW_ADMIT_ALL', untagged frames or priority- - * tagged frames received on this interface are accepted - * @qdid: control frames transmit qdid - */ -struct dpsw_if_attr { - u8 num_tcs; - u32 rate; - u32 options; - int enabled; - int accept_all_vlan; - enum dpsw_accepted_frames admit_untagged; - u16 qdid; -}; - -int dpsw_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - u16 if_id, struct dpsw_if_attr *attr); - -int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 if_id, - u16 frame_length); - -/** - * struct dpsw_vlan_cfg - VLAN Configuration - * @fdb_id: Forwarding Data Base - */ -struct dpsw_vlan_cfg { - u16 fdb_id; -}; - -int dpsw_vlan_add(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_cfg *cfg); - -#define DPSW_VLAN_ADD_IF_OPT_FDB_ID 0x0001 - -/** - * struct dpsw_vlan_if_cfg - Set of VLAN Interfaces - * @num_ifs: The number of interfaces that are assigned to the egress - * list for this VLAN - * @if_id: The set of interfaces that are - * assigned to the egress list for this VLAN - */ -struct dpsw_vlan_if_cfg { - u16 num_ifs; - u16 options; - u16 if_id[DPSW_MAX_IF]; - u16 fdb_id; -}; - -int dpsw_vlan_add_if(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_if_cfg *cfg); - -int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_if_cfg *cfg); - -int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_if_cfg *cfg); - -int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id, - const struct dpsw_vlan_if_cfg *cfg); - -int dpsw_vlan_remove(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 vlan_id); - -/** - * enum dpsw_fdb_entry_type - FDB Entry type - Static/Dynamic - * @DPSW_FDB_ENTRY_STATIC: Static entry - * @DPSW_FDB_ENTRY_DINAMIC: Dynamic entry - */ -enum dpsw_fdb_entry_type { - DPSW_FDB_ENTRY_STATIC = 0, - DPSW_FDB_ENTRY_DINAMIC = 1 -}; - -/** - * struct dpsw_fdb_unicast_cfg - Unicast entry configuration - * @type: Select static or dynamic entry - * @mac_addr: MAC address - * @if_egress: Egress interface ID - */ -struct dpsw_fdb_unicast_cfg { - enum dpsw_fdb_entry_type type; - u8 mac_addr[6]; - u16 if_egress; -}; - -int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - const struct dpsw_fdb_unicast_cfg *cfg); - -int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - const struct dpsw_fdb_unicast_cfg *cfg); - -#define DPSW_FDB_ENTRY_TYPE_DYNAMIC BIT(0) -#define DPSW_FDB_ENTRY_TYPE_UNICAST BIT(1) - -/** - * struct fdb_dump_entry - fdb snapshot entry - * @mac_addr: MAC address - * @type: bit0 - DINAMIC(1)/STATIC(0), bit1 - UNICAST(1)/MULTICAST(0) - * @if_info: unicast - egress interface, multicast - number of egress interfaces - * @if_mask: multicast - egress interface mask - */ -struct fdb_dump_entry { - u8 mac_addr[6]; - u8 type; - u8 if_info; - u8 if_mask[8]; -}; - -int dpsw_fdb_dump(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - u64 iova_addr, - u32 iova_size, - u16 *num_entries); - -/** - * struct dpsw_fdb_multicast_cfg - Multi-cast entry configuration - * @type: Select static or dynamic entry - * @mac_addr: MAC address - * @num_ifs: Number of external and internal interfaces - * @if_id: Egress interface IDs - */ -struct dpsw_fdb_multicast_cfg { - enum dpsw_fdb_entry_type type; - u8 mac_addr[6]; - u16 num_ifs; - u16 if_id[DPSW_MAX_IF]; -}; - -int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - const struct dpsw_fdb_multicast_cfg *cfg); - -int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - u16 fdb_id, - const struct dpsw_fdb_multicast_cfg *cfg); - -/** - * enum dpsw_fdb_learning_mode - Auto-learning modes - * @DPSW_FDB_LEARNING_MODE_DIS: Disable Auto-learning - * @DPSW_FDB_LEARNING_MODE_HW: Enable HW auto-Learning - * @DPSW_FDB_LEARNING_MODE_NON_SECURE: Enable None secure learning by CPU - * @DPSW_FDB_LEARNING_MODE_SECURE: Enable secure learning by CPU - * - * NONE - SECURE LEARNING - * SMAC found DMAC found CTLU Action - * v v Forward frame to - * 1. DMAC destination - * - v Forward frame to - * 1. DMAC destination - * 2. Control interface - * v - Forward frame to - * 1. Flooding list of interfaces - * - - Forward frame to - * 1. Flooding list of interfaces - * 2. Control interface - * SECURE LEARING - * SMAC found DMAC found CTLU Action - * v v Forward frame to - * 1. DMAC destination - * - v Forward frame to - * 1. Control interface - * v - Forward frame to - * 1. Flooding list of interfaces - * - - Forward frame to - * 1. Control interface - */ -enum dpsw_fdb_learning_mode { - DPSW_FDB_LEARNING_MODE_DIS = 0, - DPSW_FDB_LEARNING_MODE_HW = 1, - DPSW_FDB_LEARNING_MODE_NON_SECURE = 2, - DPSW_FDB_LEARNING_MODE_SECURE = 3 -}; - -/** - * struct dpsw_fdb_attr - FDB Attributes - * @max_fdb_entries: Number of FDB entries - * @fdb_ageing_time: Ageing time in seconds - * @learning_mode: Learning mode - * @num_fdb_mc_groups: Current number of multicast groups - * @max_fdb_mc_groups: Maximum number of multicast groups - */ -struct dpsw_fdb_attr { - u16 max_fdb_entries; - u16 fdb_ageing_time; - enum dpsw_fdb_learning_mode learning_mode; - u16 num_fdb_mc_groups; - u16 max_fdb_mc_groups; -}; - -int dpsw_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver); - -int dpsw_if_get_port_mac_addr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - u16 if_id, u8 mac_addr[6]); - -int dpsw_if_get_primary_mac_addr(struct fsl_mc_io *mc_io, u32 cmd_flags, - u16 token, u16 if_id, u8 mac_addr[6]); - -int dpsw_if_set_primary_mac_addr(struct fsl_mc_io *mc_io, u32 cmd_flags, - u16 token, u16 if_id, u8 mac_addr[6]); - -/** - * struct dpsw_fdb_cfg - FDB Configuration - * @num_fdb_entries: Number of FDB entries - * @fdb_ageing_time: Ageing time in seconds - */ -struct dpsw_fdb_cfg { - u16 num_fdb_entries; - u16 fdb_ageing_time; -}; - -int dpsw_fdb_add(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u16 *fdb_id, - const struct dpsw_fdb_cfg *cfg); - -int dpsw_fdb_remove(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u16 fdb_id); - -/** - * enum dpsw_flood_type - Define the flood type of a DPSW object - * @DPSW_BROADCAST: Broadcast flooding - * @DPSW_FLOODING: Unknown flooding - */ -enum dpsw_flood_type { - DPSW_BROADCAST = 0, - DPSW_FLOODING, -}; - -struct dpsw_egress_flood_cfg { - u16 fdb_id; - enum dpsw_flood_type flood_type; - u16 num_ifs; - u16 if_id[DPSW_MAX_IF]; -}; - -int dpsw_set_egress_flood(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, - const struct dpsw_egress_flood_cfg *cfg); - -#endif /* __FSL_DPSW_H */ diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c deleted file mode 100644 index 0af2e9914ec4..000000000000 --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c +++ /dev/null @@ -1,189 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * DPAA2 Ethernet Switch ethtool support - * - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2017-2018 NXP - * - */ - -#include <linux/ethtool.h> - -#include "ethsw.h" - -static struct { - enum dpsw_counter id; - char name[ETH_GSTRING_LEN]; -} dpaa2_switch_ethtool_counters[] = { - {DPSW_CNT_ING_FRAME, "rx frames"}, - {DPSW_CNT_ING_BYTE, "rx bytes"}, - {DPSW_CNT_ING_FLTR_FRAME, "rx filtered frames"}, - {DPSW_CNT_ING_FRAME_DISCARD, "rx discarded frames"}, - {DPSW_CNT_ING_BCAST_FRAME, "rx b-cast frames"}, - {DPSW_CNT_ING_BCAST_BYTES, "rx b-cast bytes"}, - {DPSW_CNT_ING_MCAST_FRAME, "rx m-cast frames"}, - {DPSW_CNT_ING_MCAST_BYTE, "rx m-cast bytes"}, - {DPSW_CNT_EGR_FRAME, "tx frames"}, - {DPSW_CNT_EGR_BYTE, "tx bytes"}, - {DPSW_CNT_EGR_FRAME_DISCARD, "tx discarded frames"}, - {DPSW_CNT_ING_NO_BUFF_DISCARD, "rx discarded no buffer frames"}, -}; - -#define DPAA2_SWITCH_NUM_COUNTERS ARRAY_SIZE(dpaa2_switch_ethtool_counters) - -static void dpaa2_switch_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *drvinfo) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - u16 version_major, version_minor; - int err; - - strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); - - err = dpsw_get_api_version(port_priv->ethsw_data->mc_io, 0, - &version_major, - &version_minor); - if (err) - strscpy(drvinfo->fw_version, "N/A", - sizeof(drvinfo->fw_version)); - else - snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), - "%u.%u", version_major, version_minor); - - strscpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent), - sizeof(drvinfo->bus_info)); -} - -static int -dpaa2_switch_get_link_ksettings(struct net_device *netdev, - struct ethtool_link_ksettings *link_ksettings) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - struct dpsw_link_state state = {0}; - int err = 0; - - err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - &state); - if (err) { - netdev_err(netdev, "ERROR %d getting link state\n", err); - goto out; - } - - /* At the moment, we have no way of interrogating the DPMAC - * from the DPSW side or there may not exist a DPMAC at all. - * Report only autoneg state, duplexity and speed. - */ - if (state.options & DPSW_LINK_OPT_AUTONEG) - link_ksettings->base.autoneg = AUTONEG_ENABLE; - if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX)) - link_ksettings->base.duplex = DUPLEX_FULL; - link_ksettings->base.speed = state.rate; - -out: - return err; -} - -static int -dpaa2_switch_set_link_ksettings(struct net_device *netdev, - const struct ethtool_link_ksettings *link_ksettings) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct dpsw_link_cfg cfg = {0}; - bool if_running; - int err = 0, ret; - - /* Interface needs to be down to change link settings */ - if_running = netif_running(netdev); - if (if_running) { - err = dpsw_if_disable(ethsw->mc_io, 0, - ethsw->dpsw_handle, - port_priv->idx); - if (err) { - netdev_err(netdev, "dpsw_if_disable err %d\n", err); - return err; - } - } - - cfg.rate = link_ksettings->base.speed; - if (link_ksettings->base.autoneg == AUTONEG_ENABLE) - cfg.options |= DPSW_LINK_OPT_AUTONEG; - else - cfg.options &= ~DPSW_LINK_OPT_AUTONEG; - if (link_ksettings->base.duplex == DUPLEX_HALF) - cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX; - else - cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX; - - err = dpsw_if_set_link_cfg(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - &cfg); - - if (if_running) { - ret = dpsw_if_enable(ethsw->mc_io, 0, - ethsw->dpsw_handle, - port_priv->idx); - if (ret) { - netdev_err(netdev, "dpsw_if_enable err %d\n", ret); - return ret; - } - } - return err; -} - -static int dpaa2_switch_ethtool_get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return DPAA2_SWITCH_NUM_COUNTERS; - default: - return -EOPNOTSUPP; - } -} - -static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev, - u32 stringset, u8 *data) -{ - int i; - - switch (stringset) { - case ETH_SS_STATS: - for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) - memcpy(data + i * ETH_GSTRING_LEN, - dpaa2_switch_ethtool_counters[i].name, - ETH_GSTRING_LEN); - break; - } -} - -static void dpaa2_switch_ethtool_get_stats(struct net_device *netdev, - struct ethtool_stats *stats, - u64 *data) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - int i, err; - - for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) { - err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - dpaa2_switch_ethtool_counters[i].id, - &data[i]); - if (err) - netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n", - dpaa2_switch_ethtool_counters[i].name, err); - } -} - -const struct ethtool_ops dpaa2_switch_port_ethtool_ops = { - .get_drvinfo = dpaa2_switch_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_link_ksettings = dpaa2_switch_get_link_ksettings, - .set_link_ksettings = dpaa2_switch_set_link_ksettings, - .get_strings = dpaa2_switch_ethtool_get_strings, - .get_ethtool_stats = dpaa2_switch_ethtool_get_stats, - .get_sset_count = dpaa2_switch_ethtool_get_sset_count, -}; diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c deleted file mode 100644 index 97292cf570c1..000000000000 --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c +++ /dev/null @@ -1,2901 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * DPAA2 Ethernet Switch driver - * - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2017-2021 NXP - * - */ - -#include <linux/module.h> - -#include <linux/interrupt.h> -#include <linux/msi.h> -#include <linux/kthread.h> -#include <linux/workqueue.h> -#include <linux/iommu.h> - -#include <linux/fsl/mc.h> - -#include "ethsw.h" - -/* Minimal supported DPSW version */ -#define DPSW_MIN_VER_MAJOR 8 -#define DPSW_MIN_VER_MINOR 9 - -#define DEFAULT_VLAN_ID 1 - -static u16 dpaa2_switch_port_get_fdb_id(struct ethsw_port_priv *port_priv) -{ - return port_priv->fdb->fdb_id; -} - -static struct dpaa2_switch_fdb *dpaa2_switch_fdb_get_unused(struct ethsw_core *ethsw) -{ - int i; - - for (i = 0; i < ethsw->sw_attr.num_ifs; i++) - if (!ethsw->fdbs[i].in_use) - return ðsw->fdbs[i]; - return NULL; -} - -static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv, - struct net_device *bridge_dev) -{ - struct ethsw_port_priv *other_port_priv = NULL; - struct dpaa2_switch_fdb *fdb; - struct net_device *other_dev; - struct list_head *iter; - - /* If we leave a bridge (bridge_dev is NULL), find an unused - * FDB and use that. - */ - if (!bridge_dev) { - fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data); - - /* If there is no unused FDB, we must be the last port that - * leaves the last bridge, all the others are standalone. We - * can just keep the FDB that we already have. - */ - - if (!fdb) { - port_priv->fdb->bridge_dev = NULL; - return 0; - } - - port_priv->fdb = fdb; - port_priv->fdb->in_use = true; - port_priv->fdb->bridge_dev = NULL; - return 0; - } - - /* The below call to netdev_for_each_lower_dev() demands the RTNL lock - * being held. Assert on it so that it's easier to catch new code - * paths that reach this point without the RTNL lock. - */ - ASSERT_RTNL(); - - /* If part of a bridge, use the FDB of the first dpaa2 switch interface - * to be present in that bridge - */ - netdev_for_each_lower_dev(bridge_dev, other_dev, iter) { - if (!dpaa2_switch_port_dev_check(other_dev)) - continue; - - if (other_dev == port_priv->netdev) - continue; - - other_port_priv = netdev_priv(other_dev); - break; - } - - /* The current port is about to change its FDB to the one used by the - * first port that joined the bridge. - */ - if (other_port_priv) { - /* The previous FDB is about to become unused, since the - * interface is no longer standalone. - */ - port_priv->fdb->in_use = false; - port_priv->fdb->bridge_dev = NULL; - - /* Get a reference to the new FDB */ - port_priv->fdb = other_port_priv->fdb; - } - - /* Keep track of the new upper bridge device */ - port_priv->fdb->bridge_dev = bridge_dev; - - return 0; -} - -static void *dpaa2_iova_to_virt(struct iommu_domain *domain, - dma_addr_t iova_addr) -{ - phys_addr_t phys_addr; - - phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr; - - return phys_to_virt(phys_addr); -} - -static int dpaa2_switch_add_vlan(struct ethsw_port_priv *port_priv, u16 vid) -{ - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct dpsw_vlan_cfg vcfg = {0}; - int err; - - vcfg.fdb_id = dpaa2_switch_port_get_fdb_id(port_priv); - err = dpsw_vlan_add(ethsw->mc_io, 0, - ethsw->dpsw_handle, vid, &vcfg); - if (err) { - dev_err(ethsw->dev, "dpsw_vlan_add err %d\n", err); - return err; - } - ethsw->vlans[vid] = ETHSW_VLAN_MEMBER; - - return 0; -} - -static bool dpaa2_switch_port_is_up(struct ethsw_port_priv *port_priv) -{ - struct net_device *netdev = port_priv->netdev; - struct dpsw_link_state state; - int err; - - err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, &state); - if (err) { - netdev_err(netdev, "dpsw_if_get_link_state() err %d\n", err); - return true; - } - - WARN_ONCE(state.up > 1, "Garbage read into link_state"); - - return state.up ? true : false; -} - -static int dpaa2_switch_port_set_pvid(struct ethsw_port_priv *port_priv, u16 pvid) -{ - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct net_device *netdev = port_priv->netdev; - struct dpsw_tci_cfg tci_cfg = { 0 }; - bool up; - int err, ret; - - err = dpsw_if_get_tci(ethsw->mc_io, 0, ethsw->dpsw_handle, - port_priv->idx, &tci_cfg); - if (err) { - netdev_err(netdev, "dpsw_if_get_tci err %d\n", err); - return err; - } - - tci_cfg.vlan_id = pvid; - - /* Interface needs to be down to change PVID */ - up = dpaa2_switch_port_is_up(port_priv); - if (up) { - err = dpsw_if_disable(ethsw->mc_io, 0, - ethsw->dpsw_handle, - port_priv->idx); - if (err) { - netdev_err(netdev, "dpsw_if_disable err %d\n", err); - return err; - } - } - - err = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle, - port_priv->idx, &tci_cfg); - if (err) { - netdev_err(netdev, "dpsw_if_set_tci err %d\n", err); - goto set_tci_error; - } - - /* Delete previous PVID info and mark the new one */ - port_priv->vlans[port_priv->pvid] &= ~ETHSW_VLAN_PVID; - port_priv->vlans[pvid] |= ETHSW_VLAN_PVID; - port_priv->pvid = pvid; - -set_tci_error: - if (up) { - ret = dpsw_if_enable(ethsw->mc_io, 0, - ethsw->dpsw_handle, - port_priv->idx); - if (ret) { - netdev_err(netdev, "dpsw_if_enable err %d\n", ret); - return ret; - } - } - - return err; -} - -static int dpaa2_switch_port_add_vlan(struct ethsw_port_priv *port_priv, - u16 vid, u16 flags) -{ - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct net_device *netdev = port_priv->netdev; - struct dpsw_vlan_if_cfg vcfg = {0}; - int err; - - if (port_priv->vlans[vid]) { - netdev_warn(netdev, "VLAN %d already configured\n", vid); - return -EEXIST; - } - - /* If hit, this VLAN rule will lead the packet into the FDB table - * specified in the vlan configuration below - */ - vcfg.num_ifs = 1; - vcfg.if_id[0] = port_priv->idx; - vcfg.fdb_id = dpaa2_switch_port_get_fdb_id(port_priv); - vcfg.options |= DPSW_VLAN_ADD_IF_OPT_FDB_ID; - err = dpsw_vlan_add_if(ethsw->mc_io, 0, ethsw->dpsw_handle, vid, &vcfg); - if (err) { - netdev_err(netdev, "dpsw_vlan_add_if err %d\n", err); - return err; - } - - port_priv->vlans[vid] = ETHSW_VLAN_MEMBER; - - if (flags & BRIDGE_VLAN_INFO_UNTAGGED) { - err = dpsw_vlan_add_if_untagged(ethsw->mc_io, 0, - ethsw->dpsw_handle, - vid, &vcfg); - if (err) { - netdev_err(netdev, - "dpsw_vlan_add_if_untagged err %d\n", err); - return err; - } - port_priv->vlans[vid] |= ETHSW_VLAN_UNTAGGED; - } - - if (flags & BRIDGE_VLAN_INFO_PVID) { - err = dpaa2_switch_port_set_pvid(port_priv, vid); - if (err) - return err; - } - - return 0; -} - -static int dpaa2_switch_port_set_stp_state(struct ethsw_port_priv *port_priv, u8 state) -{ - struct dpsw_stp_cfg stp_cfg = { - .state = state, - }; - int err; - u16 vid; - - if (!netif_running(port_priv->netdev) || state == port_priv->stp_state) - return 0; /* Nothing to do */ - - for (vid = 0; vid <= VLAN_VID_MASK; vid++) { - if (port_priv->vlans[vid] & ETHSW_VLAN_MEMBER) { - stp_cfg.vlan_id = vid; - err = dpsw_if_set_stp(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, &stp_cfg); - if (err) { - netdev_err(port_priv->netdev, - "dpsw_if_set_stp err %d\n", err); - return err; - } - } - } - - port_priv->stp_state = state; - - return 0; -} - -static int dpaa2_switch_dellink(struct ethsw_core *ethsw, u16 vid) -{ - struct ethsw_port_priv *ppriv_local = NULL; - int i, err; - - if (!ethsw->vlans[vid]) - return -ENOENT; - - err = dpsw_vlan_remove(ethsw->mc_io, 0, ethsw->dpsw_handle, vid); - if (err) { - dev_err(ethsw->dev, "dpsw_vlan_remove err %d\n", err); - return err; - } - ethsw->vlans[vid] = 0; - - for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { - ppriv_local = ethsw->ports[i]; - ppriv_local->vlans[vid] = 0; - } - - return 0; -} - -static int dpaa2_switch_port_fdb_add_uc(struct ethsw_port_priv *port_priv, - const unsigned char *addr) -{ - struct dpsw_fdb_unicast_cfg entry = {0}; - u16 fdb_id; - int err; - - entry.if_egress = port_priv->idx; - entry.type = DPSW_FDB_ENTRY_STATIC; - ether_addr_copy(entry.mac_addr, addr); - - fdb_id = dpaa2_switch_port_get_fdb_id(port_priv); - err = dpsw_fdb_add_unicast(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - fdb_id, &entry); - if (err) - netdev_err(port_priv->netdev, - "dpsw_fdb_add_unicast err %d\n", err); - return err; -} - -static int dpaa2_switch_port_fdb_del_uc(struct ethsw_port_priv *port_priv, - const unsigned char *addr) -{ - struct dpsw_fdb_unicast_cfg entry = {0}; - u16 fdb_id; - int err; - - entry.if_egress = port_priv->idx; - entry.type = DPSW_FDB_ENTRY_STATIC; - ether_addr_copy(entry.mac_addr, addr); - - fdb_id = dpaa2_switch_port_get_fdb_id(port_priv); - err = dpsw_fdb_remove_unicast(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - fdb_id, &entry); - /* Silently discard error for calling multiple times the del command */ - if (err && err != -ENXIO) - netdev_err(port_priv->netdev, - "dpsw_fdb_remove_unicast err %d\n", err); - return err; -} - -static int dpaa2_switch_port_fdb_add_mc(struct ethsw_port_priv *port_priv, - const unsigned char *addr) -{ - struct dpsw_fdb_multicast_cfg entry = {0}; - u16 fdb_id; - int err; - - ether_addr_copy(entry.mac_addr, addr); - entry.type = DPSW_FDB_ENTRY_STATIC; - entry.num_ifs = 1; - entry.if_id[0] = port_priv->idx; - - fdb_id = dpaa2_switch_port_get_fdb_id(port_priv); - err = dpsw_fdb_add_multicast(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - fdb_id, &entry); - /* Silently discard error for calling multiple times the add command */ - if (err && err != -ENXIO) - netdev_err(port_priv->netdev, "dpsw_fdb_add_multicast err %d\n", - err); - return err; -} - -static int dpaa2_switch_port_fdb_del_mc(struct ethsw_port_priv *port_priv, - const unsigned char *addr) -{ - struct dpsw_fdb_multicast_cfg entry = {0}; - u16 fdb_id; - int err; - - ether_addr_copy(entry.mac_addr, addr); - entry.type = DPSW_FDB_ENTRY_STATIC; - entry.num_ifs = 1; - entry.if_id[0] = port_priv->idx; - - fdb_id = dpaa2_switch_port_get_fdb_id(port_priv); - err = dpsw_fdb_remove_multicast(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - fdb_id, &entry); - /* Silently discard error for calling multiple times the del command */ - if (err && err != -ENAVAIL) - netdev_err(port_priv->netdev, - "dpsw_fdb_remove_multicast err %d\n", err); - return err; -} - -static void dpaa2_switch_port_get_stats(struct net_device *netdev, - struct rtnl_link_stats64 *stats) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - u64 tmp; - int err; - - err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - DPSW_CNT_ING_FRAME, &stats->rx_packets); - if (err) - goto error; - - err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - DPSW_CNT_EGR_FRAME, &stats->tx_packets); - if (err) - goto error; - - err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - DPSW_CNT_ING_BYTE, &stats->rx_bytes); - if (err) - goto error; - - err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - DPSW_CNT_EGR_BYTE, &stats->tx_bytes); - if (err) - goto error; - - err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - DPSW_CNT_ING_FRAME_DISCARD, - &stats->rx_dropped); - if (err) - goto error; - - err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - DPSW_CNT_ING_FLTR_FRAME, - &tmp); - if (err) - goto error; - stats->rx_dropped += tmp; - - err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - DPSW_CNT_EGR_FRAME_DISCARD, - &stats->tx_dropped); - if (err) - goto error; - - return; - -error: - netdev_err(netdev, "dpsw_if_get_counter err %d\n", err); -} - -static bool dpaa2_switch_port_has_offload_stats(const struct net_device *netdev, - int attr_id) -{ - return (attr_id == IFLA_OFFLOAD_XSTATS_CPU_HIT); -} - -static int dpaa2_switch_port_get_offload_stats(int attr_id, - const struct net_device *netdev, - void *sp) -{ - switch (attr_id) { - case IFLA_OFFLOAD_XSTATS_CPU_HIT: - dpaa2_switch_port_get_stats((struct net_device *)netdev, sp); - return 0; - } - - return -EINVAL; -} - -static int dpaa2_switch_port_change_mtu(struct net_device *netdev, int mtu) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - int err; - - err = dpsw_if_set_max_frame_length(port_priv->ethsw_data->mc_io, - 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, - (u16)ETHSW_L2_MAX_FRM(mtu)); - if (err) { - netdev_err(netdev, - "dpsw_if_set_max_frame_length() err %d\n", err); - return err; - } - - netdev->mtu = mtu; - return 0; -} - -static int dpaa2_switch_port_carrier_state_sync(struct net_device *netdev) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - struct dpsw_link_state state; - int err; - - /* Interrupts are received even though no one issued an 'ifconfig up' - * on the switch interface. Ignore these link state update interrupts - */ - if (!netif_running(netdev)) - return 0; - - err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx, &state); - if (err) { - netdev_err(netdev, "dpsw_if_get_link_state() err %d\n", err); - return err; - } - - WARN_ONCE(state.up > 1, "Garbage read into link_state"); - - if (state.up != port_priv->link_state) { - if (state.up) { - netif_carrier_on(netdev); - netif_tx_start_all_queues(netdev); - } else { - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - } - port_priv->link_state = state.up; - } - - return 0; -} - -/* Manage all NAPI instances for the control interface. - * - * We only have one RX queue and one Tx Conf queue for all - * switch ports. Therefore, we only need to enable the NAPI instance once, the - * first time one of the switch ports runs .dev_open(). - */ - -static void dpaa2_switch_enable_ctrl_if_napi(struct ethsw_core *ethsw) -{ - int i; - - /* Access to the ethsw->napi_users relies on the RTNL lock */ - ASSERT_RTNL(); - - /* a new interface is using the NAPI instance */ - ethsw->napi_users++; - - /* if there is already a user of the instance, return */ - if (ethsw->napi_users > 1) - return; - - for (i = 0; i < DPAA2_SWITCH_RX_NUM_FQS; i++) - napi_enable(ðsw->fq[i].napi); -} - -static void dpaa2_switch_disable_ctrl_if_napi(struct ethsw_core *ethsw) -{ - int i; - - /* Access to the ethsw->napi_users relies on the RTNL lock */ - ASSERT_RTNL(); - - /* If we are not the last interface using the NAPI, return */ - ethsw->napi_users--; - if (ethsw->napi_users) - return; - - for (i = 0; i < DPAA2_SWITCH_RX_NUM_FQS; i++) - napi_disable(ðsw->fq[i].napi); -} - -static int dpaa2_switch_port_open(struct net_device *netdev) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - struct ethsw_core *ethsw = port_priv->ethsw_data; - int err; - - /* Explicitly set carrier off, otherwise - * netif_carrier_ok() will return true and cause 'ip link show' - * to report the LOWER_UP flag, even though the link - * notification wasn't even received. - */ - netif_carrier_off(netdev); - - err = dpsw_if_enable(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx); - if (err) { - netdev_err(netdev, "dpsw_if_enable err %d\n", err); - return err; - } - - /* sync carrier state */ - err = dpaa2_switch_port_carrier_state_sync(netdev); - if (err) { - netdev_err(netdev, - "dpaa2_switch_port_carrier_state_sync err %d\n", err); - goto err_carrier_sync; - } - - dpaa2_switch_enable_ctrl_if_napi(ethsw); - - return 0; - -err_carrier_sync: - dpsw_if_disable(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx); - return err; -} - -static int dpaa2_switch_port_stop(struct net_device *netdev) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - struct ethsw_core *ethsw = port_priv->ethsw_data; - int err; - - err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0, - port_priv->ethsw_data->dpsw_handle, - port_priv->idx); - if (err) { - netdev_err(netdev, "dpsw_if_disable err %d\n", err); - return err; - } - - dpaa2_switch_disable_ctrl_if_napi(ethsw); - - return 0; -} - -static int dpaa2_switch_port_parent_id(struct net_device *dev, - struct netdev_phys_item_id *ppid) -{ - struct ethsw_port_priv *port_priv = netdev_priv(dev); - - ppid->id_len = 1; - ppid->id[0] = port_priv->ethsw_data->dev_id; - - return 0; -} - -static int dpaa2_switch_port_get_phys_name(struct net_device *netdev, char *name, - size_t len) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - int err; - - err = snprintf(name, len, "p%d", port_priv->idx); - if (err >= len) - return -EINVAL; - - return 0; -} - -struct ethsw_dump_ctx { - struct net_device *dev; - struct sk_buff *skb; - struct netlink_callback *cb; - int idx; -}; - -static int dpaa2_switch_fdb_dump_nl(struct fdb_dump_entry *entry, - struct ethsw_dump_ctx *dump) -{ - int is_dynamic = entry->type & DPSW_FDB_ENTRY_DINAMIC; - u32 portid = NETLINK_CB(dump->cb->skb).portid; - u32 seq = dump->cb->nlh->nlmsg_seq; - struct nlmsghdr *nlh; - struct ndmsg *ndm; - - if (dump->idx < dump->cb->args[2]) - goto skip; - - nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, - sizeof(*ndm), NLM_F_MULTI); - if (!nlh) - return -EMSGSIZE; - - ndm = nlmsg_data(nlh); - ndm->ndm_family = AF_BRIDGE; - ndm->ndm_pad1 = 0; - ndm->ndm_pad2 = 0; - ndm->ndm_flags = NTF_SELF; - ndm->ndm_type = 0; - ndm->ndm_ifindex = dump->dev->ifindex; - ndm->ndm_state = is_dynamic ? NUD_REACHABLE : NUD_NOARP; - - if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, entry->mac_addr)) - goto nla_put_failure; - - nlmsg_end(dump->skb, nlh); - -skip: - dump->idx++; - return 0; - -nla_put_failure: - nlmsg_cancel(dump->skb, nlh); - return -EMSGSIZE; -} - -static int dpaa2_switch_port_fdb_valid_entry(struct fdb_dump_entry *entry, - struct ethsw_port_priv *port_priv) -{ - int idx = port_priv->idx; - int valid; - - if (entry->type & DPSW_FDB_ENTRY_TYPE_UNICAST) - valid = entry->if_info == port_priv->idx; - else - valid = entry->if_mask[idx / 8] & BIT(idx % 8); - - return valid; -} - -static int dpaa2_switch_fdb_iterate(struct ethsw_port_priv *port_priv, - dpaa2_switch_fdb_cb_t cb, void *data) -{ - struct net_device *net_dev = port_priv->netdev; - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct device *dev = net_dev->dev.parent; - struct fdb_dump_entry *fdb_entries; - struct fdb_dump_entry fdb_entry; - dma_addr_t fdb_dump_iova; - u16 num_fdb_entries; - u32 fdb_dump_size; - int err = 0, i; - u8 *dma_mem; - u16 fdb_id; - - fdb_dump_size = ethsw->sw_attr.max_fdb_entries * sizeof(fdb_entry); - dma_mem = kzalloc(fdb_dump_size, GFP_KERNEL); - if (!dma_mem) - return -ENOMEM; - - fdb_dump_iova = dma_map_single(dev, dma_mem, fdb_dump_size, - DMA_FROM_DEVICE); - if (dma_mapping_error(dev, fdb_dump_iova)) { - netdev_err(net_dev, "dma_map_single() failed\n"); - err = -ENOMEM; - goto err_map; - } - - fdb_id = dpaa2_switch_port_get_fdb_id(port_priv); - err = dpsw_fdb_dump(ethsw->mc_io, 0, ethsw->dpsw_handle, fdb_id, - fdb_dump_iova, fdb_dump_size, &num_fdb_entries); - if (err) { - netdev_err(net_dev, "dpsw_fdb_dump() = %d\n", err); - goto err_dump; - } - - dma_unmap_single(dev, fdb_dump_iova, fdb_dump_size, DMA_FROM_DEVICE); - - fdb_entries = (struct fdb_dump_entry *)dma_mem; - for (i = 0; i < num_fdb_entries; i++) { - fdb_entry = fdb_entries[i]; - - err = cb(port_priv, &fdb_entry, data); - if (err) - goto end; - } - -end: - kfree(dma_mem); - - return 0; - -err_dump: - dma_unmap_single(dev, fdb_dump_iova, fdb_dump_size, DMA_TO_DEVICE); -err_map: - kfree(dma_mem); - return err; -} - -static int dpaa2_switch_fdb_entry_dump(struct ethsw_port_priv *port_priv, - struct fdb_dump_entry *fdb_entry, - void *data) -{ - if (!dpaa2_switch_port_fdb_valid_entry(fdb_entry, port_priv)) - return 0; - - return dpaa2_switch_fdb_dump_nl(fdb_entry, data); -} - -static int dpaa2_switch_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct net_device *net_dev, - struct net_device *filter_dev, int *idx) -{ - struct ethsw_port_priv *port_priv = netdev_priv(net_dev); - struct ethsw_dump_ctx dump = { - .dev = net_dev, - .skb = skb, - .cb = cb, - .idx = *idx, - }; - int err; - - err = dpaa2_switch_fdb_iterate(port_priv, dpaa2_switch_fdb_entry_dump, &dump); - *idx = dump.idx; - - return err; -} - -static int dpaa2_switch_fdb_entry_fast_age(struct ethsw_port_priv *port_priv, - struct fdb_dump_entry *fdb_entry, - void *data __always_unused) -{ - if (!dpaa2_switch_port_fdb_valid_entry(fdb_entry, port_priv)) - return 0; - - if (!(fdb_entry->type & DPSW_FDB_ENTRY_TYPE_DYNAMIC)) - return 0; - - if (fdb_entry->type & DPSW_FDB_ENTRY_TYPE_UNICAST) - dpaa2_switch_port_fdb_del_uc(port_priv, fdb_entry->mac_addr); - else - dpaa2_switch_port_fdb_del_mc(port_priv, fdb_entry->mac_addr); - - return 0; -} - -static void dpaa2_switch_port_fast_age(struct ethsw_port_priv *port_priv) -{ - dpaa2_switch_fdb_iterate(port_priv, - dpaa2_switch_fdb_entry_fast_age, NULL); -} - -static int dpaa2_switch_port_vlan_add(struct net_device *netdev, __be16 proto, - u16 vid) -{ - struct switchdev_obj_port_vlan vlan = { - .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, - .vid = vid, - .obj.orig_dev = netdev, - /* This API only allows programming tagged, non-PVID VIDs */ - .flags = 0, - }; - - return dpaa2_switch_port_vlans_add(netdev, &vlan); -} - -static int dpaa2_switch_port_vlan_kill(struct net_device *netdev, __be16 proto, - u16 vid) -{ - struct switchdev_obj_port_vlan vlan = { - .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, - .vid = vid, - .obj.orig_dev = netdev, - /* This API only allows programming tagged, non-PVID VIDs */ - .flags = 0, - }; - - return dpaa2_switch_port_vlans_del(netdev, &vlan); -} - -static int dpaa2_switch_port_set_mac_addr(struct ethsw_port_priv *port_priv) -{ - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct net_device *net_dev = port_priv->netdev; - struct device *dev = net_dev->dev.parent; - u8 mac_addr[ETH_ALEN]; - int err; - - if (!(ethsw->features & ETHSW_FEATURE_MAC_ADDR)) - return 0; - - /* Get firmware address, if any */ - err = dpsw_if_get_port_mac_addr(ethsw->mc_io, 0, ethsw->dpsw_handle, - port_priv->idx, mac_addr); - if (err) { - dev_err(dev, "dpsw_if_get_port_mac_addr() failed\n"); - return err; - } - - /* First check if firmware has any address configured by bootloader */ - if (!is_zero_ether_addr(mac_addr)) { - memcpy(net_dev->dev_addr, mac_addr, net_dev->addr_len); - } else { - /* No MAC address configured, fill in net_dev->dev_addr - * with a random one - */ - eth_hw_addr_random(net_dev); - dev_dbg_once(dev, "device(s) have all-zero hwaddr, replaced with random\n"); - - /* Override NET_ADDR_RANDOM set by eth_hw_addr_random(); for all - * practical purposes, this will be our "permanent" mac address, - * at least until the next reboot. This move will also permit - * register_netdevice() to properly fill up net_dev->perm_addr. - */ - net_dev->addr_assign_type = NET_ADDR_PERM; - } - - return 0; -} - -static void dpaa2_switch_free_fd(const struct ethsw_core *ethsw, - const struct dpaa2_fd *fd) -{ - struct device *dev = ethsw->dev; - unsigned char *buffer_start; - struct sk_buff **skbh, *skb; - dma_addr_t fd_addr; - - fd_addr = dpaa2_fd_get_addr(fd); - skbh = dpaa2_iova_to_virt(ethsw->iommu_domain, fd_addr); - - skb = *skbh; - buffer_start = (unsigned char *)skbh; - - dma_unmap_single(dev, fd_addr, - skb_tail_pointer(skb) - buffer_start, - DMA_TO_DEVICE); - - /* Move on with skb release */ - dev_kfree_skb(skb); -} - -static int dpaa2_switch_build_single_fd(struct ethsw_core *ethsw, - struct sk_buff *skb, - struct dpaa2_fd *fd) -{ - struct device *dev = ethsw->dev; - struct sk_buff **skbh; - dma_addr_t addr; - u8 *buff_start; - void *hwa; - - buff_start = PTR_ALIGN(skb->data - DPAA2_SWITCH_TX_DATA_OFFSET - - DPAA2_SWITCH_TX_BUF_ALIGN, - DPAA2_SWITCH_TX_BUF_ALIGN); - - /* Clear FAS to have consistent values for TX confirmation. It is - * located in the first 8 bytes of the buffer's hardware annotation - * area - */ - hwa = buff_start + DPAA2_SWITCH_SWA_SIZE; - memset(hwa, 0, 8); - - /* Store a backpointer to the skb at the beginning of the buffer - * (in the private data area) such that we can release it - * on Tx confirm - */ - skbh = (struct sk_buff **)buff_start; - *skbh = skb; - - addr = dma_map_single(dev, buff_start, - skb_tail_pointer(skb) - buff_start, - DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(dev, addr))) - return -ENOMEM; - - /* Setup the FD fields */ - memset(fd, 0, sizeof(*fd)); - - dpaa2_fd_set_addr(fd, addr); - dpaa2_fd_set_offset(fd, (u16)(skb->data - buff_start)); - dpaa2_fd_set_len(fd, skb->len); - dpaa2_fd_set_format(fd, dpaa2_fd_single); - - return 0; -} - -static netdev_tx_t dpaa2_switch_port_tx(struct sk_buff *skb, - struct net_device *net_dev) -{ - struct ethsw_port_priv *port_priv = netdev_priv(net_dev); - struct ethsw_core *ethsw = port_priv->ethsw_data; - int retries = DPAA2_SWITCH_SWP_BUSY_RETRIES; - struct dpaa2_fd fd; - int err; - - if (unlikely(skb_headroom(skb) < DPAA2_SWITCH_NEEDED_HEADROOM)) { - struct sk_buff *ns; - - ns = skb_realloc_headroom(skb, DPAA2_SWITCH_NEEDED_HEADROOM); - if (unlikely(!ns)) { - net_err_ratelimited("%s: Error reallocating skb headroom\n", net_dev->name); - goto err_free_skb; - } - dev_consume_skb_any(skb); - skb = ns; - } - - /* We'll be holding a back-reference to the skb until Tx confirmation */ - skb = skb_unshare(skb, GFP_ATOMIC); - if (unlikely(!skb)) { - /* skb_unshare() has already freed the skb */ - net_err_ratelimited("%s: Error copying the socket buffer\n", net_dev->name); - goto err_exit; - } - - /* At this stage, we do not support non-linear skbs so just try to - * linearize the skb and if that's not working, just drop the packet. - */ - err = skb_linearize(skb); - if (err) { - net_err_ratelimited("%s: skb_linearize error (%d)!\n", net_dev->name, err); - goto err_free_skb; - } - - err = dpaa2_switch_build_single_fd(ethsw, skb, &fd); - if (unlikely(err)) { - net_err_ratelimited("%s: ethsw_build_*_fd() %d\n", net_dev->name, err); - goto err_free_skb; - } - - do { - err = dpaa2_io_service_enqueue_qd(NULL, - port_priv->tx_qdid, - 8, 0, &fd); - retries--; - } while (err == -EBUSY && retries); - - if (unlikely(err < 0)) { - dpaa2_switch_free_fd(ethsw, &fd); - goto err_exit; - } - - return NETDEV_TX_OK; - -err_free_skb: - dev_kfree_skb(skb); -err_exit: - return NETDEV_TX_OK; -} - -static const struct net_device_ops dpaa2_switch_port_ops = { - .ndo_open = dpaa2_switch_port_open, - .ndo_stop = dpaa2_switch_port_stop, - - .ndo_set_mac_address = eth_mac_addr, - .ndo_get_stats64 = dpaa2_switch_port_get_stats, - .ndo_change_mtu = dpaa2_switch_port_change_mtu, - .ndo_has_offload_stats = dpaa2_switch_port_has_offload_stats, - .ndo_get_offload_stats = dpaa2_switch_port_get_offload_stats, - .ndo_fdb_dump = dpaa2_switch_port_fdb_dump, - .ndo_vlan_rx_add_vid = dpaa2_switch_port_vlan_add, - .ndo_vlan_rx_kill_vid = dpaa2_switch_port_vlan_kill, - - .ndo_start_xmit = dpaa2_switch_port_tx, - .ndo_get_port_parent_id = dpaa2_switch_port_parent_id, - .ndo_get_phys_port_name = dpaa2_switch_port_get_phys_name, -}; - -bool dpaa2_switch_port_dev_check(const struct net_device *netdev) -{ - return netdev->netdev_ops == &dpaa2_switch_port_ops; -} - -static void dpaa2_switch_links_state_update(struct ethsw_core *ethsw) -{ - int i; - - for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { - dpaa2_switch_port_carrier_state_sync(ethsw->ports[i]->netdev); - dpaa2_switch_port_set_mac_addr(ethsw->ports[i]); - } -} - -static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg) -{ - struct device *dev = (struct device *)arg; - struct ethsw_core *ethsw = dev_get_drvdata(dev); - - /* Mask the events and the if_id reserved bits to be cleared on read */ - u32 status = DPSW_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000; - int err; - - err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, - DPSW_IRQ_INDEX_IF, &status); - if (err) { - dev_err(dev, "Can't get irq status (err %d)\n", err); - - err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, - DPSW_IRQ_INDEX_IF, 0xFFFFFFFF); - if (err) - dev_err(dev, "Can't clear irq status (err %d)\n", err); - goto out; - } - - if (status & DPSW_IRQ_EVENT_LINK_CHANGED) - dpaa2_switch_links_state_update(ethsw); - -out: - return IRQ_HANDLED; -} - -static int dpaa2_switch_setup_irqs(struct fsl_mc_device *sw_dev) -{ - struct device *dev = &sw_dev->dev; - struct ethsw_core *ethsw = dev_get_drvdata(dev); - u32 mask = DPSW_IRQ_EVENT_LINK_CHANGED; - struct fsl_mc_device_irq *irq; - int err; - - err = fsl_mc_allocate_irqs(sw_dev); - if (err) { - dev_err(dev, "MC irqs allocation failed\n"); - return err; - } - - if (WARN_ON(sw_dev->obj_desc.irq_count != DPSW_IRQ_NUM)) { - err = -EINVAL; - goto free_irq; - } - - err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, - DPSW_IRQ_INDEX_IF, 0); - if (err) { - dev_err(dev, "dpsw_set_irq_enable err %d\n", err); - goto free_irq; - } - - irq = sw_dev->irqs[DPSW_IRQ_INDEX_IF]; - - err = devm_request_threaded_irq(dev, irq->msi_desc->irq, - NULL, - dpaa2_switch_irq0_handler_thread, - IRQF_NO_SUSPEND | IRQF_ONESHOT, - dev_name(dev), dev); - if (err) { - dev_err(dev, "devm_request_threaded_irq(): %d\n", err); - goto free_irq; - } - - err = dpsw_set_irq_mask(ethsw->mc_io, 0, ethsw->dpsw_handle, - DPSW_IRQ_INDEX_IF, mask); - if (err) { - dev_err(dev, "dpsw_set_irq_mask(): %d\n", err); - goto free_devm_irq; - } - - err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, - DPSW_IRQ_INDEX_IF, 1); - if (err) { - dev_err(dev, "dpsw_set_irq_enable(): %d\n", err); - goto free_devm_irq; - } - - return 0; - -free_devm_irq: - devm_free_irq(dev, irq->msi_desc->irq, dev); -free_irq: - fsl_mc_free_irqs(sw_dev); - return err; -} - -static void dpaa2_switch_teardown_irqs(struct fsl_mc_device *sw_dev) -{ - struct device *dev = &sw_dev->dev; - struct ethsw_core *ethsw = dev_get_drvdata(dev); - int err; - - err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, - DPSW_IRQ_INDEX_IF, 0); - if (err) - dev_err(dev, "dpsw_set_irq_enable err %d\n", err); - - fsl_mc_free_irqs(sw_dev); -} - -static int dpaa2_switch_port_attr_stp_state_set(struct net_device *netdev, - u8 state) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - - return dpaa2_switch_port_set_stp_state(port_priv, state); -} - -static int dpaa2_switch_port_attr_set(struct net_device *netdev, - const struct switchdev_attr *attr, - struct netlink_ext_ack *extack) -{ - int err = 0; - - switch (attr->id) { - case SWITCHDEV_ATTR_ID_PORT_STP_STATE: - err = dpaa2_switch_port_attr_stp_state_set(netdev, - attr->u.stp_state); - break; - case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: - if (!attr->u.vlan_filtering) { - NL_SET_ERR_MSG_MOD(extack, - "The DPAA2 switch does not support VLAN-unaware operation"); - return -EOPNOTSUPP; - } - break; - default: - err = -EOPNOTSUPP; - break; - } - - return err; -} - -int dpaa2_switch_port_vlans_add(struct net_device *netdev, - const struct switchdev_obj_port_vlan *vlan) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct dpsw_attr *attr = ðsw->sw_attr; - int err = 0; - - /* Make sure that the VLAN is not already configured - * on the switch port - */ - if (port_priv->vlans[vlan->vid] & ETHSW_VLAN_MEMBER) - return -EEXIST; - - /* Check if there is space for a new VLAN */ - err = dpsw_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle, - ðsw->sw_attr); - if (err) { - netdev_err(netdev, "dpsw_get_attributes err %d\n", err); - return err; - } - if (attr->max_vlans - attr->num_vlans < 1) - return -ENOSPC; - - /* Check if there is space for a new VLAN */ - err = dpsw_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle, - ðsw->sw_attr); - if (err) { - netdev_err(netdev, "dpsw_get_attributes err %d\n", err); - return err; - } - if (attr->max_vlans - attr->num_vlans < 1) - return -ENOSPC; - - if (!port_priv->ethsw_data->vlans[vlan->vid]) { - /* this is a new VLAN */ - err = dpaa2_switch_add_vlan(port_priv, vlan->vid); - if (err) - return err; - - port_priv->ethsw_data->vlans[vlan->vid] |= ETHSW_VLAN_GLOBAL; - } - - return dpaa2_switch_port_add_vlan(port_priv, vlan->vid, vlan->flags); -} - -static int dpaa2_switch_port_lookup_address(struct net_device *netdev, int is_uc, - const unsigned char *addr) -{ - struct netdev_hw_addr_list *list = (is_uc) ? &netdev->uc : &netdev->mc; - struct netdev_hw_addr *ha; - - netif_addr_lock_bh(netdev); - list_for_each_entry(ha, &list->list, list) { - if (ether_addr_equal(ha->addr, addr)) { - netif_addr_unlock_bh(netdev); - return 1; - } - } - netif_addr_unlock_bh(netdev); - return 0; -} - -static int dpaa2_switch_port_mdb_add(struct net_device *netdev, - const struct switchdev_obj_port_mdb *mdb) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - int err; - - /* Check if address is already set on this port */ - if (dpaa2_switch_port_lookup_address(netdev, 0, mdb->addr)) - return -EEXIST; - - err = dpaa2_switch_port_fdb_add_mc(port_priv, mdb->addr); - if (err) - return err; - - err = dev_mc_add(netdev, mdb->addr); - if (err) { - netdev_err(netdev, "dev_mc_add err %d\n", err); - dpaa2_switch_port_fdb_del_mc(port_priv, mdb->addr); - } - - return err; -} - -static int dpaa2_switch_port_obj_add(struct net_device *netdev, - const struct switchdev_obj *obj) -{ - int err; - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = dpaa2_switch_port_vlans_add(netdev, - SWITCHDEV_OBJ_PORT_VLAN(obj)); - break; - case SWITCHDEV_OBJ_ID_PORT_MDB: - err = dpaa2_switch_port_mdb_add(netdev, - SWITCHDEV_OBJ_PORT_MDB(obj)); - break; - default: - err = -EOPNOTSUPP; - break; - } - - return err; -} - -static int dpaa2_switch_port_del_vlan(struct ethsw_port_priv *port_priv, u16 vid) -{ - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct net_device *netdev = port_priv->netdev; - struct dpsw_vlan_if_cfg vcfg; - int i, err; - - if (!port_priv->vlans[vid]) - return -ENOENT; - - if (port_priv->vlans[vid] & ETHSW_VLAN_PVID) { - /* If we are deleting the PVID of a port, use VLAN 4095 instead - * as we are sure that neither the bridge nor the 8021q module - * will use it - */ - err = dpaa2_switch_port_set_pvid(port_priv, 4095); - if (err) - return err; - } - - vcfg.num_ifs = 1; - vcfg.if_id[0] = port_priv->idx; - if (port_priv->vlans[vid] & ETHSW_VLAN_UNTAGGED) { - err = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0, - ethsw->dpsw_handle, - vid, &vcfg); - if (err) { - netdev_err(netdev, - "dpsw_vlan_remove_if_untagged err %d\n", - err); - } - port_priv->vlans[vid] &= ~ETHSW_VLAN_UNTAGGED; - } - - if (port_priv->vlans[vid] & ETHSW_VLAN_MEMBER) { - err = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle, - vid, &vcfg); - if (err) { - netdev_err(netdev, - "dpsw_vlan_remove_if err %d\n", err); - return err; - } - port_priv->vlans[vid] &= ~ETHSW_VLAN_MEMBER; - - /* Delete VLAN from switch if it is no longer configured on - * any port - */ - for (i = 0; i < ethsw->sw_attr.num_ifs; i++) - if (ethsw->ports[i]->vlans[vid] & ETHSW_VLAN_MEMBER) - return 0; /* Found a port member in VID */ - - ethsw->vlans[vid] &= ~ETHSW_VLAN_GLOBAL; - - err = dpaa2_switch_dellink(ethsw, vid); - if (err) - return err; - } - - return 0; -} - -int dpaa2_switch_port_vlans_del(struct net_device *netdev, - const struct switchdev_obj_port_vlan *vlan) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - - if (netif_is_bridge_master(vlan->obj.orig_dev)) - return -EOPNOTSUPP; - - return dpaa2_switch_port_del_vlan(port_priv, vlan->vid); -} - -static int dpaa2_switch_port_mdb_del(struct net_device *netdev, - const struct switchdev_obj_port_mdb *mdb) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - int err; - - if (!dpaa2_switch_port_lookup_address(netdev, 0, mdb->addr)) - return -ENOENT; - - err = dpaa2_switch_port_fdb_del_mc(port_priv, mdb->addr); - if (err) - return err; - - err = dev_mc_del(netdev, mdb->addr); - if (err) { - netdev_err(netdev, "dev_mc_del err %d\n", err); - return err; - } - - return err; -} - -static int dpaa2_switch_port_obj_del(struct net_device *netdev, - const struct switchdev_obj *obj) -{ - int err; - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = dpaa2_switch_port_vlans_del(netdev, SWITCHDEV_OBJ_PORT_VLAN(obj)); - break; - case SWITCHDEV_OBJ_ID_PORT_MDB: - err = dpaa2_switch_port_mdb_del(netdev, SWITCHDEV_OBJ_PORT_MDB(obj)); - break; - default: - err = -EOPNOTSUPP; - break; - } - return err; -} - -static int dpaa2_switch_port_attr_set_event(struct net_device *netdev, - struct switchdev_notifier_port_attr_info *ptr) -{ - int err; - - err = switchdev_handle_port_attr_set(netdev, ptr, - dpaa2_switch_port_dev_check, - dpaa2_switch_port_attr_set); - return notifier_from_errno(err); -} - -static int dpaa2_switch_fdb_set_egress_flood(struct ethsw_core *ethsw, u16 fdb_id) -{ - struct dpsw_egress_flood_cfg flood_cfg; - int i = 0, j; - int err; - - /* Add all the DPAA2 switch ports found in the same bridging domain to - * the egress flooding domain - */ - for (j = 0; j < ethsw->sw_attr.num_ifs; j++) - if (ethsw->ports[j] && ethsw->ports[j]->fdb->fdb_id == fdb_id) - flood_cfg.if_id[i++] = ethsw->ports[j]->idx; - - /* Add the CTRL interface to the egress flooding domain */ - flood_cfg.if_id[i++] = ethsw->sw_attr.num_ifs; - - /* Use the FDB of the first dpaa2 switch port added to the bridge */ - flood_cfg.fdb_id = fdb_id; - - /* Setup broadcast flooding domain */ - flood_cfg.flood_type = DPSW_BROADCAST; - flood_cfg.num_ifs = i; - err = dpsw_set_egress_flood(ethsw->mc_io, 0, ethsw->dpsw_handle, - &flood_cfg); - if (err) { - dev_err(ethsw->dev, "dpsw_set_egress_flood() = %d\n", err); - return err; - } - - /* Setup unknown flooding domain */ - flood_cfg.flood_type = DPSW_FLOODING; - flood_cfg.num_ifs = i; - err = dpsw_set_egress_flood(ethsw->mc_io, 0, ethsw->dpsw_handle, - &flood_cfg); - if (err) { - dev_err(ethsw->dev, "dpsw_set_egress_flood() = %d\n", err); - return err; - } - - return 0; -} - -static int dpaa2_switch_port_bridge_join(struct net_device *netdev, - struct net_device *upper_dev) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct ethsw_port_priv *other_port_priv; - struct net_device *other_dev; - struct list_head *iter; - int err; - - netdev_for_each_lower_dev(upper_dev, other_dev, iter) { - if (!dpaa2_switch_port_dev_check(other_dev)) - continue; - - other_port_priv = netdev_priv(other_dev); - if (other_port_priv->ethsw_data != port_priv->ethsw_data) { - netdev_err(netdev, - "Interface from a different DPSW is in the bridge already!\n"); - return -EINVAL; - } - } - - /* Delete the previously manually installed VLAN 1 */ - err = dpaa2_switch_port_del_vlan(port_priv, 1); - if (err) - return err; - - dpaa2_switch_port_set_fdb(port_priv, upper_dev); - - /* Setup the egress flood policy (broadcast, unknown unicast) */ - err = dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id); - if (err) - goto err_egress_flood; - - return 0; - -err_egress_flood: - dpaa2_switch_port_set_fdb(port_priv, NULL); - return err; -} - -static int dpaa2_switch_port_clear_rxvlan(struct net_device *vdev, int vid, void *arg) -{ - __be16 vlan_proto = htons(ETH_P_8021Q); - - if (vdev) - vlan_proto = vlan_dev_vlan_proto(vdev); - - return dpaa2_switch_port_vlan_kill(arg, vlan_proto, vid); -} - -static int dpaa2_switch_port_restore_rxvlan(struct net_device *vdev, int vid, void *arg) -{ - __be16 vlan_proto = htons(ETH_P_8021Q); - - if (vdev) - vlan_proto = vlan_dev_vlan_proto(vdev); - - return dpaa2_switch_port_vlan_add(arg, vlan_proto, vid); -} - -static int dpaa2_switch_port_bridge_leave(struct net_device *netdev) -{ - struct ethsw_port_priv *port_priv = netdev_priv(netdev); - struct dpaa2_switch_fdb *old_fdb = port_priv->fdb; - struct ethsw_core *ethsw = port_priv->ethsw_data; - int err; - - /* First of all, fast age any learn FDB addresses on this switch port */ - dpaa2_switch_port_fast_age(port_priv); - - /* Clear all RX VLANs installed through vlan_vid_add() either as VLAN - * upper devices or otherwise from the FDB table that we are about to - * leave - */ - err = vlan_for_each(netdev, dpaa2_switch_port_clear_rxvlan, netdev); - if (err) - netdev_err(netdev, "Unable to clear RX VLANs from old FDB table, err (%d)\n", err); - - dpaa2_switch_port_set_fdb(port_priv, NULL); - - /* Restore all RX VLANs into the new FDB table that we just joined */ - err = vlan_for_each(netdev, dpaa2_switch_port_restore_rxvlan, netdev); - if (err) - netdev_err(netdev, "Unable to restore RX VLANs to the new FDB, err (%d)\n", err); - - /* Setup the egress flood policy (broadcast, unknown unicast). - * When the port is not under a bridge, only the CTRL interface is part - * of the flooding domain besides the actual port - */ - err = dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id); - if (err) - return err; - - /* Recreate the egress flood domain of the FDB that we just left */ - err = dpaa2_switch_fdb_set_egress_flood(ethsw, old_fdb->fdb_id); - if (err) - return err; - - /* Add the VLAN 1 as PVID when not under a bridge. We need this since - * the dpaa2 switch interfaces are not capable to be VLAN unaware - */ - return dpaa2_switch_port_add_vlan(port_priv, DEFAULT_VLAN_ID, - BRIDGE_VLAN_INFO_UNTAGGED | BRIDGE_VLAN_INFO_PVID); -} - -static int dpaa2_switch_prevent_bridging_with_8021q_upper(struct net_device *netdev) -{ - struct net_device *upper_dev; - struct list_head *iter; - - /* RCU read lock not necessary because we have write-side protection - * (rtnl_mutex), however a non-rcu iterator does not exist. - */ - netdev_for_each_upper_dev_rcu(netdev, upper_dev, iter) - if (is_vlan_dev(upper_dev)) - return -EOPNOTSUPP; - - return 0; -} - -static int dpaa2_switch_port_netdevice_event(struct notifier_block *nb, - unsigned long event, void *ptr) -{ - struct net_device *netdev = netdev_notifier_info_to_dev(ptr); - struct netdev_notifier_changeupper_info *info = ptr; - struct netlink_ext_ack *extack; - struct net_device *upper_dev; - int err = 0; - - if (!dpaa2_switch_port_dev_check(netdev)) - return NOTIFY_DONE; - - extack = netdev_notifier_info_to_extack(&info->info); - - switch (event) { - case NETDEV_PRECHANGEUPPER: - upper_dev = info->upper_dev; - if (!netif_is_bridge_master(upper_dev)) - break; - - if (!br_vlan_enabled(upper_dev)) { - NL_SET_ERR_MSG_MOD(extack, "Cannot join a VLAN-unaware bridge"); - err = -EOPNOTSUPP; - goto out; - } - - err = dpaa2_switch_prevent_bridging_with_8021q_upper(netdev); - if (err) { - NL_SET_ERR_MSG_MOD(extack, - "Cannot join a bridge while VLAN uppers are present"); - goto out; - } - - break; - case NETDEV_CHANGEUPPER: - upper_dev = info->upper_dev; - if (netif_is_bridge_master(upper_dev)) { - if (info->linking) - err = dpaa2_switch_port_bridge_join(netdev, upper_dev); - else - err = dpaa2_switch_port_bridge_leave(netdev); - } - break; - } - -out: - return notifier_from_errno(err); -} - -struct ethsw_switchdev_event_work { - struct work_struct work; - struct switchdev_notifier_fdb_info fdb_info; - struct net_device *dev; - unsigned long event; -}; - -static void dpaa2_switch_event_work(struct work_struct *work) -{ - struct ethsw_switchdev_event_work *switchdev_work = - container_of(work, struct ethsw_switchdev_event_work, work); - struct net_device *dev = switchdev_work->dev; - struct switchdev_notifier_fdb_info *fdb_info; - int err; - - rtnl_lock(); - fdb_info = &switchdev_work->fdb_info; - - switch (switchdev_work->event) { - case SWITCHDEV_FDB_ADD_TO_DEVICE: - if (!fdb_info->added_by_user) - break; - if (is_unicast_ether_addr(fdb_info->addr)) - err = dpaa2_switch_port_fdb_add_uc(netdev_priv(dev), - fdb_info->addr); - else - err = dpaa2_switch_port_fdb_add_mc(netdev_priv(dev), - fdb_info->addr); - if (err) - break; - fdb_info->offloaded = true; - call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev, - &fdb_info->info, NULL); - break; - case SWITCHDEV_FDB_DEL_TO_DEVICE: - if (!fdb_info->added_by_user) - break; - if (is_unicast_ether_addr(fdb_info->addr)) - dpaa2_switch_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr); - else - dpaa2_switch_port_fdb_del_mc(netdev_priv(dev), fdb_info->addr); - break; - } - - rtnl_unlock(); - kfree(switchdev_work->fdb_info.addr); - kfree(switchdev_work); - dev_put(dev); -} - -/* Called under rcu_read_lock() */ -static int dpaa2_switch_port_event(struct notifier_block *nb, - unsigned long event, void *ptr) -{ - struct net_device *dev = switchdev_notifier_info_to_dev(ptr); - struct ethsw_port_priv *port_priv = netdev_priv(dev); - struct ethsw_switchdev_event_work *switchdev_work; - struct switchdev_notifier_fdb_info *fdb_info = ptr; - struct ethsw_core *ethsw = port_priv->ethsw_data; - - if (event == SWITCHDEV_PORT_ATTR_SET) - return dpaa2_switch_port_attr_set_event(dev, ptr); - - if (!dpaa2_switch_port_dev_check(dev)) - return NOTIFY_DONE; - - switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); - if (!switchdev_work) - return NOTIFY_BAD; - - INIT_WORK(&switchdev_work->work, dpaa2_switch_event_work); - switchdev_work->dev = dev; - switchdev_work->event = event; - - switch (event) { - case SWITCHDEV_FDB_ADD_TO_DEVICE: - case SWITCHDEV_FDB_DEL_TO_DEVICE: - memcpy(&switchdev_work->fdb_info, ptr, - sizeof(switchdev_work->fdb_info)); - switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); - if (!switchdev_work->fdb_info.addr) - goto err_addr_alloc; - - ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, - fdb_info->addr); - - /* Take a reference on the device to avoid being freed. */ - dev_hold(dev); - break; - default: - kfree(switchdev_work); - return NOTIFY_DONE; - } - - queue_work(ethsw->workqueue, &switchdev_work->work); - - return NOTIFY_DONE; - -err_addr_alloc: - kfree(switchdev_work); - return NOTIFY_BAD; -} - -static int dpaa2_switch_port_obj_event(unsigned long event, - struct net_device *netdev, - struct switchdev_notifier_port_obj_info *port_obj_info) -{ - int err = -EOPNOTSUPP; - - if (!dpaa2_switch_port_dev_check(netdev)) - return NOTIFY_DONE; - - switch (event) { - case SWITCHDEV_PORT_OBJ_ADD: - err = dpaa2_switch_port_obj_add(netdev, port_obj_info->obj); - break; - case SWITCHDEV_PORT_OBJ_DEL: - err = dpaa2_switch_port_obj_del(netdev, port_obj_info->obj); - break; - } - - port_obj_info->handled = true; - return notifier_from_errno(err); -} - -static int dpaa2_switch_port_blocking_event(struct notifier_block *nb, - unsigned long event, void *ptr) -{ - struct net_device *dev = switchdev_notifier_info_to_dev(ptr); - - switch (event) { - case SWITCHDEV_PORT_OBJ_ADD: - case SWITCHDEV_PORT_OBJ_DEL: - return dpaa2_switch_port_obj_event(event, dev, ptr); - case SWITCHDEV_PORT_ATTR_SET: - return dpaa2_switch_port_attr_set_event(dev, ptr); - } - - return NOTIFY_DONE; -} - -/* Build a linear skb based on a single-buffer frame descriptor */ -static struct sk_buff *dpaa2_switch_build_linear_skb(struct ethsw_core *ethsw, - const struct dpaa2_fd *fd) -{ - u16 fd_offset = dpaa2_fd_get_offset(fd); - dma_addr_t addr = dpaa2_fd_get_addr(fd); - u32 fd_length = dpaa2_fd_get_len(fd); - struct device *dev = ethsw->dev; - struct sk_buff *skb = NULL; - void *fd_vaddr; - - fd_vaddr = dpaa2_iova_to_virt(ethsw->iommu_domain, addr); - dma_unmap_page(dev, addr, DPAA2_SWITCH_RX_BUF_SIZE, - DMA_FROM_DEVICE); - - skb = build_skb(fd_vaddr, DPAA2_SWITCH_RX_BUF_SIZE + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); - if (unlikely(!skb)) { - dev_err(dev, "build_skb() failed\n"); - return NULL; - } - - skb_reserve(skb, fd_offset); - skb_put(skb, fd_length); - - ethsw->buf_count--; - - return skb; -} - -static void dpaa2_switch_tx_conf(struct dpaa2_switch_fq *fq, - const struct dpaa2_fd *fd) -{ - dpaa2_switch_free_fd(fq->ethsw, fd); -} - -static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq, - const struct dpaa2_fd *fd) -{ - struct ethsw_core *ethsw = fq->ethsw; - struct ethsw_port_priv *port_priv; - struct net_device *netdev; - struct vlan_ethhdr *hdr; - struct sk_buff *skb; - u16 vlan_tci, vid; - int if_id, err; - - /* get switch ingress interface ID */ - if_id = upper_32_bits(dpaa2_fd_get_flc(fd)) & 0x0000FFFF; - - if (if_id >= ethsw->sw_attr.num_ifs) { - dev_err(ethsw->dev, "Frame received from unknown interface!\n"); - goto err_free_fd; - } - port_priv = ethsw->ports[if_id]; - netdev = port_priv->netdev; - - /* build the SKB based on the FD received */ - if (dpaa2_fd_get_format(fd) != dpaa2_fd_single) { - if (net_ratelimit()) { - netdev_err(netdev, "Received invalid frame format\n"); - goto err_free_fd; - } - } - - skb = dpaa2_switch_build_linear_skb(ethsw, fd); - if (unlikely(!skb)) - goto err_free_fd; - - skb_reset_mac_header(skb); - - /* Remove the VLAN header if the packet that we just received has a vid - * equal to the port PVIDs. Since the dpaa2-switch can operate only in - * VLAN-aware mode and no alterations are made on the packet when it's - * redirected/mirrored to the control interface, we are sure that there - * will always be a VLAN header present. - */ - hdr = vlan_eth_hdr(skb); - vid = ntohs(hdr->h_vlan_TCI) & VLAN_VID_MASK; - if (vid == port_priv->pvid) { - err = __skb_vlan_pop(skb, &vlan_tci); - if (err) { - dev_info(ethsw->dev, "__skb_vlan_pop() returned %d", err); - goto err_free_fd; - } - } - - skb->dev = netdev; - skb->protocol = eth_type_trans(skb, skb->dev); - - netif_receive_skb(skb); - - return; - -err_free_fd: - dpaa2_switch_free_fd(ethsw, fd); -} - -static void dpaa2_switch_detect_features(struct ethsw_core *ethsw) -{ - ethsw->features = 0; - - if (ethsw->major > 8 || (ethsw->major == 8 && ethsw->minor >= 6)) - ethsw->features |= ETHSW_FEATURE_MAC_ADDR; -} - -static int dpaa2_switch_setup_fqs(struct ethsw_core *ethsw) -{ - struct dpsw_ctrl_if_attr ctrl_if_attr; - struct device *dev = ethsw->dev; - int i = 0; - int err; - - err = dpsw_ctrl_if_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle, - &ctrl_if_attr); - if (err) { - dev_err(dev, "dpsw_ctrl_if_get_attributes() = %d\n", err); - return err; - } - - ethsw->fq[i].fqid = ctrl_if_attr.rx_fqid; - ethsw->fq[i].ethsw = ethsw; - ethsw->fq[i++].type = DPSW_QUEUE_RX; - - ethsw->fq[i].fqid = ctrl_if_attr.tx_err_conf_fqid; - ethsw->fq[i].ethsw = ethsw; - ethsw->fq[i++].type = DPSW_QUEUE_TX_ERR_CONF; - - return 0; -} - -/* Free buffers acquired from the buffer pool or which were meant to - * be released in the pool - */ -static void dpaa2_switch_free_bufs(struct ethsw_core *ethsw, u64 *buf_array, int count) -{ - struct device *dev = ethsw->dev; - void *vaddr; - int i; - - for (i = 0; i < count; i++) { - vaddr = dpaa2_iova_to_virt(ethsw->iommu_domain, buf_array[i]); - dma_unmap_page(dev, buf_array[i], DPAA2_SWITCH_RX_BUF_SIZE, - DMA_FROM_DEVICE); - free_pages((unsigned long)vaddr, 0); - } -} - -/* Perform a single release command to add buffers - * to the specified buffer pool - */ -static int dpaa2_switch_add_bufs(struct ethsw_core *ethsw, u16 bpid) -{ - struct device *dev = ethsw->dev; - u64 buf_array[BUFS_PER_CMD]; - struct page *page; - int retries = 0; - dma_addr_t addr; - int err; - int i; - - for (i = 0; i < BUFS_PER_CMD; i++) { - /* Allocate one page for each Rx buffer. WRIOP sees - * the entire page except for a tailroom reserved for - * skb shared info - */ - page = dev_alloc_pages(0); - if (!page) { - dev_err(dev, "buffer allocation failed\n"); - goto err_alloc; - } - - addr = dma_map_page(dev, page, 0, DPAA2_SWITCH_RX_BUF_SIZE, - DMA_FROM_DEVICE); - if (dma_mapping_error(dev, addr)) { - dev_err(dev, "dma_map_single() failed\n"); - goto err_map; - } - buf_array[i] = addr; - } - -release_bufs: - /* In case the portal is busy, retry until successful or - * max retries hit. - */ - while ((err = dpaa2_io_service_release(NULL, bpid, - buf_array, i)) == -EBUSY) { - if (retries++ >= DPAA2_SWITCH_SWP_BUSY_RETRIES) - break; - - cpu_relax(); - } - - /* If release command failed, clean up and bail out. */ - if (err) { - dpaa2_switch_free_bufs(ethsw, buf_array, i); - return 0; - } - - return i; - -err_map: - __free_pages(page, 0); -err_alloc: - /* If we managed to allocate at least some buffers, - * release them to hardware - */ - if (i) - goto release_bufs; - - return 0; -} - -static int dpaa2_switch_refill_bp(struct ethsw_core *ethsw) -{ - int *count = ðsw->buf_count; - int new_count; - int err = 0; - - if (unlikely(*count < DPAA2_ETHSW_REFILL_THRESH)) { - do { - new_count = dpaa2_switch_add_bufs(ethsw, ethsw->bpid); - if (unlikely(!new_count)) { - /* Out of memory; abort for now, we'll - * try later on - */ - break; - } - *count += new_count; - } while (*count < DPAA2_ETHSW_NUM_BUFS); - - if (unlikely(*count < DPAA2_ETHSW_NUM_BUFS)) - err = -ENOMEM; - } - - return err; -} - -static int dpaa2_switch_seed_bp(struct ethsw_core *ethsw) -{ - int *count, i; - - for (i = 0; i < DPAA2_ETHSW_NUM_BUFS; i += BUFS_PER_CMD) { - count = ðsw->buf_count; - *count += dpaa2_switch_add_bufs(ethsw, ethsw->bpid); - - if (unlikely(*count < BUFS_PER_CMD)) - return -ENOMEM; - } - - return 0; -} - -static void dpaa2_switch_drain_bp(struct ethsw_core *ethsw) -{ - u64 buf_array[BUFS_PER_CMD]; - int ret; - - do { - ret = dpaa2_io_service_acquire(NULL, ethsw->bpid, - buf_array, BUFS_PER_CMD); - if (ret < 0) { - dev_err(ethsw->dev, - "dpaa2_io_service_acquire() = %d\n", ret); - return; - } - dpaa2_switch_free_bufs(ethsw, buf_array, ret); - - } while (ret); -} - -static int dpaa2_switch_setup_dpbp(struct ethsw_core *ethsw) -{ - struct dpsw_ctrl_if_pools_cfg dpsw_ctrl_if_pools_cfg = { 0 }; - struct device *dev = ethsw->dev; - struct fsl_mc_device *dpbp_dev; - struct dpbp_attr dpbp_attrs; - int err; - - err = fsl_mc_object_allocate(to_fsl_mc_device(dev), FSL_MC_POOL_DPBP, - &dpbp_dev); - if (err) { - if (err == -ENXIO) - err = -EPROBE_DEFER; - else - dev_err(dev, "DPBP device allocation failed\n"); - return err; - } - ethsw->dpbp_dev = dpbp_dev; - - err = dpbp_open(ethsw->mc_io, 0, dpbp_dev->obj_desc.id, - &dpbp_dev->mc_handle); - if (err) { - dev_err(dev, "dpbp_open() failed\n"); - goto err_open; - } - - err = dpbp_reset(ethsw->mc_io, 0, dpbp_dev->mc_handle); - if (err) { - dev_err(dev, "dpbp_reset() failed\n"); - goto err_reset; - } - - err = dpbp_enable(ethsw->mc_io, 0, dpbp_dev->mc_handle); - if (err) { - dev_err(dev, "dpbp_enable() failed\n"); - goto err_enable; - } - - err = dpbp_get_attributes(ethsw->mc_io, 0, dpbp_dev->mc_handle, - &dpbp_attrs); - if (err) { - dev_err(dev, "dpbp_get_attributes() failed\n"); - goto err_get_attr; - } - - dpsw_ctrl_if_pools_cfg.num_dpbp = 1; - dpsw_ctrl_if_pools_cfg.pools[0].dpbp_id = dpbp_attrs.id; - dpsw_ctrl_if_pools_cfg.pools[0].buffer_size = DPAA2_SWITCH_RX_BUF_SIZE; - dpsw_ctrl_if_pools_cfg.pools[0].backup_pool = 0; - - err = dpsw_ctrl_if_set_pools(ethsw->mc_io, 0, ethsw->dpsw_handle, - &dpsw_ctrl_if_pools_cfg); - if (err) { - dev_err(dev, "dpsw_ctrl_if_set_pools() failed\n"); - goto err_get_attr; - } - ethsw->bpid = dpbp_attrs.id; - - return 0; - -err_get_attr: - dpbp_disable(ethsw->mc_io, 0, dpbp_dev->mc_handle); -err_enable: -err_reset: - dpbp_close(ethsw->mc_io, 0, dpbp_dev->mc_handle); -err_open: - fsl_mc_object_free(dpbp_dev); - return err; -} - -static void dpaa2_switch_free_dpbp(struct ethsw_core *ethsw) -{ - dpbp_disable(ethsw->mc_io, 0, ethsw->dpbp_dev->mc_handle); - dpbp_close(ethsw->mc_io, 0, ethsw->dpbp_dev->mc_handle); - fsl_mc_object_free(ethsw->dpbp_dev); -} - -static int dpaa2_switch_alloc_rings(struct ethsw_core *ethsw) -{ - int i; - - for (i = 0; i < DPAA2_SWITCH_RX_NUM_FQS; i++) { - ethsw->fq[i].store = - dpaa2_io_store_create(DPAA2_SWITCH_STORE_SIZE, - ethsw->dev); - if (!ethsw->fq[i].store) { - dev_err(ethsw->dev, "dpaa2_io_store_create failed\n"); - while (--i >= 0) - dpaa2_io_store_destroy(ethsw->fq[i].store); - return -ENOMEM; - } - } - - return 0; -} - -static void dpaa2_switch_destroy_rings(struct ethsw_core *ethsw) -{ - int i; - - for (i = 0; i < DPAA2_SWITCH_RX_NUM_FQS; i++) - dpaa2_io_store_destroy(ethsw->fq[i].store); -} - -static int dpaa2_switch_pull_fq(struct dpaa2_switch_fq *fq) -{ - int err, retries = 0; - - /* Try to pull from the FQ while the portal is busy and we didn't hit - * the maximum number fo retries - */ - do { - err = dpaa2_io_service_pull_fq(NULL, fq->fqid, fq->store); - cpu_relax(); - } while (err == -EBUSY && retries++ < DPAA2_SWITCH_SWP_BUSY_RETRIES); - - if (unlikely(err)) - dev_err(fq->ethsw->dev, "dpaa2_io_service_pull err %d", err); - - return err; -} - -/* Consume all frames pull-dequeued into the store */ -static int dpaa2_switch_store_consume(struct dpaa2_switch_fq *fq) -{ - struct ethsw_core *ethsw = fq->ethsw; - int cleaned = 0, is_last; - struct dpaa2_dq *dq; - int retries = 0; - - do { - /* Get the next available FD from the store */ - dq = dpaa2_io_store_next(fq->store, &is_last); - if (unlikely(!dq)) { - if (retries++ >= DPAA2_SWITCH_SWP_BUSY_RETRIES) { - dev_err_once(ethsw->dev, - "No valid dequeue response\n"); - return -ETIMEDOUT; - } - continue; - } - - if (fq->type == DPSW_QUEUE_RX) - dpaa2_switch_rx(fq, dpaa2_dq_fd(dq)); - else - dpaa2_switch_tx_conf(fq, dpaa2_dq_fd(dq)); - cleaned++; - - } while (!is_last); - - return cleaned; -} - -/* NAPI poll routine */ -static int dpaa2_switch_poll(struct napi_struct *napi, int budget) -{ - int err, cleaned = 0, store_cleaned, work_done; - struct dpaa2_switch_fq *fq; - int retries = 0; - - fq = container_of(napi, struct dpaa2_switch_fq, napi); - - do { - err = dpaa2_switch_pull_fq(fq); - if (unlikely(err)) - break; - - /* Refill pool if appropriate */ - dpaa2_switch_refill_bp(fq->ethsw); - - store_cleaned = dpaa2_switch_store_consume(fq); - cleaned += store_cleaned; - - if (cleaned >= budget) { - work_done = budget; - goto out; - } - - } while (store_cleaned); - - /* We didn't consume the entire budget, so finish napi and re-enable - * data availability notifications - */ - napi_complete_done(napi, cleaned); - do { - err = dpaa2_io_service_rearm(NULL, &fq->nctx); - cpu_relax(); - } while (err == -EBUSY && retries++ < DPAA2_SWITCH_SWP_BUSY_RETRIES); - - work_done = max(cleaned, 1); -out: - - return work_done; -} - -static void dpaa2_switch_fqdan_cb(struct dpaa2_io_notification_ctx *nctx) -{ - struct dpaa2_switch_fq *fq; - - fq = container_of(nctx, struct dpaa2_switch_fq, nctx); - - napi_schedule(&fq->napi); -} - -static int dpaa2_switch_setup_dpio(struct ethsw_core *ethsw) -{ - struct dpsw_ctrl_if_queue_cfg queue_cfg; - struct dpaa2_io_notification_ctx *nctx; - int err, i, j; - - for (i = 0; i < DPAA2_SWITCH_RX_NUM_FQS; i++) { - nctx = ðsw->fq[i].nctx; - - /* Register a new software context for the FQID. - * By using NULL as the first parameter, we specify that we do - * not care on which cpu are interrupts received for this queue - */ - nctx->is_cdan = 0; - nctx->id = ethsw->fq[i].fqid; - nctx->desired_cpu = DPAA2_IO_ANY_CPU; - nctx->cb = dpaa2_switch_fqdan_cb; - err = dpaa2_io_service_register(NULL, nctx, ethsw->dev); - if (err) { - err = -EPROBE_DEFER; - goto err_register; - } - - queue_cfg.options = DPSW_CTRL_IF_QUEUE_OPT_DEST | - DPSW_CTRL_IF_QUEUE_OPT_USER_CTX; - queue_cfg.dest_cfg.dest_type = DPSW_CTRL_IF_DEST_DPIO; - queue_cfg.dest_cfg.dest_id = nctx->dpio_id; - queue_cfg.dest_cfg.priority = 0; - queue_cfg.user_ctx = nctx->qman64; - - err = dpsw_ctrl_if_set_queue(ethsw->mc_io, 0, - ethsw->dpsw_handle, - ethsw->fq[i].type, - &queue_cfg); - if (err) - goto err_set_queue; - } - - return 0; - -err_set_queue: - dpaa2_io_service_deregister(NULL, nctx, ethsw->dev); -err_register: - for (j = 0; j < i; j++) - dpaa2_io_service_deregister(NULL, ðsw->fq[j].nctx, - ethsw->dev); - - return err; -} - -static void dpaa2_switch_free_dpio(struct ethsw_core *ethsw) -{ - int i; - - for (i = 0; i < DPAA2_SWITCH_RX_NUM_FQS; i++) - dpaa2_io_service_deregister(NULL, ðsw->fq[i].nctx, - ethsw->dev); -} - -static int dpaa2_switch_ctrl_if_setup(struct ethsw_core *ethsw) -{ - int err; - - /* setup FQs for Rx and Tx Conf */ - err = dpaa2_switch_setup_fqs(ethsw); - if (err) - return err; - - /* setup the buffer pool needed on the Rx path */ - err = dpaa2_switch_setup_dpbp(ethsw); - if (err) - return err; - - err = dpaa2_switch_seed_bp(ethsw); - if (err) - goto err_free_dpbp; - - err = dpaa2_switch_alloc_rings(ethsw); - if (err) - goto err_drain_dpbp; - - err = dpaa2_switch_setup_dpio(ethsw); - if (err) - goto err_destroy_rings; - - err = dpsw_ctrl_if_enable(ethsw->mc_io, 0, ethsw->dpsw_handle); - if (err) { - dev_err(ethsw->dev, "dpsw_ctrl_if_enable err %d\n", err); - goto err_deregister_dpio; - } - - return 0; - -err_deregister_dpio: - dpaa2_switch_free_dpio(ethsw); -err_destroy_rings: - dpaa2_switch_destroy_rings(ethsw); -err_drain_dpbp: - dpaa2_switch_drain_bp(ethsw); -err_free_dpbp: - dpaa2_switch_free_dpbp(ethsw); - - return err; -} - -static int dpaa2_switch_init(struct fsl_mc_device *sw_dev) -{ - struct device *dev = &sw_dev->dev; - struct ethsw_core *ethsw = dev_get_drvdata(dev); - struct dpsw_vlan_if_cfg vcfg = {0}; - struct dpsw_tci_cfg tci_cfg = {0}; - struct dpsw_stp_cfg stp_cfg; - int err; - u16 i; - - ethsw->dev_id = sw_dev->obj_desc.id; - - err = dpsw_open(ethsw->mc_io, 0, ethsw->dev_id, ðsw->dpsw_handle); - if (err) { - dev_err(dev, "dpsw_open err %d\n", err); - return err; - } - - err = dpsw_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle, - ðsw->sw_attr); - if (err) { - dev_err(dev, "dpsw_get_attributes err %d\n", err); - goto err_close; - } - - err = dpsw_get_api_version(ethsw->mc_io, 0, - ðsw->major, - ðsw->minor); - if (err) { - dev_err(dev, "dpsw_get_api_version err %d\n", err); - goto err_close; - } - - /* Minimum supported DPSW version check */ - if (ethsw->major < DPSW_MIN_VER_MAJOR || - (ethsw->major == DPSW_MIN_VER_MAJOR && - ethsw->minor < DPSW_MIN_VER_MINOR)) { - dev_err(dev, "DPSW version %d:%d not supported. Use firmware 10.28.0 or greater.\n", - ethsw->major, ethsw->minor); - err = -EOPNOTSUPP; - goto err_close; - } - - if (!dpaa2_switch_supports_cpu_traffic(ethsw)) { - err = -EOPNOTSUPP; - goto err_close; - } - - dpaa2_switch_detect_features(ethsw); - - err = dpsw_reset(ethsw->mc_io, 0, ethsw->dpsw_handle); - if (err) { - dev_err(dev, "dpsw_reset err %d\n", err); - goto err_close; - } - - stp_cfg.vlan_id = DEFAULT_VLAN_ID; - stp_cfg.state = DPSW_STP_STATE_FORWARDING; - - for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { - err = dpsw_if_disable(ethsw->mc_io, 0, ethsw->dpsw_handle, i); - if (err) { - dev_err(dev, "dpsw_if_disable err %d\n", err); - goto err_close; - } - - err = dpsw_if_set_stp(ethsw->mc_io, 0, ethsw->dpsw_handle, i, - &stp_cfg); - if (err) { - dev_err(dev, "dpsw_if_set_stp err %d for port %d\n", - err, i); - goto err_close; - } - - /* Switch starts with all ports configured to VLAN 1. Need to - * remove this setting to allow configuration at bridge join - */ - vcfg.num_ifs = 1; - vcfg.if_id[0] = i; - err = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0, ethsw->dpsw_handle, - DEFAULT_VLAN_ID, &vcfg); - if (err) { - dev_err(dev, "dpsw_vlan_remove_if_untagged err %d\n", - err); - goto err_close; - } - - tci_cfg.vlan_id = 4095; - err = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle, i, &tci_cfg); - if (err) { - dev_err(dev, "dpsw_if_set_tci err %d\n", err); - goto err_close; - } - - err = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle, - DEFAULT_VLAN_ID, &vcfg); - if (err) { - dev_err(dev, "dpsw_vlan_remove_if err %d\n", err); - goto err_close; - } - } - - err = dpsw_vlan_remove(ethsw->mc_io, 0, ethsw->dpsw_handle, DEFAULT_VLAN_ID); - if (err) { - dev_err(dev, "dpsw_vlan_remove err %d\n", err); - goto err_close; - } - - ethsw->workqueue = alloc_ordered_workqueue("%s_%d_ordered", - WQ_MEM_RECLAIM, "ethsw", - ethsw->sw_attr.id); - if (!ethsw->workqueue) { - err = -ENOMEM; - goto err_close; - } - - err = dpsw_fdb_remove(ethsw->mc_io, 0, ethsw->dpsw_handle, 0); - if (err) - goto err_destroy_ordered_workqueue; - - err = dpaa2_switch_ctrl_if_setup(ethsw); - if (err) - goto err_destroy_ordered_workqueue; - - return 0; - -err_destroy_ordered_workqueue: - destroy_workqueue(ethsw->workqueue); - -err_close: - dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle); - return err; -} - -static int dpaa2_switch_port_init(struct ethsw_port_priv *port_priv, u16 port) -{ - struct switchdev_obj_port_vlan vlan = { - .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, - .vid = DEFAULT_VLAN_ID, - .flags = BRIDGE_VLAN_INFO_UNTAGGED | BRIDGE_VLAN_INFO_PVID, - }; - struct net_device *netdev = port_priv->netdev; - struct ethsw_core *ethsw = port_priv->ethsw_data; - struct dpsw_fdb_cfg fdb_cfg = {0}; - struct dpaa2_switch_fdb *fdb; - struct dpsw_if_attr dpsw_if_attr; - u16 fdb_id; - int err; - - /* Get the Tx queue for this specific port */ - err = dpsw_if_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle, - port_priv->idx, &dpsw_if_attr); - if (err) { - netdev_err(netdev, "dpsw_if_get_attributes err %d\n", err); - return err; - } - port_priv->tx_qdid = dpsw_if_attr.qdid; - - /* Create a FDB table for this particular switch port */ - fdb_cfg.num_fdb_entries = ethsw->sw_attr.max_fdb_entries / ethsw->sw_attr.num_ifs; - err = dpsw_fdb_add(ethsw->mc_io, 0, ethsw->dpsw_handle, - &fdb_id, &fdb_cfg); - if (err) { - netdev_err(netdev, "dpsw_fdb_add err %d\n", err); - return err; - } - - /* Find an unused dpaa2_switch_fdb structure and use it */ - fdb = dpaa2_switch_fdb_get_unused(ethsw); - fdb->fdb_id = fdb_id; - fdb->in_use = true; - fdb->bridge_dev = NULL; - port_priv->fdb = fdb; - - /* We need to add VLAN 1 as the PVID on this port until it is under a - * bridge since the DPAA2 switch is not able to handle the traffic in a - * VLAN unaware fashion - */ - err = dpaa2_switch_port_vlans_add(netdev, &vlan); - if (err) - return err; - - /* Setup the egress flooding domains (broadcast, unknown unicast */ - err = dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id); - if (err) - return err; - - return err; -} - -static void dpaa2_switch_takedown(struct fsl_mc_device *sw_dev) -{ - struct device *dev = &sw_dev->dev; - struct ethsw_core *ethsw = dev_get_drvdata(dev); - int err; - - err = dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle); - if (err) - dev_warn(dev, "dpsw_close err %d\n", err); -} - -static void dpaa2_switch_ctrl_if_teardown(struct ethsw_core *ethsw) -{ - dpsw_ctrl_if_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); - dpaa2_switch_free_dpio(ethsw); - dpaa2_switch_destroy_rings(ethsw); - dpaa2_switch_drain_bp(ethsw); - dpaa2_switch_free_dpbp(ethsw); -} - -static int dpaa2_switch_remove(struct fsl_mc_device *sw_dev) -{ - struct ethsw_port_priv *port_priv; - struct ethsw_core *ethsw; - struct device *dev; - int i; - - dev = &sw_dev->dev; - ethsw = dev_get_drvdata(dev); - - dpaa2_switch_ctrl_if_teardown(ethsw); - - dpaa2_switch_teardown_irqs(sw_dev); - - dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); - - for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { - port_priv = ethsw->ports[i]; - unregister_netdev(port_priv->netdev); - free_netdev(port_priv->netdev); - } - - kfree(ethsw->fdbs); - kfree(ethsw->ports); - - dpaa2_switch_takedown(sw_dev); - - destroy_workqueue(ethsw->workqueue); - - fsl_mc_portal_free(ethsw->mc_io); - - kfree(ethsw); - - dev_set_drvdata(dev, NULL); - - return 0; -} - -static int dpaa2_switch_probe_port(struct ethsw_core *ethsw, - u16 port_idx) -{ - struct ethsw_port_priv *port_priv; - struct device *dev = ethsw->dev; - struct net_device *port_netdev; - int err; - - port_netdev = alloc_etherdev(sizeof(struct ethsw_port_priv)); - if (!port_netdev) { - dev_err(dev, "alloc_etherdev error\n"); - return -ENOMEM; - } - - port_priv = netdev_priv(port_netdev); - port_priv->netdev = port_netdev; - port_priv->ethsw_data = ethsw; - - port_priv->idx = port_idx; - port_priv->stp_state = BR_STATE_FORWARDING; - - SET_NETDEV_DEV(port_netdev, dev); - port_netdev->netdev_ops = &dpaa2_switch_port_ops; - port_netdev->ethtool_ops = &dpaa2_switch_port_ethtool_ops; - - port_netdev->needed_headroom = DPAA2_SWITCH_NEEDED_HEADROOM; - - /* Set MTU limits */ - port_netdev->min_mtu = ETH_MIN_MTU; - port_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH; - - /* Populate the private port structure so that later calls to - * dpaa2_switch_port_init() can use it. - */ - ethsw->ports[port_idx] = port_priv; - - /* The DPAA2 switch's ingress path depends on the VLAN table, - * thus we are not able to disable VLAN filtering. - */ - port_netdev->features = NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER; - - err = dpaa2_switch_port_init(port_priv, port_idx); - if (err) - goto err_port_probe; - - err = dpaa2_switch_port_set_mac_addr(port_priv); - if (err) - goto err_port_probe; - - return 0; - -err_port_probe: - free_netdev(port_netdev); - ethsw->ports[port_idx] = NULL; - - return err; -} - -static int dpaa2_switch_probe(struct fsl_mc_device *sw_dev) -{ - struct device *dev = &sw_dev->dev; - struct ethsw_core *ethsw; - int i, err; - - /* Allocate switch core*/ - ethsw = kzalloc(sizeof(*ethsw), GFP_KERNEL); - - if (!ethsw) - return -ENOMEM; - - ethsw->dev = dev; - ethsw->iommu_domain = iommu_get_domain_for_dev(dev); - dev_set_drvdata(dev, ethsw); - - err = fsl_mc_portal_allocate(sw_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, - ðsw->mc_io); - if (err) { - if (err == -ENXIO) - err = -EPROBE_DEFER; - else - dev_err(dev, "fsl_mc_portal_allocate err %d\n", err); - goto err_free_drvdata; - } - - err = dpaa2_switch_init(sw_dev); - if (err) - goto err_free_cmdport; - - ethsw->ports = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->ports), - GFP_KERNEL); - if (!(ethsw->ports)) { - err = -ENOMEM; - goto err_takedown; - } - - ethsw->fdbs = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->fdbs), - GFP_KERNEL); - if (!ethsw->fdbs) { - err = -ENOMEM; - goto err_free_ports; - } - - for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { - err = dpaa2_switch_probe_port(ethsw, i); - if (err) - goto err_free_netdev; - } - - /* Add a NAPI instance for each of the Rx queues. The first port's - * net_device will be associated with the instances since we do not have - * different queues for each switch ports. - */ - for (i = 0; i < DPAA2_SWITCH_RX_NUM_FQS; i++) - netif_napi_add(ethsw->ports[0]->netdev, - ðsw->fq[i].napi, dpaa2_switch_poll, - NAPI_POLL_WEIGHT); - - err = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle); - if (err) { - dev_err(ethsw->dev, "dpsw_enable err %d\n", err); - goto err_free_netdev; - } - - /* Setup IRQs */ - err = dpaa2_switch_setup_irqs(sw_dev); - if (err) - goto err_stop; - - /* Register the netdev only when the entire setup is done and the - * switch port interfaces are ready to receive traffic - */ - for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { - err = register_netdev(ethsw->ports[i]->netdev); - if (err < 0) { - dev_err(dev, "register_netdev error %d\n", err); - goto err_unregister_ports; - } - } - - return 0; - -err_unregister_ports: - for (i--; i >= 0; i--) - unregister_netdev(ethsw->ports[i]->netdev); - dpaa2_switch_teardown_irqs(sw_dev); -err_stop: - dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); -err_free_netdev: - for (i--; i >= 0; i--) - free_netdev(ethsw->ports[i]->netdev); - kfree(ethsw->fdbs); -err_free_ports: - kfree(ethsw->ports); - -err_takedown: - dpaa2_switch_takedown(sw_dev); - -err_free_cmdport: - fsl_mc_portal_free(ethsw->mc_io); - -err_free_drvdata: - kfree(ethsw); - dev_set_drvdata(dev, NULL); - - return err; -} - -static const struct fsl_mc_device_id dpaa2_switch_match_id_table[] = { - { - .vendor = FSL_MC_VENDOR_FREESCALE, - .obj_type = "dpsw", - }, - { .vendor = 0x0 } -}; -MODULE_DEVICE_TABLE(fslmc, dpaa2_switch_match_id_table); - -static struct fsl_mc_driver dpaa2_switch_drv = { - .driver = { - .name = KBUILD_MODNAME, - .owner = THIS_MODULE, - }, - .probe = dpaa2_switch_probe, - .remove = dpaa2_switch_remove, - .match_id_table = dpaa2_switch_match_id_table -}; - -static struct notifier_block dpaa2_switch_port_nb __read_mostly = { - .notifier_call = dpaa2_switch_port_netdevice_event, -}; - -static struct notifier_block dpaa2_switch_port_switchdev_nb = { - .notifier_call = dpaa2_switch_port_event, -}; - -static struct notifier_block dpaa2_switch_port_switchdev_blocking_nb = { - .notifier_call = dpaa2_switch_port_blocking_event, -}; - -static int dpaa2_switch_register_notifiers(void) -{ - int err; - - err = register_netdevice_notifier(&dpaa2_switch_port_nb); - if (err) { - pr_err("dpaa2-switch: failed to register net_device notifier (%d)\n", err); - return err; - } - - err = register_switchdev_notifier(&dpaa2_switch_port_switchdev_nb); - if (err) { - pr_err("dpaa2-switch: failed to register switchdev notifier (%d)\n", err); - goto err_switchdev_nb; - } - - err = register_switchdev_blocking_notifier(&dpaa2_switch_port_switchdev_blocking_nb); - if (err) { - pr_err("dpaa2-switch: failed to register switchdev blocking notifier (%d)\n", err); - goto err_switchdev_blocking_nb; - } - - return 0; - -err_switchdev_blocking_nb: - unregister_switchdev_notifier(&dpaa2_switch_port_switchdev_nb); -err_switchdev_nb: - unregister_netdevice_notifier(&dpaa2_switch_port_nb); - - return err; -} - -static void dpaa2_switch_unregister_notifiers(void) -{ - int err; - - err = unregister_switchdev_blocking_notifier(&dpaa2_switch_port_switchdev_blocking_nb); - if (err) - pr_err("dpaa2-switch: failed to unregister switchdev blocking notifier (%d)\n", - err); - - err = unregister_switchdev_notifier(&dpaa2_switch_port_switchdev_nb); - if (err) - pr_err("dpaa2-switch: failed to unregister switchdev notifier (%d)\n", err); - - err = unregister_netdevice_notifier(&dpaa2_switch_port_nb); - if (err) - pr_err("dpaa2-switch: failed to unregister net_device notifier (%d)\n", err); -} - -static int __init dpaa2_switch_driver_init(void) -{ - int err; - - err = fsl_mc_driver_register(&dpaa2_switch_drv); - if (err) - return err; - - err = dpaa2_switch_register_notifiers(); - if (err) { - fsl_mc_driver_unregister(&dpaa2_switch_drv); - return err; - } - - return 0; -} - -static void __exit dpaa2_switch_driver_exit(void) -{ - dpaa2_switch_unregister_notifiers(); - fsl_mc_driver_unregister(&dpaa2_switch_drv); -} - -module_init(dpaa2_switch_driver_init); -module_exit(dpaa2_switch_driver_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("DPAA2 Ethernet Switch Driver"); diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h deleted file mode 100644 index 933563064015..000000000000 --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h +++ /dev/null @@ -1,178 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * DPAA2 Ethernet Switch declarations - * - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2017-2021 NXP - * - */ - -#ifndef __ETHSW_H -#define __ETHSW_H - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/rtnetlink.h> -#include <linux/if_vlan.h> -#include <uapi/linux/if_bridge.h> -#include <net/switchdev.h> -#include <linux/if_bridge.h> -#include <linux/fsl/mc.h> -#include <soc/fsl/dpaa2-io.h> - -#include "dpsw.h" - -/* Number of IRQs supported */ -#define DPSW_IRQ_NUM 2 - -/* Port is member of VLAN */ -#define ETHSW_VLAN_MEMBER 1 -/* VLAN to be treated as untagged on egress */ -#define ETHSW_VLAN_UNTAGGED 2 -/* Untagged frames will be assigned to this VLAN */ -#define ETHSW_VLAN_PVID 4 -/* VLAN configured on the switch */ -#define ETHSW_VLAN_GLOBAL 8 - -/* Maximum Frame Length supported by HW (currently 10k) */ -#define DPAA2_MFL (10 * 1024) -#define ETHSW_MAX_FRAME_LENGTH (DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN) -#define ETHSW_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN) - -#define ETHSW_FEATURE_MAC_ADDR BIT(0) - -/* Number of receive queues (one RX and one TX_CONF) */ -#define DPAA2_SWITCH_RX_NUM_FQS 2 - -/* Hardware requires alignment for ingress/egress buffer addresses */ -#define DPAA2_SWITCH_RX_BUF_RAW_SIZE PAGE_SIZE -#define DPAA2_SWITCH_RX_BUF_TAILROOM \ - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) -#define DPAA2_SWITCH_RX_BUF_SIZE \ - (DPAA2_SWITCH_RX_BUF_RAW_SIZE - DPAA2_SWITCH_RX_BUF_TAILROOM) - -#define DPAA2_SWITCH_STORE_SIZE 16 - -/* Buffer management */ -#define BUFS_PER_CMD 7 -#define DPAA2_ETHSW_NUM_BUFS (1024 * BUFS_PER_CMD) -#define DPAA2_ETHSW_REFILL_THRESH (DPAA2_ETHSW_NUM_BUFS * 5 / 6) - -/* Number of times to retry DPIO portal operations while waiting - * for portal to finish executing current command and become - * available. We want to avoid being stuck in a while loop in case - * hardware becomes unresponsive, but not give up too easily if - * the portal really is busy for valid reasons - */ -#define DPAA2_SWITCH_SWP_BUSY_RETRIES 1000 - -/* Hardware annotation buffer size */ -#define DPAA2_SWITCH_HWA_SIZE 64 -/* Software annotation buffer size */ -#define DPAA2_SWITCH_SWA_SIZE 64 - -#define DPAA2_SWITCH_TX_BUF_ALIGN 64 - -#define DPAA2_SWITCH_TX_DATA_OFFSET \ - (DPAA2_SWITCH_HWA_SIZE + DPAA2_SWITCH_SWA_SIZE) - -#define DPAA2_SWITCH_NEEDED_HEADROOM \ - (DPAA2_SWITCH_TX_DATA_OFFSET + DPAA2_SWITCH_TX_BUF_ALIGN) - -extern const struct ethtool_ops dpaa2_switch_port_ethtool_ops; - -struct ethsw_core; - -struct dpaa2_switch_fq { - struct ethsw_core *ethsw; - enum dpsw_queue_type type; - struct dpaa2_io_store *store; - struct dpaa2_io_notification_ctx nctx; - struct napi_struct napi; - u32 fqid; -}; - -struct dpaa2_switch_fdb { - struct net_device *bridge_dev; - u16 fdb_id; - bool in_use; -}; - -/* Per port private data */ -struct ethsw_port_priv { - struct net_device *netdev; - u16 idx; - struct ethsw_core *ethsw_data; - u8 link_state; - u8 stp_state; - bool flood; - - u8 vlans[VLAN_VID_MASK + 1]; - u16 pvid; - u16 tx_qdid; - - struct dpaa2_switch_fdb *fdb; -}; - -/* Switch data */ -struct ethsw_core { - struct device *dev; - struct fsl_mc_io *mc_io; - u16 dpsw_handle; - struct dpsw_attr sw_attr; - u16 major, minor; - unsigned long features; - int dev_id; - struct ethsw_port_priv **ports; - struct iommu_domain *iommu_domain; - - u8 vlans[VLAN_VID_MASK + 1]; - - struct workqueue_struct *workqueue; - - struct dpaa2_switch_fq fq[DPAA2_SWITCH_RX_NUM_FQS]; - struct fsl_mc_device *dpbp_dev; - int buf_count; - u16 bpid; - int napi_users; - - struct dpaa2_switch_fdb *fdbs; -}; - -static inline bool dpaa2_switch_supports_cpu_traffic(struct ethsw_core *ethsw) -{ - if (ethsw->sw_attr.options & DPSW_OPT_CTRL_IF_DIS) { - dev_err(ethsw->dev, "Control Interface is disabled, cannot probe\n"); - return false; - } - - if (ethsw->sw_attr.flooding_cfg != DPSW_FLOODING_PER_FDB) { - dev_err(ethsw->dev, "Flooding domain is not per FDB, cannot probe\n"); - return false; - } - - if (ethsw->sw_attr.broadcast_cfg != DPSW_BROADCAST_PER_FDB) { - dev_err(ethsw->dev, "Broadcast domain is not per FDB, cannot probe\n"); - return false; - } - - if (ethsw->sw_attr.max_fdbs < ethsw->sw_attr.num_ifs) { - dev_err(ethsw->dev, "The number of FDBs is lower than the number of ports, cannot probe\n"); - return false; - } - - return true; -} - -bool dpaa2_switch_port_dev_check(const struct net_device *netdev); - -int dpaa2_switch_port_vlans_add(struct net_device *netdev, - const struct switchdev_obj_port_vlan *vlan); - -int dpaa2_switch_port_vlans_del(struct net_device *netdev, - const struct switchdev_obj_port_vlan *vlan); - -typedef int dpaa2_switch_fdb_cb_t(struct ethsw_port_priv *port_priv, - struct fdb_dump_entry *fdb_entry, - void *data); -#endif /* __ETHSW_H */ |