Commit d624e158 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-router-interfaces-groundwork'

Jiri Pirko says:

====================
mlxsw: Lay the groundwork for the introduction of router interfaces

This is first patchset on a way to introduce ipv4 routing offload support
in mlxsw driver. Does preparations before router interfaces will
be introduced in mlxsw.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cec88ea3 7b27ce7b
...@@ -7,5 +7,5 @@ obj-$(CONFIG_MLXSW_SWITCHX2) += mlxsw_switchx2.o ...@@ -7,5 +7,5 @@ obj-$(CONFIG_MLXSW_SWITCHX2) += mlxsw_switchx2.o
mlxsw_switchx2-objs := switchx2.o mlxsw_switchx2-objs := switchx2.o
obj-$(CONFIG_MLXSW_SPECTRUM) += mlxsw_spectrum.o obj-$(CONFIG_MLXSW_SPECTRUM) += mlxsw_spectrum.o
mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_switchdev.o spectrum_switchdev.o spectrum_router.o
mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o
/* /*
* drivers/net/ethernet/mellanox/mlxsw/reg.h * drivers/net/ethernet/mellanox/mlxsw/reg.h
* Copyright (c) 2015 Mellanox Technologies. All rights reserved. * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
* Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com> * Copyright (c) 2015-2016 Ido Schimmel <idosch@mellanox.com>
* Copyright (c) 2015 Elad Raz <eladr@mellanox.com> * Copyright (c) 2015 Elad Raz <eladr@mellanox.com>
* Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com> * Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
* *
...@@ -386,7 +386,9 @@ enum mlxsw_reg_sfd_rec_action { ...@@ -386,7 +386,9 @@ enum mlxsw_reg_sfd_rec_action {
/* forward and trap, trap_id is FDB_TRAP */ /* forward and trap, trap_id is FDB_TRAP */
MLXSW_REG_SFD_REC_ACTION_MIRROR_TO_CPU = 1, MLXSW_REG_SFD_REC_ACTION_MIRROR_TO_CPU = 1,
/* trap and do not forward, trap_id is FDB_TRAP */ /* trap and do not forward, trap_id is FDB_TRAP */
MLXSW_REG_SFD_REC_ACTION_TRAP = 3, MLXSW_REG_SFD_REC_ACTION_TRAP = 2,
/* forward to IP router */
MLXSW_REG_SFD_REC_ACTION_FORWARD_IP_ROUTER = 3,
MLXSW_REG_SFD_REC_ACTION_DISCARD_ERROR = 15, MLXSW_REG_SFD_REC_ACTION_DISCARD_ERROR = 15,
}; };
...@@ -3186,6 +3188,272 @@ static inline void mlxsw_reg_hpkt_pack(char *payload, u8 action, u16 trap_id) ...@@ -3186,6 +3188,272 @@ static inline void mlxsw_reg_hpkt_pack(char *payload, u8 action, u16 trap_id)
mlxsw_reg_hpkt_ctrl_set(payload, MLXSW_REG_HPKT_CTRL_PACKET_DEFAULT); mlxsw_reg_hpkt_ctrl_set(payload, MLXSW_REG_HPKT_CTRL_PACKET_DEFAULT);
} }
/* RGCR - Router General Configuration Register
* --------------------------------------------
* The register is used for setting up the router configuration.
*/
#define MLXSW_REG_RGCR_ID 0x8001
#define MLXSW_REG_RGCR_LEN 0x28
static const struct mlxsw_reg_info mlxsw_reg_rgcr = {
.id = MLXSW_REG_RGCR_ID,
.len = MLXSW_REG_RGCR_LEN,
};
/* reg_rgcr_ipv4_en
* IPv4 router enable.
* Access: RW
*/
MLXSW_ITEM32(reg, rgcr, ipv4_en, 0x00, 31, 1);
/* reg_rgcr_ipv6_en
* IPv6 router enable.
* Access: RW
*/
MLXSW_ITEM32(reg, rgcr, ipv6_en, 0x00, 30, 1);
/* reg_rgcr_max_router_interfaces
* Defines the maximum number of active router interfaces for all virtual
* routers.
* Access: RW
*/
MLXSW_ITEM32(reg, rgcr, max_router_interfaces, 0x10, 0, 16);
/* reg_rgcr_usp
* Update switch priority and packet color.
* 0 - Preserve the value of Switch Priority and packet color.
* 1 - Recalculate the value of Switch Priority and packet color.
* Access: RW
*
* Note: Not supported by SwitchX and SwitchX-2.
*/
MLXSW_ITEM32(reg, rgcr, usp, 0x18, 20, 1);
/* reg_rgcr_pcp_rw
* Indicates how to handle the pcp_rewrite_en value:
* 0 - Preserve the value of pcp_rewrite_en.
* 2 - Disable PCP rewrite.
* 3 - Enable PCP rewrite.
* Access: RW
*
* Note: Not supported by SwitchX and SwitchX-2.
*/
MLXSW_ITEM32(reg, rgcr, pcp_rw, 0x18, 16, 2);
/* reg_rgcr_activity_dis
* Activity disable:
* 0 - Activity will be set when an entry is hit (default).
* 1 - Activity will not be set when an entry is hit.
*
* Bit 0 - Disable activity bit in Router Algorithmic LPM Unicast Entry
* (RALUE).
* Bit 1 - Disable activity bit in Router Algorithmic LPM Unicast Host
* Entry (RAUHT).
* Bits 2:7 are reserved.
* Access: RW
*
* Note: Not supported by SwitchX, SwitchX-2 and Switch-IB.
*/
MLXSW_ITEM32(reg, rgcr, activity_dis, 0x20, 0, 8);
static inline void mlxsw_reg_rgcr_pack(char *payload, bool ipv4_en)
{
MLXSW_REG_ZERO(rgcr, payload);
mlxsw_reg_rgcr_ipv4_en_set(payload, ipv4_en);
}
/* RITR - Router Interface Table Register
* --------------------------------------
* The register is used to configure the router interface table.
*/
#define MLXSW_REG_RITR_ID 0x8002
#define MLXSW_REG_RITR_LEN 0x40
static const struct mlxsw_reg_info mlxsw_reg_ritr = {
.id = MLXSW_REG_RITR_ID,
.len = MLXSW_REG_RITR_LEN,
};
/* reg_ritr_enable
* Enables routing on the router interface.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, enable, 0x00, 31, 1);
/* reg_ritr_ipv4
* IPv4 routing enable. Enables routing of IPv4 traffic on the router
* interface.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, ipv4, 0x00, 29, 1);
/* reg_ritr_ipv6
* IPv6 routing enable. Enables routing of IPv6 traffic on the router
* interface.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, ipv6, 0x00, 28, 1);
enum mlxsw_reg_ritr_if_type {
MLXSW_REG_RITR_VLAN_IF,
MLXSW_REG_RITR_FID_IF,
MLXSW_REG_RITR_SP_IF,
};
/* reg_ritr_type
* Router interface type.
* 0 - VLAN interface.
* 1 - FID interface.
* 2 - Sub-port interface.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, type, 0x00, 23, 3);
enum {
MLXSW_REG_RITR_RIF_CREATE,
MLXSW_REG_RITR_RIF_DEL,
};
/* reg_ritr_op
* Opcode:
* 0 - Create or edit RIF.
* 1 - Delete RIF.
* Reserved for SwitchX-2. For Spectrum, editing of interface properties
* is not supported. An interface must be deleted and re-created in order
* to update properties.
* Access: WO
*/
MLXSW_ITEM32(reg, ritr, op, 0x00, 20, 2);
/* reg_ritr_rif
* Router interface index. A pointer to the Router Interface Table.
* Access: Index
*/
MLXSW_ITEM32(reg, ritr, rif, 0x00, 0, 16);
/* reg_ritr_ipv4_fe
* IPv4 Forwarding Enable.
* Enables routing of IPv4 traffic on the router interface. When disabled,
* forwarding is blocked but local traffic (traps and IP2ME) will be enabled.
* Not supported in SwitchX-2.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, ipv4_fe, 0x04, 29, 1);
/* reg_ritr_ipv6_fe
* IPv6 Forwarding Enable.
* Enables routing of IPv6 traffic on the router interface. When disabled,
* forwarding is blocked but local traffic (traps and IP2ME) will be enabled.
* Not supported in SwitchX-2.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, ipv6_fe, 0x04, 28, 1);
/* reg_ritr_virtual_router
* Virtual router ID associated with the router interface.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, virtual_router, 0x04, 0, 16);
/* reg_ritr_mtu
* Router interface MTU.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, mtu, 0x34, 0, 16);
/* reg_ritr_if_swid
* Switch partition ID.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, if_swid, 0x08, 24, 8);
/* reg_ritr_if_mac
* Router interface MAC address.
* In Spectrum, all MAC addresses must have the same 38 MSBits.
* Access: RW
*/
MLXSW_ITEM_BUF(reg, ritr, if_mac, 0x12, 6);
/* VLAN Interface */
/* reg_ritr_vlan_if_vid
* VLAN ID.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, vlan_if_vid, 0x08, 0, 12);
/* FID Interface */
/* reg_ritr_fid_if_fid
* Filtering ID. Used to connect a bridge to the router. Only FIDs from
* the vFID range are supported.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, fid_if_fid, 0x08, 0, 16);
static inline void mlxsw_reg_ritr_fid_set(char *payload,
enum mlxsw_reg_ritr_if_type rif_type,
u16 fid)
{
if (rif_type == MLXSW_REG_RITR_FID_IF)
mlxsw_reg_ritr_fid_if_fid_set(payload, fid);
else
mlxsw_reg_ritr_vlan_if_vid_set(payload, fid);
}
/* Sub-port Interface */
/* reg_ritr_sp_if_lag
* LAG indication. When this bit is set the system_port field holds the
* LAG identifier.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, sp_if_lag, 0x08, 24, 1);
/* reg_ritr_sp_system_port
* Port unique indentifier. When lag bit is set, this field holds the
* lag_id in bits 0:9.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, sp_if_system_port, 0x08, 0, 16);
/* reg_ritr_sp_if_vid
* VLAN ID.
* Access: RW
*/
MLXSW_ITEM32(reg, ritr, sp_if_vid, 0x18, 0, 12);
static inline void mlxsw_reg_ritr_rif_pack(char *payload, u16 rif)
{
MLXSW_REG_ZERO(ritr, payload);
mlxsw_reg_ritr_rif_set(payload, rif);
}
static inline void mlxsw_reg_ritr_sp_if_pack(char *payload, bool lag,
u16 system_port, u16 vid)
{
mlxsw_reg_ritr_sp_if_lag_set(payload, lag);
mlxsw_reg_ritr_sp_if_system_port_set(payload, system_port);
mlxsw_reg_ritr_sp_if_vid_set(payload, vid);
}
static inline void mlxsw_reg_ritr_pack(char *payload, bool enable,
enum mlxsw_reg_ritr_if_type type,
u16 rif, u16 mtu, const char *mac)
{
bool op = enable ? MLXSW_REG_RITR_RIF_CREATE : MLXSW_REG_RITR_RIF_DEL;
MLXSW_REG_ZERO(ritr, payload);
mlxsw_reg_ritr_enable_set(payload, enable);
mlxsw_reg_ritr_ipv4_set(payload, 1);
mlxsw_reg_ritr_type_set(payload, type);
mlxsw_reg_ritr_op_set(payload, op);
mlxsw_reg_ritr_rif_set(payload, rif);
mlxsw_reg_ritr_ipv4_fe_set(payload, 1);
mlxsw_reg_ritr_mtu_set(payload, mtu);
mlxsw_reg_ritr_if_mac_memcpy_to(payload, mac);
}
/* MFCR - Management Fan Control Register /* MFCR - Management Fan Control Register
* -------------------------------------- * --------------------------------------
* This register controls the settings of the Fan Speed PWM mechanism. * This register controls the settings of the Fan Speed PWM mechanism.
...@@ -3924,6 +4192,10 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id) ...@@ -3924,6 +4192,10 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id)
return "HTGT"; return "HTGT";
case MLXSW_REG_HPKT_ID: case MLXSW_REG_HPKT_ID:
return "HPKT"; return "HPKT";
case MLXSW_REG_RGCR_ID:
return "RGCR";
case MLXSW_REG_RITR_ID:
return "RITR";
case MLXSW_REG_MFCR_ID: case MLXSW_REG_MFCR_ID:
return "MFCR"; return "MFCR";
case MLXSW_REG_MFSC_ID: case MLXSW_REG_MFSC_ID:
......
...@@ -816,6 +816,7 @@ int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto, ...@@ -816,6 +816,7 @@ int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto,
{ {
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
struct mlxsw_sp_port *mlxsw_sp_vport; struct mlxsw_sp_port *mlxsw_sp_vport;
bool untagged = vid == 1;
int err; int err;
/* VLAN 0 is added to HW filter when device goes up, but it is /* VLAN 0 is added to HW filter when device goes up, but it is
...@@ -859,7 +860,7 @@ int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto, ...@@ -859,7 +860,7 @@ int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto,
goto err_port_vid_learning_set; goto err_port_vid_learning_set;
} }
err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, false); err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged);
if (err) { if (err) {
netdev_err(dev, "Failed to set VLAN membership for VID=%d\n", netdev_err(dev, "Failed to set VLAN membership for VID=%d\n",
vid); vid);
...@@ -889,7 +890,7 @@ int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto, ...@@ -889,7 +890,7 @@ int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto,
return err; return err;
} }
int mlxsw_sp_port_kill_vid(struct net_device *dev, static int mlxsw_sp_port_kill_vid(struct net_device *dev,
__be16 __always_unused proto, u16 vid) __be16 __always_unused proto, u16 vid)
{ {
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
...@@ -1844,23 +1845,6 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, ...@@ -1844,23 +1845,6 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
return err; return err;
} }
static void mlxsw_sp_port_vports_fini(struct mlxsw_sp_port *mlxsw_sp_port)
{
struct net_device *dev = mlxsw_sp_port->dev;
struct mlxsw_sp_port *mlxsw_sp_vport, *tmp;
list_for_each_entry_safe(mlxsw_sp_vport, tmp,
&mlxsw_sp_port->vports_list, vport.list) {
u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
/* vPorts created for VLAN devices should already be gone
* by now, since we unregistered the port netdev.
*/
WARN_ON(is_vlan_dev(mlxsw_sp_vport->dev));
mlxsw_sp_port_kill_vid(dev, 0, vid);
}
}
static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
{ {
struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port]; struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
...@@ -1871,13 +1855,14 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) ...@@ -1871,13 +1855,14 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
mlxsw_core_port_fini(&mlxsw_sp_port->core_port); mlxsw_core_port_fini(&mlxsw_sp_port->core_port);
unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */ unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */
mlxsw_sp_port_dcb_fini(mlxsw_sp_port); mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
mlxsw_sp_port_vports_fini(mlxsw_sp_port); mlxsw_sp_port_kill_vid(mlxsw_sp_port->dev, 0, 1);
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port); mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port);
free_percpu(mlxsw_sp_port->pcpu_stats); free_percpu(mlxsw_sp_port->pcpu_stats);
kfree(mlxsw_sp_port->untagged_vlans); kfree(mlxsw_sp_port->untagged_vlans);
kfree(mlxsw_sp_port->active_vlans); kfree(mlxsw_sp_port->active_vlans);
WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vports_list));
free_netdev(mlxsw_sp_port->dev); free_netdev(mlxsw_sp_port->dev);
} }
...@@ -2114,11 +2099,8 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg, ...@@ -2114,11 +2099,8 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
local_port = mlxsw_reg_pude_local_port_get(pude_pl); local_port = mlxsw_reg_pude_local_port_get(pude_pl);
mlxsw_sp_port = mlxsw_sp->ports[local_port]; mlxsw_sp_port = mlxsw_sp->ports[local_port];
if (!mlxsw_sp_port) { if (!mlxsw_sp_port)
dev_warn(mlxsw_sp->bus_info->dev, "Port %d: Link event received for non-existent port\n",
local_port);
return; return;
}
status = mlxsw_reg_pude_oper_status_get(pude_pl); status = mlxsw_reg_pude_oper_status_get(pude_pl);
if (status == MLXSW_PORT_OPER_STATUS_UP) { if (status == MLXSW_PORT_OPER_STATUS_UP) {
...@@ -2273,6 +2255,31 @@ static const struct mlxsw_rx_listener mlxsw_sp_rx_listener[] = { ...@@ -2273,6 +2255,31 @@ static const struct mlxsw_rx_listener mlxsw_sp_rx_listener[] = {
.local_port = MLXSW_PORT_DONT_CARE, .local_port = MLXSW_PORT_DONT_CARE,
.trap_id = MLXSW_TRAP_ID_IGMP_V3_REPORT, .trap_id = MLXSW_TRAP_ID_IGMP_V3_REPORT,
}, },
{
.func = mlxsw_sp_rx_listener_func,
.local_port = MLXSW_PORT_DONT_CARE,
.trap_id = MLXSW_TRAP_ID_ARPBC,
},
{
.func = mlxsw_sp_rx_listener_func,
.local_port = MLXSW_PORT_DONT_CARE,
.trap_id = MLXSW_TRAP_ID_ARPUC,
},
{
.func = mlxsw_sp_rx_listener_func,
.local_port = MLXSW_PORT_DONT_CARE,
.trap_id = MLXSW_TRAP_ID_IP2ME,
},
{
.func = mlxsw_sp_rx_listener_func,
.local_port = MLXSW_PORT_DONT_CARE,
.trap_id = MLXSW_TRAP_ID_RTR_INGRESS0,
},
{
.func = mlxsw_sp_rx_listener_func,
.local_port = MLXSW_PORT_DONT_CARE,
.trap_id = MLXSW_TRAP_ID_HOST_MISS_IPV4,
},
}; };
static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
...@@ -2313,7 +2320,7 @@ static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) ...@@ -2313,7 +2320,7 @@ static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
mlxsw_sp); mlxsw_sp);
err_rx_listener_register: err_rx_listener_register:
for (i--; i >= 0; i--) { for (i--; i >= 0; i--) {
mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_FORWARD, mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_DISCARD,
mlxsw_sp_rx_listener[i].trap_id); mlxsw_sp_rx_listener[i].trap_id);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(hpkt), hpkt_pl); mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(hpkt), hpkt_pl);
...@@ -2330,7 +2337,7 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) ...@@ -2330,7 +2337,7 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
int i; int i;
for (i = 0; i < ARRAY_SIZE(mlxsw_sp_rx_listener); i++) { for (i = 0; i < ARRAY_SIZE(mlxsw_sp_rx_listener); i++) {
mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_FORWARD, mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_DISCARD,
mlxsw_sp_rx_listener[i].trap_id); mlxsw_sp_rx_listener[i].trap_id);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(hpkt), hpkt_pl); mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(hpkt), hpkt_pl);
...@@ -2420,16 +2427,10 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, ...@@ -2420,16 +2427,10 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
return err; return err;
} }
err = mlxsw_sp_ports_create(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n");
return err;
}
err = mlxsw_sp_event_register(mlxsw_sp, MLXSW_TRAP_ID_PUDE); err = mlxsw_sp_event_register(mlxsw_sp, MLXSW_TRAP_ID_PUDE);
if (err) { if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to register for PUDE events\n"); dev_err(mlxsw_sp->bus_info->dev, "Failed to register for PUDE events\n");
goto err_event_register; return err;
} }
err = mlxsw_sp_traps_init(mlxsw_sp); err = mlxsw_sp_traps_init(mlxsw_sp);
...@@ -2462,8 +2463,24 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, ...@@ -2462,8 +2463,24 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
goto err_switchdev_init; goto err_switchdev_init;
} }
err = mlxsw_sp_router_init(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n");
goto err_router_init;
}
err = mlxsw_sp_ports_create(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n");
goto err_ports_create;
}
return 0; return 0;
err_ports_create:
mlxsw_sp_router_fini(mlxsw_sp);
err_router_init:
mlxsw_sp_switchdev_fini(mlxsw_sp);
err_switchdev_init: err_switchdev_init:
err_lag_init: err_lag_init:
mlxsw_sp_buffers_fini(mlxsw_sp); mlxsw_sp_buffers_fini(mlxsw_sp);
...@@ -2472,21 +2489,23 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, ...@@ -2472,21 +2489,23 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp_traps_fini(mlxsw_sp); mlxsw_sp_traps_fini(mlxsw_sp);
err_rx_listener_register: err_rx_listener_register:
mlxsw_sp_event_unregister(mlxsw_sp, MLXSW_TRAP_ID_PUDE); mlxsw_sp_event_unregister(mlxsw_sp, MLXSW_TRAP_ID_PUDE);
err_event_register:
mlxsw_sp_ports_remove(mlxsw_sp);
return err; return err;
} }
static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
{ {
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
int i;
mlxsw_sp_ports_remove(mlxsw_sp);
mlxsw_sp_router_fini(mlxsw_sp);
mlxsw_sp_switchdev_fini(mlxsw_sp); mlxsw_sp_switchdev_fini(mlxsw_sp);
mlxsw_sp_buffers_fini(mlxsw_sp); mlxsw_sp_buffers_fini(mlxsw_sp);
mlxsw_sp_traps_fini(mlxsw_sp); mlxsw_sp_traps_fini(mlxsw_sp);
mlxsw_sp_event_unregister(mlxsw_sp, MLXSW_TRAP_ID_PUDE); mlxsw_sp_event_unregister(mlxsw_sp, MLXSW_TRAP_ID_PUDE);
mlxsw_sp_ports_remove(mlxsw_sp);
WARN_ON(!list_empty(&mlxsw_sp->fids)); WARN_ON(!list_empty(&mlxsw_sp->fids));
for (i = 0; i < MLXSW_SP_RIF_MAX; i++)
WARN_ON_ONCE(mlxsw_sp->rifs[i]);
} }
static struct mlxsw_config_profile mlxsw_sp_config_profile = { static struct mlxsw_config_profile mlxsw_sp_config_profile = {
...@@ -2810,6 +2829,45 @@ static int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp, ...@@ -2810,6 +2829,45 @@ static int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp,
return -EBUSY; return -EBUSY;
} }
static void
mlxsw_sp_port_pvid_vport_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
u16 lag_id)
{
struct mlxsw_sp_port *mlxsw_sp_vport;
struct mlxsw_sp_fid *f;
mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1);
if (WARN_ON(!mlxsw_sp_vport))
return;
/* If vPort is assigned a RIF, then leave it since it's no
* longer valid.
*/
f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
if (f)
f->leave(mlxsw_sp_vport);
mlxsw_sp_vport->lag_id = lag_id;
mlxsw_sp_vport->lagged = 1;
}
static void
mlxsw_sp_port_pvid_vport_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port)
{
struct mlxsw_sp_port *mlxsw_sp_vport;
struct mlxsw_sp_fid *f;
mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, 1);
if (WARN_ON(!mlxsw_sp_vport))
return;
f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
if (f)
f->leave(mlxsw_sp_vport);
mlxsw_sp_vport->lagged = 0;
}
static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
struct net_device *lag_dev) struct net_device *lag_dev)
{ {
...@@ -2845,6 +2903,9 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -2845,6 +2903,9 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_port->lag_id = lag_id; mlxsw_sp_port->lag_id = lag_id;
mlxsw_sp_port->lagged = 1; mlxsw_sp_port->lagged = 1;
lag->ref_count++; lag->ref_count++;
mlxsw_sp_port_pvid_vport_lag_join(mlxsw_sp_port, lag_id);
return 0; return 0;
err_col_port_enable: err_col_port_enable:
...@@ -2882,6 +2943,8 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -2882,6 +2943,8 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_port->local_port); mlxsw_sp_port->local_port);
mlxsw_sp_port->lagged = 0; mlxsw_sp_port->lagged = 0;
lag->ref_count--; lag->ref_count--;
mlxsw_sp_port_pvid_vport_lag_leave(mlxsw_sp_port);
} }
static int mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port *mlxsw_sp_port,
......
...@@ -74,6 +74,8 @@ ...@@ -74,6 +74,8 @@
#define MLXSW_SP_CELL_FACTOR 2 /* 2 * cell_size / (IPG + cell_size + 1) */ #define MLXSW_SP_CELL_FACTOR 2 /* 2 * cell_size / (IPG + cell_size + 1) */
#define MLXSW_SP_RIF_MAX 800
static inline u16 mlxsw_sp_pfc_delay_get(int mtu, u16 delay) static inline u16 mlxsw_sp_pfc_delay_get(int mtu, u16 delay)
{ {
delay = MLXSW_SP_BYTES_TO_CELLS(DIV_ROUND_UP(delay, BITS_PER_BYTE)); delay = MLXSW_SP_BYTES_TO_CELLS(DIV_ROUND_UP(delay, BITS_PER_BYTE));
...@@ -96,6 +98,11 @@ struct mlxsw_sp_fid { ...@@ -96,6 +98,11 @@ struct mlxsw_sp_fid {
u16 vid; u16 vid;
}; };
struct mlxsw_sp_rif {
struct net_device *dev;
u16 rif;
};
struct mlxsw_sp_mid { struct mlxsw_sp_mid {
struct list_head list; struct list_head list;
unsigned char addr[ETH_ALEN]; unsigned char addr[ETH_ALEN];
...@@ -167,6 +174,7 @@ struct mlxsw_sp { ...@@ -167,6 +174,7 @@ struct mlxsw_sp {
DECLARE_BITMAP(mapped, MLXSW_SP_MID_MAX); DECLARE_BITMAP(mapped, MLXSW_SP_MID_MAX);
} br_mids; } br_mids;
struct list_head fids; /* VLAN-aware bridge FIDs */ struct list_head fids; /* VLAN-aware bridge FIDs */
struct mlxsw_sp_rif *rifs[MLXSW_SP_RIF_MAX];
struct mlxsw_sp_port **ports; struct mlxsw_sp_port **ports;
struct mlxsw_core *core; struct mlxsw_core *core;
const struct mlxsw_bus_info *bus_info; const struct mlxsw_bus_info *bus_info;
...@@ -325,6 +333,19 @@ mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -325,6 +333,19 @@ mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port,
return NULL; return NULL;
} }
static inline struct mlxsw_sp_rif *
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *dev)
{
int i;
for (i = 0; i < MLXSW_SP_RIF_MAX; i++)
if (mlxsw_sp->rifs[i] && mlxsw_sp->rifs[i]->dev == dev)
return mlxsw_sp->rifs[i];
return NULL;
}
enum mlxsw_sp_flood_table { enum mlxsw_sp_flood_table {
MLXSW_SP_FLOOD_TABLE_UC, MLXSW_SP_FLOOD_TABLE_UC,
MLXSW_SP_FLOOD_TABLE_BM, MLXSW_SP_FLOOD_TABLE_BM,
...@@ -377,8 +398,6 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, ...@@ -377,8 +398,6 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
u16 vid_end, bool is_member, bool untagged); u16 vid_end, bool is_member, bool untagged);
int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto, int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto,
u16 vid); u16 vid);
int mlxsw_sp_port_kill_vid(struct net_device *dev,
__be16 __always_unused proto, u16 vid);
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
bool set); bool set);
void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port);
...@@ -413,4 +432,7 @@ static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port) ...@@ -413,4 +432,7 @@ static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
#endif #endif
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp);
#endif #endif
/*
* drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
* Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
* Copyright (c) 2016 Ido Schimmel <idosch@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include "spectrum.h"
#include "core.h"
#include "reg.h"
static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
{
char rgcr_pl[MLXSW_REG_RGCR_LEN];
mlxsw_reg_rgcr_pack(rgcr_pl, true);
mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, MLXSW_SP_RIF_MAX);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
}
static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
{
char rgcr_pl[MLXSW_REG_RGCR_LEN];
mlxsw_reg_rgcr_pack(rgcr_pl, false);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
}
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
{
return __mlxsw_sp_router_init(mlxsw_sp);
}
void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
{
__mlxsw_sp_router_fini(mlxsw_sp);
}
...@@ -633,25 +633,6 @@ int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) ...@@ -633,25 +633,6 @@ int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
return err; return err;
} }
static int mlxsw_sp_port_add_vids(struct net_device *dev, u16 vid_begin,
u16 vid_end)
{
u16 vid;
int err;
for (vid = vid_begin; vid <= vid_end; vid++) {
err = mlxsw_sp_port_add_vid(dev, 0, vid);
if (err)
goto err_port_add_vid;
}
return 0;
err_port_add_vid:
for (vid--; vid >= vid_begin; vid--)
mlxsw_sp_port_kill_vid(dev, 0, vid);
return err;
}
static int __mlxsw_sp_port_vlans_set(struct mlxsw_sp_port *mlxsw_sp_port, static int __mlxsw_sp_port_vlans_set(struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid_begin, u16 vid_end, bool is_member, u16 vid_begin, u16 vid_end, bool is_member,
bool untagged) bool untagged)
...@@ -681,12 +662,8 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -681,12 +662,8 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid, old_pvid; u16 vid, old_pvid;
int err; int err;
/* In case this is invoked with BRIDGE_FLAGS_SELF and port is
* not bridged, then packets ingressing through the port with
* the specified VIDs will be directed to CPU.
*/
if (!mlxsw_sp_port->bridged) if (!mlxsw_sp_port->bridged)
return mlxsw_sp_port_add_vids(dev, vid_begin, vid_end); return -EINVAL;
err = mlxsw_sp_port_fid_join(mlxsw_sp_port, vid_begin, vid_end); err = mlxsw_sp_port_fid_join(mlxsw_sp_port, vid_begin, vid_end);
if (err) { if (err) {
...@@ -1019,21 +996,6 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, ...@@ -1019,21 +996,6 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev,
return err; return err;
} }
static int mlxsw_sp_port_kill_vids(struct net_device *dev, u16 vid_begin,
u16 vid_end)
{
u16 vid;
int err;
for (vid = vid_begin; vid <= vid_end; vid++) {
err = mlxsw_sp_port_kill_vid(dev, 0, vid);
if (err)
return err;
}
return 0;
}
static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid_begin, u16 vid_end, bool init) u16 vid_begin, u16 vid_end, bool init)
{ {
...@@ -1041,12 +1003,8 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, ...@@ -1041,12 +1003,8 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid, pvid; u16 vid, pvid;
int err; int err;
/* In case this is invoked with BRIDGE_FLAGS_SELF and port is
* not bridged, then prevent packets ingressing through the
* port with the specified VIDs from being trapped to CPU.
*/
if (!init && !mlxsw_sp_port->bridged) if (!init && !mlxsw_sp_port->bridged)
return mlxsw_sp_port_kill_vids(dev, vid_begin, vid_end); return -EINVAL;
err = __mlxsw_sp_port_vlans_set(mlxsw_sp_port, vid_begin, vid_end, err = __mlxsw_sp_port_vlans_set(mlxsw_sp_port, vid_begin, vid_end,
false, false); false, false);
......
...@@ -54,6 +54,11 @@ enum { ...@@ -54,6 +54,11 @@ enum {
MLXSW_TRAP_ID_IGMP_V2_REPORT = 0x32, MLXSW_TRAP_ID_IGMP_V2_REPORT = 0x32,
MLXSW_TRAP_ID_IGMP_V2_LEAVE = 0x33, MLXSW_TRAP_ID_IGMP_V2_LEAVE = 0x33,
MLXSW_TRAP_ID_IGMP_V3_REPORT = 0x34, MLXSW_TRAP_ID_IGMP_V3_REPORT = 0x34,
MLXSW_TRAP_ID_ARPBC = 0x50,
MLXSW_TRAP_ID_ARPUC = 0x51,
MLXSW_TRAP_ID_IP2ME = 0x5F,
MLXSW_TRAP_ID_RTR_INGRESS0 = 0x70,
MLXSW_TRAP_ID_HOST_MISS_IPV4 = 0x90,
MLXSW_TRAP_ID_MAX = 0x1FF MLXSW_TRAP_ID_MAX = 0x1FF
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment