]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Merge tag 'mfd-for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
[mirror_ubuntu-bionic-kernel.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum.h
index 13b30eaa13d471180d473459aa8fe38606a0b8f1..f69aa37d1521854a2383c8db8c78bbffa1925ac6 100644 (file)
 
 #include <linux/types.h>
 #include <linux/netdevice.h>
+#include <linux/rhashtable.h>
 #include <linux/bitops.h>
 #include <linux/if_vlan.h>
 #include <linux/list.h>
 #include <linux/dcbnl.h>
+#include <linux/in6.h>
 #include <net/switchdev.h>
 
 #include "port.h"
 #include "core.h"
 
 #define MLXSW_SP_VFID_BASE VLAN_N_VID
-#define MLXSW_SP_VFID_PORT_MAX 512     /* Non-bridged VLAN interfaces */
-#define MLXSW_SP_VFID_BR_MAX 6144      /* Bridged VLAN interfaces */
-#define MLXSW_SP_VFID_MAX (MLXSW_SP_VFID_PORT_MAX + MLXSW_SP_VFID_BR_MAX)
+#define MLXSW_SP_VFID_MAX 6656 /* Bridged VLAN interfaces */
+
+#define MLXSW_SP_RFID_BASE 15360
+#define MLXSW_SP_RIF_MAX 800
 
 #define MLXSW_SP_LAG_MAX 64
 #define MLXSW_SP_PORT_PER_LAG_MAX 16
 
 #define MLXSW_SP_PORTS_PER_CLUSTER_MAX 4
 
+#define MLXSW_SP_LPM_TREE_MIN 2 /* trees 0 and 1 are reserved */
+#define MLXSW_SP_LPM_TREE_MAX 22
+#define MLXSW_SP_LPM_TREE_COUNT (MLXSW_SP_LPM_TREE_MAX - MLXSW_SP_LPM_TREE_MIN)
+
+#define MLXSW_SP_VIRTUAL_ROUTER_MAX 256
+
 #define MLXSW_SP_PORT_BASE_SPEED 25000 /* Mb/s */
 
 #define MLXSW_SP_BYTES_PER_CELL 96
 #define MLXSW_SP_BYTES_TO_CELLS(b) DIV_ROUND_UP(b, MLXSW_SP_BYTES_PER_CELL)
 #define MLXSW_SP_CELLS_TO_BYTES(c) (c * MLXSW_SP_BYTES_PER_CELL)
 
+#define MLXSW_SP_KVD_LINEAR_SIZE 65536 /* entries */
+#define MLXSW_SP_KVD_HASH_SINGLE_SIZE 163840 /* entries */
+#define MLXSW_SP_KVD_HASH_DOUBLE_SIZE 32768 /* entries */
+
 /* Maximum delay buffer needed in case of PAUSE frames, in cells.
  * Assumes 100m cable and maximum MTU.
  */
@@ -87,12 +100,22 @@ struct mlxsw_sp_upper {
        unsigned int ref_count;
 };
 
-struct mlxsw_sp_vfid {
+struct mlxsw_sp_fid {
+       void (*leave)(struct mlxsw_sp_port *mlxsw_sp_vport);
        struct list_head list;
-       u16 nr_vports;
-       u16 vfid;       /* Starting at 0 */
-       struct net_device *br_dev;
-       u16 vid;
+       unsigned int ref_count;
+       struct net_device *dev;
+       struct mlxsw_sp_rif *r;
+       u16 fid;
+};
+
+struct mlxsw_sp_rif {
+       struct net_device *dev;
+       unsigned int ref_count;
+       struct mlxsw_sp_fid *f;
+       unsigned char addr[ETH_ALEN];
+       int mtu;
+       u16 rif;
 };
 
 struct mlxsw_sp_mid {
@@ -115,7 +138,17 @@ static inline u16 mlxsw_sp_fid_to_vfid(u16 fid)
 
 static inline bool mlxsw_sp_fid_is_vfid(u16 fid)
 {
-       return fid >= MLXSW_SP_VFID_BASE;
+       return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_RFID_BASE;
+}
+
+static inline bool mlxsw_sp_fid_is_rfid(u16 fid)
+{
+       return fid >= MLXSW_SP_RFID_BASE;
+}
+
+static inline u16 mlxsw_sp_rif_sp_to_fid(u16 rif)
+{
+       return MLXSW_SP_RFID_BASE + rif;
 }
 
 struct mlxsw_sp_sb_pr {
@@ -152,20 +185,97 @@ struct mlxsw_sp_sb {
        } ports[MLXSW_PORT_MAX_PORTS];
 };
 
-struct mlxsw_sp {
+#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE)
+
+struct mlxsw_sp_prefix_usage {
+       DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT);
+};
+
+enum mlxsw_sp_l3proto {
+       MLXSW_SP_L3_PROTO_IPV4,
+       MLXSW_SP_L3_PROTO_IPV6,
+};
+
+struct mlxsw_sp_lpm_tree {
+       u8 id; /* tree ID */
+       unsigned int ref_count;
+       enum mlxsw_sp_l3proto proto;
+       struct mlxsw_sp_prefix_usage prefix_usage;
+};
+
+struct mlxsw_sp_fib;
+
+struct mlxsw_sp_vr {
+       u16 id; /* virtual router ID */
+       bool used;
+       enum mlxsw_sp_l3proto proto;
+       u32 tb_id; /* kernel fib table id */
+       struct mlxsw_sp_lpm_tree *lpm_tree;
+       struct mlxsw_sp_fib *fib;
+};
+
+enum mlxsw_sp_span_type {
+       MLXSW_SP_SPAN_EGRESS,
+       MLXSW_SP_SPAN_INGRESS
+};
+
+struct mlxsw_sp_span_inspected_port {
+       struct list_head list;
+       enum mlxsw_sp_span_type type;
+       u8 local_port;
+};
+
+struct mlxsw_sp_span_entry {
+       u8 local_port;
+       bool used;
+       struct list_head bound_ports_list;
+       int ref_count;
+       int id;
+};
+
+enum mlxsw_sp_port_mall_action_type {
+       MLXSW_SP_PORT_MALL_MIRROR,
+};
+
+struct mlxsw_sp_port_mall_mirror_tc_entry {
+       u8 to_local_port;
+       bool ingress;
+};
+
+struct mlxsw_sp_port_mall_tc_entry {
+       struct list_head list;
+       unsigned long cookie;
+       enum mlxsw_sp_port_mall_action_type type;
+       union {
+               struct mlxsw_sp_port_mall_mirror_tc_entry mirror;
+       };
+};
+
+struct mlxsw_sp_router {
+       struct mlxsw_sp_lpm_tree lpm_trees[MLXSW_SP_LPM_TREE_COUNT];
+       struct mlxsw_sp_vr vrs[MLXSW_SP_VIRTUAL_ROUTER_MAX];
+       struct rhashtable neigh_ht;
        struct {
-               struct list_head list;
-               unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_VFID_PORT_MAX)];
-       } port_vfids;
+               struct delayed_work dw;
+               unsigned long interval; /* ms */
+       } neighs_update;
+       struct delayed_work nexthop_probe_dw;
+#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
+       struct list_head nexthop_group_list;
+       struct list_head nexthop_neighs_list;
+};
+
+struct mlxsw_sp {
        struct {
                struct list_head list;
-               unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_VFID_BR_MAX)];
-       } br_vfids;
+               DECLARE_BITMAP(mapped, MLXSW_SP_VFID_MAX);
+       } vfids;
        struct {
                struct list_head list;
-               unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_MID_MAX)];
+               DECLARE_BITMAP(mapped, MLXSW_SP_MID_MAX);
        } br_mids;
