OSDN Git Service

net: dsa: request drivers to perform FDB isolation
[uclinux-h8/linux.git] / include / net / dsa.h
index 85a5ba3..87c5f18 100644 (file)
@@ -116,6 +116,14 @@ struct dsa_netdevice_ops {
 #define MODULE_ALIAS_DSA_TAG_DRIVER(__proto)                           \
        MODULE_ALIAS(DSA_TAG_DRIVER_ALIAS __stringify(__proto##_VALUE))
 
+struct dsa_lag {
+       struct net_device *dev;
+       unsigned int id;
+       struct mutex fdb_lock;
+       struct list_head fdbs;
+       refcount_t refcount;
+};
+
 struct dsa_switch_tree {
        struct list_head        list;
 
@@ -134,7 +142,7 @@ struct dsa_switch_tree {
        /* Maps offloaded LAG netdevs to a zero-based linear ID for
         * drivers that need it.
         */
-       struct net_device **lags;
+       struct dsa_lag **lags;
 
        /* Tagging protocol operations */
        const struct dsa_device_ops *tag_ops;
@@ -163,32 +171,36 @@ struct dsa_switch_tree {
        unsigned int last_switch;
 };
 
+/* LAG IDs are one-based, the dst->lags array is zero-based */
 #define dsa_lags_foreach_id(_id, _dst)                         \
-       for ((_id) = 0; (_id) < (_dst)->lags_len; (_id)++)      \
-               if ((_dst)->lags[(_id)])
+       for ((_id) = 1; (_id) <= (_dst)->lags_len; (_id)++)     \
+               if ((_dst)->lags[(_id) - 1])
 
 #define dsa_lag_foreach_port(_dp, _dst, _lag)                  \
        list_for_each_entry((_dp), &(_dst)->ports, list)        \
-               if ((_dp)->lag_dev == (_lag))
+               if (dsa_port_offloads_lag((_dp), (_lag)))
 
 #define dsa_hsr_foreach_port(_dp, _ds, _hsr)                   \
        list_for_each_entry((_dp), &(_ds)->dst->ports, list)    \
                if ((_dp)->ds == (_ds) && (_dp)->hsr_dev == (_hsr))
 
-static inline struct net_device *dsa_lag_dev(struct dsa_switch_tree *dst,
-                                            unsigned int id)
+static inline struct dsa_lag *dsa_lag_by_id(struct dsa_switch_tree *dst,
+                                           unsigned int id)
 {
-       return dst->lags[id];
+       /* DSA LAG IDs are one-based, dst->lags is zero-based */
+       return dst->lags[id - 1];
 }
 
 static inline int dsa_lag_id(struct dsa_switch_tree *dst,
-                            struct net_device *lag)
+                            struct net_device *lag_dev)
 {
        unsigned int id;
 
        dsa_lags_foreach_id(id, dst) {
-               if (dsa_lag_dev(dst, id) == lag)
-                       return id;
+               struct dsa_lag *lag = dsa_lag_by_id(dst, id);
+
+               if (lag->dev == lag_dev)
+                       return lag->id;
        }
 
        return -ENODEV;
@@ -278,6 +290,10 @@ struct dsa_port {
 
        u8                      devlink_port_setup:1;
 
+       /* Master state bits, valid only on CPU ports */
+       u8                      master_admin_up:1;
+       u8                      master_oper_up:1;
+
        u8                      setup:1;
 
        struct device_node      *dn;
@@ -287,7 +303,7 @@ struct dsa_port {
        struct devlink_port     devlink_port;
        struct phylink          *pl;
        struct phylink_config   pl_config;
-       struct net_device       *lag_dev;
+       struct dsa_lag          *lag;
        struct net_device       *hsr_dev;
 
        struct list_head list;
@@ -308,6 +324,10 @@ struct dsa_port {
        struct mutex            addr_lists_lock;
        struct list_head        fdbs;
        struct list_head        mdbs;
+
+       /* List of VLANs that CPU and DSA ports are members of. */
+       struct mutex            vlans_lock;
+       struct list_head        vlans;
 };
 
 /* TODO: ideally DSA ports would have a single dp->link_dp member,
@@ -321,11 +341,34 @@ struct dsa_link {
        struct list_head list;
 };
 
+enum dsa_db_type {
+       DSA_DB_PORT,
+       DSA_DB_LAG,
+       DSA_DB_BRIDGE,
+};
+
+struct dsa_db {
+       enum dsa_db_type type;
+
+       union {
+               const struct dsa_port *dp;
+               struct dsa_lag lag;
+               struct dsa_bridge bridge;
+       };
+};
+
 struct dsa_mac_addr {
        unsigned char addr[ETH_ALEN];
        u16 vid;
        refcount_t refcount;
        struct list_head list;
+       struct dsa_db db;
+};
+
+struct dsa_vlan {
+       u16 vid;
+       refcount_t refcount;
+       struct list_head list;
 };
 
 struct dsa_switch {
@@ -377,17 +420,19 @@ struct dsa_switch {
         */
        u32                     vlan_filtering:1;
 
-       /* MAC PCS does not provide link state change interrupt, and requires
-        * polling. Flag passed on to PHYLINK.
-        */
-       u32                     pcs_poll:1;
-
        /* For switches that only have the MRU configurable. To ensure the
         * configured MTU is not exceeded, normalization of MRU on all bridged
         * interfaces is needed.
         */
        u32                     mtu_enforcement_ingress:1;
 
+       /* Drivers that isolate the FDBs of multiple bridges must set this
+        * to true to receive the bridge as an argument in .port_fdb_{add,del}
+        * and .port_mdb_{add,del}. Otherwise, the bridge.num will always be
+        * passed as zero.
+        */
+       u32                     fdb_isolation:1;
+
        /* Listener for switch fabric events */
        struct notifier_block   nb;
 
@@ -478,6 +523,12 @@ static inline bool dsa_port_is_unused(struct dsa_port *dp)
        return dp->type == DSA_PORT_TYPE_UNUSED;
 }
 
+static inline bool dsa_port_master_is_operational(struct dsa_port *dp)
+{
+       return dsa_port_is_cpu(dp) && dp->master_admin_up &&
+              dp->master_oper_up;
+}
+
 static inline bool dsa_is_unused_port(struct dsa_switch *ds, int p)
 {
        return dsa_to_port(ds, p)->type == DSA_PORT_TYPE_UNUSED;
@@ -581,6 +632,24 @@ static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int port)
        return port == dsa_upstream_port(ds, port);
 }
 
+/* Return true if this is a DSA port leading away from the CPU */
+static inline bool dsa_is_downstream_port(struct dsa_switch *ds, int port)
+{
+       return dsa_is_dsa_port(ds, port) && !dsa_is_upstream_port(ds, port);
+}
+
+/* Return the local port used to reach the CPU port */
+static inline unsigned int dsa_switch_upstream_port(struct dsa_switch *ds)
+{
+       struct dsa_port *dp;
+
+       dsa_switch_for_each_available_port(dp, ds) {
+               return dsa_upstream_port(ds, dp->index);
+       }
+
+       return ds->num_ports;
+}
+
 /* Return true if @upstream_ds is an upstream switch of @downstream_ds, meaning
  * that the routing port from @downstream_ds to @upstream_ds is also the port
  * which @downstream_ds uses to reach its dedicated CPU.
@@ -608,14 +677,30 @@ static inline bool dsa_port_is_vlan_filtering(const struct dsa_port *dp)
                return dp->vlan_filtering;
 }
 
+static inline unsigned int dsa_port_lag_id_get(struct dsa_port *dp)
+{
+       return dp->lag ? dp->lag->id : 0;
+}
+
+static inline struct net_device *dsa_port_lag_dev_get(struct dsa_port *dp)
+{
+       return dp->lag ? dp->lag->dev : NULL;
+}
+
+static inline bool dsa_port_offloads_lag(struct dsa_port *dp,
+                                        const struct dsa_lag *lag)
+{
+       return dsa_port_lag_dev_get(dp) == lag->dev;
+}
+
 static inline
 struct net_device *dsa_port_to_bridge_port(const struct dsa_port *dp)
 {
        if (!dp->bridge)
                return NULL;
 
-       if (dp->lag_dev)
-               return dp->lag_dev;
+       if (dp->lag)
+               return dp->lag->dev;
        else if (dp->hsr_dev)
                return dp->hsr_dev;
 
@@ -750,6 +835,9 @@ struct dsa_switch_ops {
        void    (*phylink_validate)(struct dsa_switch *ds, int port,
                                    unsigned long *supported,
                                    struct phylink_link_state *state);
+       struct phylink_pcs *(*phylink_mac_select_pcs)(struct dsa_switch *ds,
+                                                     int port,
+                                                     phy_interface_t iface);
        int     (*phylink_mac_link_state)(struct dsa_switch *ds, int port,
                                          struct phylink_link_state *state);
        void    (*phylink_mac_config)(struct dsa_switch *ds, int port,
@@ -877,19 +965,29 @@ struct dsa_switch_ops {
         * Forwarding database
         */
        int     (*port_fdb_add)(struct dsa_switch *ds, int port,
-                               const unsigned char *addr, u16 vid);
+                               const unsigned char *addr, u16 vid,
+                               struct dsa_db db);
        int     (*port_fdb_del)(struct dsa_switch *ds, int port,
-                               const unsigned char *addr, u16 vid);
+                               const unsigned char *addr, u16 vid,
+                               struct dsa_db db);
        int     (*port_fdb_dump)(struct dsa_switch *ds, int port,
                                 dsa_fdb_dump_cb_t *cb, void *data);
+       int     (*lag_fdb_add)(struct dsa_switch *ds, struct dsa_lag lag,
+                              const unsigned char *addr, u16 vid,
+                              struct dsa_db db);
+       int     (*lag_fdb_del)(struct dsa_switch *ds, struct dsa_lag lag,
+                              const unsigned char *addr, u16 vid,
+                              struct dsa_db db);
 
        /*
         * Multicast database
         */
        int     (*port_mdb_add)(struct dsa_switch *ds, int port,
-                               const struct switchdev_obj_port_mdb *mdb);
+                               const struct switchdev_obj_port_mdb *mdb,
+                               struct dsa_db db);
        int     (*port_mdb_del)(struct dsa_switch *ds, int port,
-                               const struct switchdev_obj_port_mdb *mdb);
+                               const struct switchdev_obj_port_mdb *mdb,
+                               struct dsa_db db);
        /*
         * RXNFC
         */
@@ -930,10 +1028,10 @@ struct dsa_switch_ops {
        int     (*crosschip_lag_change)(struct dsa_switch *ds, int sw_index,
                                        int port);
        int     (*crosschip_lag_join)(struct dsa_switch *ds, int sw_index,
-                                     int port, struct net_device *lag,
+                                     int port, struct dsa_lag lag,
                                      struct netdev_lag_upper_info *info);
        int     (*crosschip_lag_leave)(struct dsa_switch *ds, int sw_index,
-                                      int port, struct net_device *lag);
+                                      int port, struct dsa_lag lag);
 
        /*
         * PTP functionality
@@ -1005,10 +1103,10 @@ struct dsa_switch_ops {
         */
        int     (*port_lag_change)(struct dsa_switch *ds, int port);
        int     (*port_lag_join)(struct dsa_switch *ds, int port,
-                                struct net_device *lag,
+                                struct dsa_lag lag,
                                 struct netdev_lag_upper_info *info);
        int     (*port_lag_leave)(struct dsa_switch *ds, int port,
-                                 struct net_device *lag);
+                                 struct dsa_lag lag);
 
        /*
         * HSR integration
@@ -1036,6 +1134,13 @@ struct dsa_switch_ops {
        int     (*tag_8021q_vlan_add)(struct dsa_switch *ds, int port, u16 vid,
                                      u16 flags);
        int     (*tag_8021q_vlan_del)(struct dsa_switch *ds, int port, u16 vid);
+
+       /*
+        * DSA master tracking operations
+        */
+       void    (*master_state_change)(struct dsa_switch *ds,
+                                      const struct net_device *master,
+                                      bool operational);
 };
 
 #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes)           \
@@ -1212,9 +1317,6 @@ static inline bool dsa_slave_dev_check(const struct net_device *dev)
 #endif
 
 netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev);
-int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data);
-int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data);
-int dsa_port_get_phy_sset_count(struct dsa_port *dp);
 void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up);
 
 struct dsa_tag_driver {
@@ -1247,7 +1349,7 @@ module_exit(dsa_tag_driver_module_exit)
 /**
  * module_dsa_tag_drivers() - Helper macro for registering DSA tag
  * drivers
- * @__ops_array: Array of tag driver strucutres
+ * @__ops_array: Array of tag driver structures
  *
  * Helper macro for DSA tag drivers which do not do anything special
  * in module init/exit. Each module may only use this macro once, and