-       unsigned long active_fids[BITS_TO_LONGS(VLAN_N_VID)];
+       struct list_head fids;  /* VLAN-aware bridge FIDs */
+       struct mlxsw_sp_rif *rifs[MLXSW_SP_RIF_MAX];
        struct mlxsw_sp_port **ports;
        struct mlxsw_core *core;
        const struct mlxsw_bus_info *bus_info;
@@ -183,6 +293,15 @@ struct mlxsw_sp {
        struct mlxsw_sp_upper lags[MLXSW_SP_LAG_MAX];
        u8 port_to_module[MLXSW_PORT_MAX_PORTS];
        struct mlxsw_sp_sb sb;
+       struct mlxsw_sp_router router;
+       struct {
+               DECLARE_BITMAP(usage, MLXSW_SP_KVD_LINEAR_SIZE);
+       } kvdl;
+
+       struct {
+               struct mlxsw_sp_span_entry *entries;
+               int entries_count;
+       } span;
 };
 
 static inline struct mlxsw_sp_upper *
@@ -217,7 +336,7 @@ struct mlxsw_sp_port {
        u16 lag_id;
        struct {
                struct list_head list;
-               struct mlxsw_sp_vfid *vfid;
+               struct mlxsw_sp_fid *f;
                u16 vid;
        } vport;
        struct {
@@ -239,8 +358,13 @@ struct mlxsw_sp_port {
        unsigned long *untagged_vlans;
        /* VLAN interfaces */
        struct list_head vports_list;
+       /* TC handles */
+       struct list_head mall_tc_list;
 };
 
+struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev);
+void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port);
+
 static inline bool
 mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port)
 {
@@ -259,28 +383,38 @@ mlxsw_sp_port_lagged_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id, u8 port_index)
        return mlxsw_sp_port && mlxsw_sp_port->lagged ? mlxsw_sp_port : NULL;
 }
 
+static inline u16
+mlxsw_sp_vport_vid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
+{
+       return mlxsw_sp_vport->vport.vid;
+}
+
 static inline bool
 mlxsw_sp_port_is_vport(const struct mlxsw_sp_port *mlxsw_sp_port)
 {
-       return mlxsw_sp_port->vport.vfid;
+       u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port);
+
+       return vid != 0;
 }
 
-static inline struct net_device *
-mlxsw_sp_vport_br_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
+static inline void mlxsw_sp_vport_fid_set(struct mlxsw_sp_port *mlxsw_sp_vport,
+                                         struct mlxsw_sp_fid *f)
 {
-       return mlxsw_sp_vport->vport.vfid->br_dev;
+       mlxsw_sp_vport->vport.f = f;
 }
 
-static inline u16
-mlxsw_sp_vport_vid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
+static inline struct mlxsw_sp_fid *
+mlxsw_sp_vport_fid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
 {
-       return mlxsw_sp_vport->vport.vid;
+       return mlxsw_sp_vport->vport.f;
 }
 
-static inline u16
-mlxsw_sp_vport_vfid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
+static inline struct net_device *
+mlxsw_sp_vport_dev_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
 {
-       return mlxsw_sp_vport->vport.vfid->vfid;
+       struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
+
+       return f ? f->dev : NULL;
 }
 
 static inline struct mlxsw_sp_port *
@@ -298,20 +432,60 @@ mlxsw_sp_port_vport_find(const struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
 }
 
 static inline struct mlxsw_sp_port *
-mlxsw_sp_port_vport_find_by_vfid(const struct mlxsw_sp_port *mlxsw_sp_port,
-                                u16 vfid)
+mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port,
+                               u16 fid)
 {
        struct mlxsw_sp_port *mlxsw_sp_vport;
 
        list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list,
                            vport.list) {
-               if (mlxsw_sp_vport_vfid_get(mlxsw_sp_vport) == vfid)
+               struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
+
+               if (f && f->fid == fid)
                        return mlxsw_sp_vport;
        }
 
        return NULL;
 }
 
+static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp,
+                                                    u16 fid)
+{
+       struct mlxsw_sp_fid *f;
+
+       list_for_each_entry(f, &mlxsw_sp->fids, list)
+               if (f->fid == fid)
+                       return f;
+
+       return NULL;
+}
+
+static inline struct mlxsw_sp_fid *
+mlxsw_sp_vfid_find(const struct mlxsw_sp *mlxsw_sp,
+                  const struct net_device *br_dev)
+{
+       struct mlxsw_sp_fid *f;
+
+       list_for_each_entry(f, &mlxsw_sp->vfids.list, list)
+               if (f->dev == br_dev)
+                       return f;
+
+       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 {
        MLXSW_SP_FLOOD_TABLE_UC,
        MLXSW_SP_FLOOD_TABLE_BM,
@@ -364,12 +538,17 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
                           u16 vid_end, bool is_member, bool untagged);
 int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto,
                          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 vfid,
-                            bool set, bool only_uc);
+int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
+                            bool set);
 void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port);
 int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
+int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid);
+int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
+                       bool adding);
+struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid);
+void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *f);
+void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
+                                struct mlxsw_sp_rif *r);
 int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
                          enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
                          bool dwrr, u8 dwrr_weight);
@@ -399,4 +578,19 @@ static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
 
 #endif
 
+int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
+void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp);
+int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port,
+                            const struct switchdev_obj_ipv4_fib *fib4,
+                            struct switchdev_trans *trans);
+int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
+                            const struct switchdev_obj_ipv4_fib *fib4);
+int mlxsw_sp_router_neigh_construct(struct net_device *dev,
+                                   struct neighbour *n);
+void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
+                                  struct neighbour *n);
+
+int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count);
+void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index);
+
 #endif