Merge tag 'asm-generic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / rocker / rocker.c
index 7ca1abbc0d05676bdcbc2ea427d7f162a0a2e3f4..e9f2349e98bc0f32894c4880faf98f30b7737eab 100644 (file)
@@ -152,8 +152,9 @@ struct rocker_fdb_tbl_entry {
        struct hlist_node entry;
        u32 key_crc32; /* key */
        bool learned;
+       unsigned long touched;
        struct rocker_fdb_tbl_key {
-               u32 pport;
+               struct rocker_port *rocker_port;
                u8 addr[ETH_ALEN];
                __be16 vlan_id;
        } key;
@@ -220,13 +221,13 @@ struct rocker_port {
        __be16 internal_vlan_id;
        int stp_state;
        u32 brport_flags;
+       unsigned long ageing_time;
        bool ctrls[ROCKER_CTRL_MAX];
        unsigned long vlan_bitmap[ROCKER_VLAN_BITMAP_LEN];
        struct napi_struct napi_tx;
        struct napi_struct napi_rx;
        struct rocker_dma_ring_info tx_ring;
        struct rocker_dma_ring_info rx_ring;
-       struct list_head trans_mem;
 };
 
 struct rocker {
@@ -246,6 +247,7 @@ struct rocker {
        u64 flow_tbl_next_cookie;
        DECLARE_HASHTABLE(group_tbl, 16);
        spinlock_t group_tbl_lock;              /* for group tbl accesses */
+       struct timer_list fdb_cleanup_timer;
        DECLARE_HASHTABLE(fdb_tbl, 16);
        spinlock_t fdb_tbl_lock;                /* for fdb tbl accesses */
        unsigned long internal_vlan_bitmap[ROCKER_INTERNAL_VLAN_BITMAP_LEN];
@@ -340,74 +342,63 @@ static bool rocker_port_is_ovsed(const struct rocker_port *rocker_port)
 #define ROCKER_OP_FLAG_REFRESH         BIT(3)
 
 static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port,
-                                    enum switchdev_trans trans, int flags,
+                                    struct switchdev_trans *trans, int flags,
                                     size_t size)
 {
-       struct list_head *elem = NULL;
+       struct switchdev_trans_item *elem = NULL;
        gfp_t gfp_flags = (flags & ROCKER_OP_FLAG_NOWAIT) ?
                          GFP_ATOMIC : GFP_KERNEL;
 
        /* If in transaction prepare phase, allocate the memory
-        * and enqueue it on a per-port list.  If in transaction
-        * commit phase, dequeue the memory from the per-port list
+        * and enqueue it on a transaction.  If in transaction
+        * commit phase, dequeue the memory from the transaction
         * rather than re-allocating the memory.  The idea is the
         * driver code paths for prepare and commit are identical
         * so the memory allocated in the prepare phase is the
         * memory used in the commit phase.
         */
 
-       switch (trans) {
-       case SWITCHDEV_TRANS_PREPARE:
+       if (!trans) {
+               elem = kzalloc(size + sizeof(*elem), gfp_flags);
+       } else if (switchdev_trans_ph_prepare(trans)) {
                elem = kzalloc(size + sizeof(*elem), gfp_flags);
                if (!elem)
                        return NULL;
-               list_add_tail(elem, &rocker_port->trans_mem);
-               break;
-       case SWITCHDEV_TRANS_COMMIT:
-               BUG_ON(list_empty(&rocker_port->trans_mem));
-               elem = rocker_port->trans_mem.next;
-               list_del_init(elem);
-               break;
-       case SWITCHDEV_TRANS_NONE:
-               elem = kzalloc(size + sizeof(*elem), gfp_flags);
-               if (elem)
-                       INIT_LIST_HEAD(elem);
-               break;
-       default:
-               break;
+               switchdev_trans_item_enqueue(trans, elem, kfree, elem);
+       } else {
+               elem = switchdev_trans_item_dequeue(trans);
        }
 
        return elem ? elem + 1 : NULL;
 }
 
 static void *rocker_port_kzalloc(struct rocker_port *rocker_port,
-                                enum switchdev_trans trans, int flags,
+                                struct switchdev_trans *trans, int flags,
                                 size_t size)
 {
        return __rocker_port_mem_alloc(rocker_port, trans, flags, size);
 }
 
 static void *rocker_port_kcalloc(struct rocker_port *rocker_port,
-                                enum switchdev_trans trans, int flags,
+                                struct switchdev_trans *trans, int flags,
                                 size_t n, size_t size)
 {
        return __rocker_port_mem_alloc(rocker_port, trans, flags, n * size);
 }
 
-static void rocker_port_kfree(enum switchdev_trans trans, const void *mem)
+static void rocker_port_kfree(struct switchdev_trans *trans, const void *mem)
 {
-       struct list_head *elem;
+       struct switchdev_trans_item *elem;
 
        /* Frees are ignored if in transaction prepare phase.  The
         * memory remains on the per-port list until freed in the
         * commit phase.
         */
 
-       if (trans == SWITCHDEV_TRANS_PREPARE)
+       if (switchdev_trans_ph_prepare(trans))
                return;
 
-       elem = (struct list_head *)mem - 1;
-       BUG_ON(!list_empty(elem));
+       elem = (struct switchdev_trans_item *) mem - 1;
        kfree(elem);
 }
 
@@ -430,7 +421,7 @@ static void rocker_wait_init(struct rocker_wait *wait)
 }
 
 static struct rocker_wait *rocker_wait_create(struct rocker_port *rocker_port,
-                                             enum switchdev_trans trans,
+                                             struct switchdev_trans *trans,
                                              int flags)
 {
        struct rocker_wait *wait;
@@ -442,7 +433,7 @@ static struct rocker_wait *rocker_wait_create(struct rocker_port *rocker_port,
        return wait;
 }
 
-static void rocker_wait_destroy(enum switchdev_trans trans,
+static void rocker_wait_destroy(struct switchdev_trans *trans,
                                struct rocker_wait *wait)
 {
        rocker_port_kfree(trans, wait);
@@ -1408,7 +1399,7 @@ static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id)
                wait = rocker_desc_cookie_ptr_get(desc_info);
                if (wait->nowait) {
                        rocker_desc_gen_clear(desc_info);
-                       rocker_wait_destroy(SWITCHDEV_TRANS_NONE, wait);
+                       rocker_wait_destroy(NULL, wait);
                } else {
                        rocker_wait_wake_up(wait);
                }
@@ -1463,7 +1454,7 @@ static int rocker_event_link_change(const struct rocker *rocker,
 }
 
 static int rocker_port_fdb(struct rocker_port *rocker_port,
-                          enum switchdev_trans trans,
+                          struct switchdev_trans *trans,
                           const unsigned char *addr,
                           __be16 vlan_id, int flags);
 
@@ -1496,8 +1487,7 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
            rocker_port->stp_state != BR_STATE_FORWARDING)
                return 0;
 
-       return rocker_port_fdb(rocker_port, SWITCHDEV_TRANS_NONE,
-                              addr, vlan_id, flags);
+       return rocker_port_fdb(rocker_port, NULL, addr, vlan_id, flags);
 }
 
 static int rocker_event_process(const struct rocker *rocker,
@@ -1582,7 +1572,7 @@ typedef int (*rocker_cmd_proc_cb_t)(const struct rocker_port *rocker_port,
                                    void *priv);
 
 static int rocker_cmd_exec(struct rocker_port *rocker_port,
-                          enum switchdev_trans trans, int flags,
+                          struct switchdev_trans *trans, int flags,
                           rocker_cmd_prep_cb_t prepare, void *prepare_priv,
                           rocker_cmd_proc_cb_t process, void *process_priv)
 {
@@ -1615,7 +1605,7 @@ static int rocker_cmd_exec(struct rocker_port *rocker_port,
 
        rocker_desc_cookie_ptr_set(desc_info, wait);
 
-       if (trans != SWITCHDEV_TRANS_PREPARE)
+       if (!switchdev_trans_ph_prepare(trans))
                rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info);
 
        spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
@@ -1623,7 +1613,7 @@ static int rocker_cmd_exec(struct rocker_port *rocker_port,
        if (nowait)
                return 0;
 
-       if (trans != SWITCHDEV_TRANS_PREPARE)
+       if (!switchdev_trans_ph_prepare(trans))
                if (!rocker_wait_event_timeout(wait, HZ / 10))
                        return -EIO;
 
@@ -1875,7 +1865,7 @@ rocker_cmd_set_port_learning_prep(const struct rocker_port *rocker_port,
 static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,
                                                struct ethtool_cmd *ecmd)
 {
-       return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
+       return rocker_cmd_exec(rocker_port, NULL, 0,
                               rocker_cmd_get_port_settings_prep, NULL,
                               rocker_cmd_get_port_settings_ethtool_proc,
                               ecmd);
@@ -1884,7 +1874,7 @@ static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,
 static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port,
                                                unsigned char *macaddr)
 {
-       return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
+       return rocker_cmd_exec(rocker_port, NULL, 0,
                               rocker_cmd_get_port_settings_prep, NULL,
                               rocker_cmd_get_port_settings_macaddr_proc,
                               macaddr);
@@ -1893,7 +1883,7 @@ static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port,
 static int rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port,
                                                struct ethtool_cmd *ecmd)
 {
-       return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
+       return rocker_cmd_exec(rocker_port, NULL, 0,
                               rocker_cmd_set_port_settings_ethtool_prep,
                               ecmd, NULL, NULL);
 }
@@ -1901,7 +1891,7 @@ static int rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port,
 static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
                                                unsigned char *macaddr)
 {
-       return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
+       return rocker_cmd_exec(rocker_port, NULL, 0,
                               rocker_cmd_set_port_settings_macaddr_prep,
                               macaddr, NULL, NULL);
 }
@@ -1909,13 +1899,13 @@ static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
 static int rocker_cmd_set_port_settings_mtu(struct rocker_port *rocker_port,
                                            int mtu)
 {
-       return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
+       return rocker_cmd_exec(rocker_port, NULL, 0,
                               rocker_cmd_set_port_settings_mtu_prep,
                               &mtu, NULL, NULL);
 }
 
 static int rocker_port_set_learning(struct rocker_port *rocker_port,
-                                   enum switchdev_trans trans)
+                                   struct switchdev_trans *trans)
 {
        return rocker_cmd_exec(rocker_port, trans, 0,
                               rocker_cmd_set_port_learning_prep,
@@ -2433,7 +2423,7 @@ rocker_flow_tbl_find(const struct rocker *rocker,
 }
 
 static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
-                              enum switchdev_trans trans, int flags,
+                              struct switchdev_trans *trans, int flags,
                               struct rocker_flow_tbl_entry *match)
 {
        struct rocker *rocker = rocker_port->rocker;
@@ -2449,7 +2439,7 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
 
        if (found) {
                match->cookie = found->cookie;
-               if (trans != SWITCHDEV_TRANS_PREPARE)
+               if (!switchdev_trans_ph_prepare(trans))
                        hash_del(&found->entry);
                rocker_port_kfree(trans, found);
                found = match;
@@ -2460,7 +2450,7 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD;
        }
 
-       if (trans != SWITCHDEV_TRANS_PREPARE)
+       if (!switchdev_trans_ph_prepare(trans))
                hash_add(rocker->flow_tbl, &found->entry, found->key_crc32);
 
        spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags);
@@ -2470,7 +2460,7 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
 }
 
 static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
-                              enum switchdev_trans trans, int flags,
+                              struct switchdev_trans *trans, int flags,
                               struct rocker_flow_tbl_entry *match)
 {
        struct rocker *rocker = rocker_port->rocker;
@@ -2486,7 +2476,7 @@ static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
        found = rocker_flow_tbl_find(rocker, match);
 
        if (found) {
-               if (trans != SWITCHDEV_TRANS_PREPARE)
+               if (!switchdev_trans_ph_prepare(trans))
                        hash_del(&found->entry);
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL;
        }
@@ -2506,7 +2496,7 @@ static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
 }
 
 static int rocker_flow_tbl_do(struct rocker_port *rocker_port,
-                             enum switchdev_trans trans, int flags,
+                             struct switchdev_trans *trans, int flags,
                              struct rocker_flow_tbl_entry *entry)
 {
        if (flags & ROCKER_OP_FLAG_REMOVE)
@@ -2516,7 +2506,7 @@ static int rocker_flow_tbl_do(struct rocker_port *rocker_port,
 }
 
 static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
-                                  enum switchdev_trans trans, int flags,
+                                  struct switchdev_trans *trans, int flags,
                                   u32 in_pport, u32 in_pport_mask,
                                   enum rocker_of_dpa_table_id goto_tbl)
 {
@@ -2536,7 +2526,7 @@ static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
 }
 
 static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
-                               enum switchdev_trans trans, int flags,
+                               struct switchdev_trans *trans, int flags,
                                u32 in_pport, __be16 vlan_id,
                                __be16 vlan_id_mask,
                                enum rocker_of_dpa_table_id goto_tbl,
@@ -2562,7 +2552,7 @@ static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
 }
 
 static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
-                                   enum switchdev_trans trans,
+                                   struct switchdev_trans *trans,
                                    u32 in_pport, u32 in_pport_mask,
                                    __be16 eth_type, const u8 *eth_dst,
                                    const u8 *eth_dst_mask, __be16 vlan_id,
@@ -2599,7 +2589,7 @@ static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
 }
 
 static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
-                                 enum switchdev_trans trans, int flags,
+                                 struct switchdev_trans *trans, int flags,
                                  const u8 *eth_dst, const u8 *eth_dst_mask,
                                  __be16 vlan_id, u32 tunnel_id,
                                  enum rocker_of_dpa_table_id goto_tbl,
@@ -2653,7 +2643,7 @@ static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
 }
 
 static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port,
-                                         enum switchdev_trans trans,
+                                         struct switchdev_trans *trans,
                                          __be16 eth_type, __be32 dst,
                                          __be32 dst_mask, u32 priority,
                                          enum rocker_of_dpa_table_id goto_tbl,
@@ -2679,7 +2669,7 @@ static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port,
 }
 
 static int rocker_flow_tbl_acl(struct rocker_port *rocker_port,
-                              enum switchdev_trans trans, int flags,
+                              struct switchdev_trans *trans, int flags,
                               u32 in_pport, u32 in_pport_mask,
                               const u8 *eth_src, const u8 *eth_src_mask,
                               const u8 *eth_dst, const u8 *eth_dst_mask,
@@ -2744,7 +2734,7 @@ rocker_group_tbl_find(const struct rocker *rocker,
        return NULL;
 }
 
-static void rocker_group_tbl_entry_free(enum switchdev_trans trans,
+static void rocker_group_tbl_entry_free(struct switchdev_trans *trans,
                                        struct rocker_group_tbl_entry *entry)
 {
        switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
@@ -2759,7 +2749,7 @@ static void rocker_group_tbl_entry_free(enum switchdev_trans trans,
 }
 
 static int rocker_group_tbl_add(struct rocker_port *rocker_port,
-                               enum switchdev_trans trans, int flags,
+                               struct switchdev_trans *trans, int flags,
                                struct rocker_group_tbl_entry *match)
 {
        struct rocker *rocker = rocker_port->rocker;
@@ -2771,7 +2761,7 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port,
        found = rocker_group_tbl_find(rocker, match);
 
        if (found) {
-               if (trans != SWITCHDEV_TRANS_PREPARE)
+               if (!switchdev_trans_ph_prepare(trans))
                        hash_del(&found->entry);
                rocker_group_tbl_entry_free(trans, found);
                found = match;
@@ -2781,7 +2771,7 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port,
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD;
        }
 
-       if (trans != SWITCHDEV_TRANS_PREPARE)
+       if (!switchdev_trans_ph_prepare(trans))
                hash_add(rocker->group_tbl, &found->entry, found->group_id);
 
        spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags);
@@ -2791,7 +2781,7 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port,
 }
 
 static int rocker_group_tbl_del(struct rocker_port *rocker_port,
-                               enum switchdev_trans trans, int flags,
+                               struct switchdev_trans *trans, int flags,
                                struct rocker_group_tbl_entry *match)
 {
        struct rocker *rocker = rocker_port->rocker;
@@ -2804,7 +2794,7 @@ static int rocker_group_tbl_del(struct rocker_port *rocker_port,
        found = rocker_group_tbl_find(rocker, match);
 
        if (found) {
-               if (trans != SWITCHDEV_TRANS_PREPARE)
+               if (!switchdev_trans_ph_prepare(trans))
                        hash_del(&found->entry);
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
        }
@@ -2824,7 +2814,7 @@ static int rocker_group_tbl_del(struct rocker_port *rocker_port,
 }
 
 static int rocker_group_tbl_do(struct rocker_port *rocker_port,
-                              enum switchdev_trans trans, int flags,
+                              struct switchdev_trans *trans, int flags,
                               struct rocker_group_tbl_entry *entry)
 {
        if (flags & ROCKER_OP_FLAG_REMOVE)
@@ -2834,7 +2824,7 @@ static int rocker_group_tbl_do(struct rocker_port *rocker_port,
 }
 
 static int rocker_group_l2_interface(struct rocker_port *rocker_port,
-                                    enum switchdev_trans trans, int flags,
+                                    struct switchdev_trans *trans, int flags,
                                     __be16 vlan_id, u32 out_pport,
                                     int pop_vlan)
 {
@@ -2851,7 +2841,7 @@ static int rocker_group_l2_interface(struct rocker_port *rocker_port,
 }
 
 static int rocker_group_l2_fan_out(struct rocker_port *rocker_port,
-                                  enum switchdev_trans trans,
+                                  struct switchdev_trans *trans,
                                   int flags, u8 group_count,
                                   const u32 *group_ids, u32 group_id)
 {
@@ -2876,7 +2866,7 @@ static int rocker_group_l2_fan_out(struct rocker_port *rocker_port,
 }
 
 static int rocker_group_l2_flood(struct rocker_port *rocker_port,
-                                enum switchdev_trans trans, int flags,
+                                struct switchdev_trans *trans, int flags,
                                 __be16 vlan_id, u8 group_count,
                                 const u32 *group_ids, u32 group_id)
 {
@@ -2886,7 +2876,7 @@ static int rocker_group_l2_flood(struct rocker_port *rocker_port,
 }
 
 static int rocker_group_l3_unicast(struct rocker_port *rocker_port,
-                                  enum switchdev_trans trans, int flags,
+                                  struct switchdev_trans *trans, int flags,
                                   u32 index, const u8 *src_mac, const u8 *dst_mac,
                                   __be16 vlan_id, bool ttl_check, u32 pport)
 {
@@ -2922,22 +2912,22 @@ rocker_neigh_tbl_find(const struct rocker *rocker, __be32 ip_addr)
 }
 
 static void _rocker_neigh_add(struct rocker *rocker,
-                             enum switchdev_trans trans,
+                             struct switchdev_trans *trans,
                              struct rocker_neigh_tbl_entry *entry)
 {
-       if (trans != SWITCHDEV_TRANS_COMMIT)
+       if (!switchdev_trans_ph_commit(trans))
                entry->index = rocker->neigh_tbl_next_index++;
-       if (trans == SWITCHDEV_TRANS_PREPARE)
+       if (switchdev_trans_ph_prepare(trans))
                return;
        entry->ref_count++;
        hash_add(rocker->neigh_tbl, &entry->entry,
                 be32_to_cpu(entry->ip_addr));
 }
 
-static void _rocker_neigh_del(enum switchdev_trans trans,
+static void _rocker_neigh_del(struct switchdev_trans *trans,
                              struct rocker_neigh_tbl_entry *entry)
 {
-       if (trans == SWITCHDEV_TRANS_PREPARE)
+       if (switchdev_trans_ph_prepare(trans))
                return;
        if (--entry->ref_count == 0) {
                hash_del(&entry->entry);
@@ -2946,19 +2936,19 @@ static void _rocker_neigh_del(enum switchdev_trans trans,
 }
 
 static void _rocker_neigh_update(struct rocker_neigh_tbl_entry *entry,
-                                enum switchdev_trans trans,
+                                struct switchdev_trans *trans,
                                 const u8 *eth_dst, bool ttl_check)
 {
        if (eth_dst) {
                ether_addr_copy(entry->eth_dst, eth_dst);
                entry->ttl_check = ttl_check;
-       } else if (trans != SWITCHDEV_TRANS_PREPARE) {
+       } else if (!switchdev_trans_ph_prepare(trans)) {
                entry->ref_count++;
        }
 }
 
 static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
-                                 enum switchdev_trans trans,
+                                 struct switchdev_trans *trans,
                                  int flags, __be32 ip_addr, const u8 *eth_dst)
 {
        struct rocker *rocker = rocker_port->rocker;
@@ -3050,7 +3040,8 @@ err_out:
 }
 
 static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
-                                   enum switchdev_trans trans, __be32 ip_addr)
+                                   struct switchdev_trans *trans,
+                                   __be32 ip_addr)
 {
        struct net_device *dev = rocker_port->dev;
        struct neighbour *n = __ipv4_neigh_lookup(dev, (__force u32)ip_addr);
@@ -3078,7 +3069,7 @@ static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_ipv4_nh(struct rocker_port *rocker_port,
-                              enum switchdev_trans trans, int flags,
+                              struct switchdev_trans *trans, int flags,
                               __be32 ip_addr, u32 *index)
 {
        struct rocker *rocker = rocker_port->rocker;
@@ -3137,7 +3128,7 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
-                                       enum switchdev_trans trans,
+                                       struct switchdev_trans *trans,
                                        int flags, __be16 vlan_id)
 {
        struct rocker_port *p;
@@ -3186,7 +3177,7 @@ no_ports_in_vlan:
 }
 
 static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
-                                     enum switchdev_trans trans, int flags,
+                                     struct switchdev_trans *trans, int flags,
                                      __be16 vlan_id, bool pop_vlan)
 {
        const struct rocker *rocker = rocker_port->rocker;
@@ -3292,7 +3283,7 @@ static struct rocker_ctrl {
 };
 
 static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
-                                    enum switchdev_trans trans, int flags,
+                                    struct switchdev_trans *trans, int flags,
                                     const struct rocker_ctrl *ctrl, __be16 vlan_id)
 {
        u32 in_pport = rocker_port->pport;
@@ -3325,7 +3316,8 @@ static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
-                                       enum switchdev_trans trans, int flags,
+                                       struct switchdev_trans *trans,
+                                       int flags,
                                        const struct rocker_ctrl *ctrl,
                                        __be16 vlan_id)
 {
@@ -3350,7 +3342,7 @@ static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
-                                     enum switchdev_trans trans, int flags,
+                                     struct switchdev_trans *trans, int flags,
                                      const struct rocker_ctrl *ctrl, __be16 vlan_id)
 {
        u32 in_pport_mask = 0xffffffff;
@@ -3374,7 +3366,7 @@ static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port,
-                                enum switchdev_trans trans, int flags,
+                                struct switchdev_trans *trans, int flags,
                                 const struct rocker_ctrl *ctrl, __be16 vlan_id)
 {
        if (ctrl->acl)
@@ -3392,7 +3384,7 @@ static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port,
-                                    enum switchdev_trans trans, int flags,
+                                    struct switchdev_trans *trans, int flags,
                                     __be16 vlan_id)
 {
        int err = 0;
@@ -3411,7 +3403,7 @@ static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_ctrl(struct rocker_port *rocker_port,
-                           enum switchdev_trans trans, int flags,
+                           struct switchdev_trans *trans, int flags,
                            const struct rocker_ctrl *ctrl)
 {
        u16 vid;
@@ -3430,7 +3422,7 @@ static int rocker_port_ctrl(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_vlan(struct rocker_port *rocker_port,
-                           enum switchdev_trans trans, int flags, u16 vid)
+                           struct switchdev_trans *trans, int flags, u16 vid)
 {
        enum rocker_of_dpa_table_id goto_tbl =
                ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
@@ -3487,14 +3479,14 @@ static int rocker_port_vlan(struct rocker_port *rocker_port,
                           "Error (%d) port VLAN table\n", err);
 
 err_out:
-       if (trans == SWITCHDEV_TRANS_PREPARE)
+       if (switchdev_trans_ph_prepare(trans))
                change_bit(ntohs(internal_vlan_id), rocker_port->vlan_bitmap);
 
        return err;
 }
 
 static int rocker_port_ig_tbl(struct rocker_port *rocker_port,
-                             enum switchdev_trans trans, int flags)
+                             struct switchdev_trans *trans, int flags)
 {
        enum rocker_of_dpa_table_id goto_tbl;
        u32 in_pport;
@@ -3522,7 +3514,7 @@ static int rocker_port_ig_tbl(struct rocker_port *rocker_port,
 struct rocker_fdb_learn_work {
        struct work_struct work;
        struct rocker_port *rocker_port;
-       enum switchdev_trans trans;
+       struct switchdev_trans *trans;
        int flags;
        u8 addr[ETH_ALEN];
        u16 vid;
@@ -3550,7 +3542,7 @@ static void rocker_port_fdb_learn_work(struct work_struct *work)
 }
 
 static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
-                                enum switchdev_trans trans, int flags,
+                                struct switchdev_trans *trans, int flags,
                                 const u8 *addr, __be16 vlan_id)
 {
        struct rocker_fdb_learn_work *lw;
@@ -3592,7 +3584,7 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
        ether_addr_copy(lw->addr, addr);
        lw->vid = rocker_port_vlan_to_vid(rocker_port, vlan_id);
 
-       if (trans == SWITCHDEV_TRANS_PREPARE)
+       if (switchdev_trans_ph_prepare(trans))
                rocker_port_kfree(trans, lw);
        else
                schedule_work(&lw->work);
@@ -3614,7 +3606,7 @@ rocker_fdb_tbl_find(const struct rocker *rocker,
 }
 
 static int rocker_port_fdb(struct rocker_port *rocker_port,
-                          enum switchdev_trans trans,
+                          struct switchdev_trans *trans,
                           const unsigned char *addr,
                           __be16 vlan_id, int flags)
 {
@@ -3629,7 +3621,8 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
                return -ENOMEM;
 
        fdb->learned = (flags & ROCKER_OP_FLAG_LEARNED);
-       fdb->key.pport = rocker_port->pport;
+       fdb->touched = jiffies;
+       fdb->key.rocker_port = rocker_port;
        ether_addr_copy(fdb->key.addr, addr);
        fdb->key.vlan_id = vlan_id;
        fdb->key_crc32 = crc32(~0, &fdb->key, sizeof(fdb->key));
@@ -3638,13 +3631,17 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
 
        found = rocker_fdb_tbl_find(rocker, fdb);
 
-       if (removing && found) {
-               rocker_port_kfree(trans, fdb);
-               if (trans != SWITCHDEV_TRANS_PREPARE)
-                       hash_del(&found->entry);
-       } else if (!removing && !found) {
-               if (trans != SWITCHDEV_TRANS_PREPARE)
-                       hash_add(rocker->fdb_tbl, &fdb->entry, fdb->key_crc32);
+       if (found) {
+               found->touched = jiffies;
+               if (removing) {
+                       rocker_port_kfree(trans, fdb);
+                       if (!switchdev_trans_ph_prepare(trans))
+                               hash_del(&found->entry);
+               }
+       } else if (!removing) {
+               if (!switchdev_trans_ph_prepare(trans))
+                       hash_add(rocker->fdb_tbl, &fdb->entry,
+                                fdb->key_crc32);
        }
 
        spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
@@ -3662,7 +3659,7 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
-                                enum switchdev_trans trans, int flags)
+                                struct switchdev_trans *trans, int flags)
 {
        struct rocker *rocker = rocker_port->rocker;
        struct rocker_fdb_tbl_entry *found;
@@ -3675,12 +3672,12 @@ static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
            rocker_port->stp_state == BR_STATE_FORWARDING)
                return 0;
 
-       flags |= ROCKER_OP_FLAG_REMOVE;
+       flags |= ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE;
 
        spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
 
        hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
-               if (found->key.pport != rocker_port->pport)
+               if (found->key.rocker_port != rocker_port)
                        continue;
                if (!found->learned)
                        continue;
@@ -3689,7 +3686,7 @@ static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
                                            found->key.vlan_id);
                if (err)
                        goto err_out;
-               if (trans != SWITCHDEV_TRANS_PREPARE)
+               if (!switchdev_trans_ph_prepare(trans))
                        hash_del(&found->entry);
        }
 
@@ -3699,8 +3696,43 @@ err_out:
        return err;
 }
 
+static void rocker_fdb_cleanup(unsigned long data)
+{
+       struct rocker *rocker = (struct rocker *)data;
+       struct rocker_port *rocker_port;
+       struct rocker_fdb_tbl_entry *entry;
+       struct hlist_node *tmp;
+       unsigned long next_timer = jiffies + BR_MIN_AGEING_TIME;
+       unsigned long expires;
+       unsigned long lock_flags;
+       int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE |
+                   ROCKER_OP_FLAG_LEARNED;
+       int bkt;
+
+       spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
+
+       hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, entry, entry) {
+               if (!entry->learned)
+                       continue;
+               rocker_port = entry->key.rocker_port;
+               expires = entry->touched + rocker_port->ageing_time;
+               if (time_before_eq(expires, jiffies)) {
+                       rocker_port_fdb_learn(rocker_port, NULL,
+                                             flags, entry->key.addr,
+                                             entry->key.vlan_id);
+                       hash_del(&entry->entry);
+               } else if (time_before(expires, next_timer)) {
+                       next_timer = expires;
+               }
+       }
+
+       spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
+
+       mod_timer(&rocker->fdb_cleanup_timer, round_jiffies_up(next_timer));
+}
+
 static int rocker_port_router_mac(struct rocker_port *rocker_port,
-                                 enum switchdev_trans trans, int flags,
+                                 struct switchdev_trans *trans, int flags,
                                  __be16 vlan_id)
 {
        u32 in_pport_mask = 0xffffffff;
@@ -3733,7 +3765,7 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_fwding(struct rocker_port *rocker_port,
-                             enum switchdev_trans trans, int flags)
+                             struct switchdev_trans *trans, int flags)
 {
        bool pop_vlan;
        u32 out_pport;
@@ -3772,16 +3804,16 @@ static int rocker_port_fwding(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_stp_update(struct rocker_port *rocker_port,
-                                 enum switchdev_trans trans, int flags,
+                                 struct switchdev_trans *trans, int flags,
                                  u8 state)
 {
        bool want[ROCKER_CTRL_MAX] = { 0, };
        bool prev_ctrls[ROCKER_CTRL_MAX];
-       u8 prev_state;
+       u8 uninitialized_var(prev_state);
        int err;
        int i;
 
-       if (trans == SWITCHDEV_TRANS_PREPARE) {
+       if (switchdev_trans_ph_prepare(trans)) {
                memcpy(prev_ctrls, rocker_port->ctrls, sizeof(prev_ctrls));
                prev_state = rocker_port->stp_state;
        }
@@ -3833,7 +3865,7 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port,
        err = rocker_port_fwding(rocker_port, trans, flags);
 
 err_out:
-       if (trans == SWITCHDEV_TRANS_PREPARE) {
+       if (switchdev_trans_ph_prepare(trans)) {
                memcpy(rocker_port->ctrls, prev_ctrls, sizeof(prev_ctrls));
                rocker_port->stp_state = prev_state;
        }
@@ -3842,7 +3874,7 @@ err_out:
 }
 
 static int rocker_port_fwd_enable(struct rocker_port *rocker_port,
-                                 enum switchdev_trans trans, int flags)
+                                 struct switchdev_trans *trans, int flags)
 {
        if (rocker_port_is_bridged(rocker_port))
                /* bridge STP will enable port */
@@ -3854,7 +3886,7 @@ static int rocker_port_fwd_enable(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_fwd_disable(struct rocker_port *rocker_port,
-                                  enum switchdev_trans trans, int flags)
+                                  struct switchdev_trans *trans, int flags)
 {
        if (rocker_port_is_bridged(rocker_port))
                /* bridge STP will disable port */
@@ -3952,7 +3984,7 @@ not_found:
 }
 
 static int rocker_port_fib_ipv4(struct rocker_port *rocker_port,
-                               enum switchdev_trans trans, __be32 dst,
+                               struct switchdev_trans *trans, __be32 dst,
                                int dst_len, const struct fib_info *fi,
                                u32 tb_id, int flags)
 {
@@ -4026,7 +4058,7 @@ static int rocker_port_open(struct net_device *dev)
                goto err_request_rx_irq;
        }
 
-       err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0);
+       err = rocker_port_fwd_enable(rocker_port, NULL, 0);
        if (err)
                goto err_fwd_enable;
 
@@ -4054,7 +4086,7 @@ static int rocker_port_stop(struct net_device *dev)
        rocker_port_set_enable(rocker_port, false);
        napi_disable(&rocker_port->napi_rx);
        napi_disable(&rocker_port->napi_tx);
-       rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE,
+       rocker_port_fwd_disable(rocker_port, NULL,
                                ROCKER_OP_FLAG_NOWAIT);
        free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
        free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
@@ -4240,7 +4272,7 @@ static int rocker_port_get_phys_port_name(struct net_device *dev,
        struct port_name name = { .buf = buf, .len = len };
        int err;
 
-       err = rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
+       err = rocker_cmd_exec(rocker_port, NULL, 0,
                              rocker_cmd_get_port_settings_prep, NULL,
                              rocker_cmd_get_port_settings_phys_name_proc,
                              &name);
@@ -4265,7 +4297,7 @@ static void rocker_port_neigh_destroy(struct neighbour *n)
        int flags = ROCKER_OP_FLAG_REMOVE | ROCKER_OP_FLAG_NOWAIT;
        __be32 ip_addr = *(__be32 *)n->primary_key;
 
-       rocker_port_ipv4_neigh(rocker_port, SWITCHDEV_TRANS_NONE,
+       rocker_port_ipv4_neigh(rocker_port, NULL,
                               flags, ip_addr, n->ha);
 }
 
@@ -4297,11 +4329,11 @@ static int rocker_port_attr_get(struct net_device *dev,
        const struct rocker *rocker = rocker_port->rocker;
 
        switch (attr->id) {
-       case SWITCHDEV_ATTR_PORT_PARENT_ID:
+       case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
                attr->u.ppid.id_len = sizeof(rocker->hw.id);
                memcpy(&attr->u.ppid.id, &rocker->hw.id, attr->u.ppid.id_len);
                break;
-       case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS:
+       case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
                attr->u.brport_flags = rocker_port->brport_flags;
                break;
        default:
@@ -4311,18 +4343,8 @@ static int rocker_port_attr_get(struct net_device *dev,
        return 0;
 }
 
-static void rocker_port_trans_abort(const struct rocker_port *rocker_port)
-{
-       struct list_head *mem, *tmp;
-
-       list_for_each_safe(mem, tmp, &rocker_port->trans_mem) {
-               list_del(mem);
-               kfree(mem);
-       }
-}
-
 static int rocker_port_brport_flags_set(struct rocker_port *rocker_port,
-                                       enum switchdev_trans trans,
+                                       struct switchdev_trans *trans,
                                        unsigned long brport_flags)
 {
        unsigned long orig_flags;
@@ -4333,39 +4355,44 @@ static int rocker_port_brport_flags_set(struct rocker_port *rocker_port,
        if ((orig_flags ^ rocker_port->brport_flags) & BR_LEARNING)
                err = rocker_port_set_learning(rocker_port, trans);
 
-       if (trans == SWITCHDEV_TRANS_PREPARE)
+       if (switchdev_trans_ph_prepare(trans))
                rocker_port->brport_flags = orig_flags;
 
        return err;
 }
 
+static int rocker_port_bridge_ageing_time(struct rocker_port *rocker_port,
+                                         struct switchdev_trans *trans,
+                                         u32 ageing_time)
+{
+       if (!switchdev_trans_ph_prepare(trans)) {
+               rocker_port->ageing_time = clock_t_to_jiffies(ageing_time);
+               mod_timer(&rocker_port->rocker->fdb_cleanup_timer, jiffies);
+       }
+
+       return 0;
+}
+
 static int rocker_port_attr_set(struct net_device *dev,
-                               struct switchdev_attr *attr)
+                               const struct switchdev_attr *attr,
+                               struct switchdev_trans *trans)
 {
        struct rocker_port *rocker_port = netdev_priv(dev);
        int err = 0;
 
-       switch (attr->trans) {
-       case SWITCHDEV_TRANS_PREPARE:
-               BUG_ON(!list_empty(&rocker_port->trans_mem));
-               break;
-       case SWITCHDEV_TRANS_ABORT:
-               rocker_port_trans_abort(rocker_port);
-               return 0;
-       default:
-               break;
-       }
-
        switch (attr->id) {
-       case SWITCHDEV_ATTR_PORT_STP_STATE:
-               err = rocker_port_stp_update(rocker_port, attr->trans,
-                                            ROCKER_OP_FLAG_NOWAIT,
+       case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+               err = rocker_port_stp_update(rocker_port, trans, 0,
                                             attr->u.stp_state);
                break;
-       case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS:
-               err = rocker_port_brport_flags_set(rocker_port, attr->trans,
+       case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+               err = rocker_port_brport_flags_set(rocker_port, trans,
                                                   attr->u.brport_flags);
                break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
+               err = rocker_port_bridge_ageing_time(rocker_port, trans,
+                                                    attr->u.ageing_time);
+               break;
        default:
                err = -EOPNOTSUPP;
                break;
@@ -4375,7 +4402,8 @@ static int rocker_port_attr_set(struct net_device *dev,
 }
 
 static int rocker_port_vlan_add(struct rocker_port *rocker_port,
-                               enum switchdev_trans trans, u16 vid, u16 flags)
+                               struct switchdev_trans *trans,
+                               u16 vid, u16 flags)
 {
        int err;
 
@@ -4394,8 +4422,8 @@ static int rocker_port_vlan_add(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_vlans_add(struct rocker_port *rocker_port,
-                                enum switchdev_trans trans,
-                                const struct switchdev_obj_vlan *vlan)
+                                struct switchdev_trans *trans,
+                                const struct switchdev_obj_port_vlan *vlan)
 {
        u16 vid;
        int err;
@@ -4411,8 +4439,8 @@ static int rocker_port_vlans_add(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_fdb_add(struct rocker_port *rocker_port,
-                              enum switchdev_trans trans,
-                              const struct switchdev_obj_fdb *fdb)
+                              struct switchdev_trans *trans,
+                              const struct switchdev_obj_port_fdb *fdb)
 {
        __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL);
        int flags = 0;
@@ -4424,36 +4452,27 @@ static int rocker_port_fdb_add(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_obj_add(struct net_device *dev,
-                              struct switchdev_obj *obj)
+                              const struct switchdev_obj *obj,
+                              struct switchdev_trans *trans)
 {
        struct rocker_port *rocker_port = netdev_priv(dev);
        const struct switchdev_obj_ipv4_fib *fib4;
        int err = 0;
 
-       switch (obj->trans) {
-       case SWITCHDEV_TRANS_PREPARE:
-               BUG_ON(!list_empty(&rocker_port->trans_mem));
-               break;
-       case SWITCHDEV_TRANS_ABORT:
-               rocker_port_trans_abort(rocker_port);
-               return 0;
-       default:
-               break;
-       }
-
        switch (obj->id) {
-       case SWITCHDEV_OBJ_PORT_VLAN:
-               err = rocker_port_vlans_add(rocker_port, obj->trans,
-                                           &obj->u.vlan);
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               err = rocker_port_vlans_add(rocker_port, trans,
+                                           SWITCHDEV_OBJ_PORT_VLAN(obj));
                break;
-       case SWITCHDEV_OBJ_IPV4_FIB:
-               fib4 = &obj->u.ipv4_fib;
-               err = rocker_port_fib_ipv4(rocker_port, obj->trans,
+       case SWITCHDEV_OBJ_ID_IPV4_FIB:
+               fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
+               err = rocker_port_fib_ipv4(rocker_port, trans,
                                           htonl(fib4->dst), fib4->dst_len,
-                                          fib4->fi, fib4->tb_id, 0);
+                                          &fib4->fi, fib4->tb_id, 0);
                break;
-       case SWITCHDEV_OBJ_PORT_FDB:
-               err = rocker_port_fdb_add(rocker_port, obj->trans, &obj->u.fdb);
+       case SWITCHDEV_OBJ_ID_PORT_FDB:
+               err = rocker_port_fdb_add(rocker_port, trans,
+                                         SWITCHDEV_OBJ_PORT_FDB(obj));
                break;
        default:
                err = -EOPNOTSUPP;
@@ -4468,17 +4487,17 @@ static int rocker_port_vlan_del(struct rocker_port *rocker_port,
 {
        int err;
 
-       err = rocker_port_router_mac(rocker_port, SWITCHDEV_TRANS_NONE,
+       err = rocker_port_router_mac(rocker_port, NULL,
                                     ROCKER_OP_FLAG_REMOVE, htons(vid));
        if (err)
                return err;
 
-       return rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE,
+       return rocker_port_vlan(rocker_port, NULL,
                                ROCKER_OP_FLAG_REMOVE, vid);
 }
 
 static int rocker_port_vlans_del(struct rocker_port *rocker_port,
-                                const struct switchdev_obj_vlan *vlan)
+                                const struct switchdev_obj_port_vlan *vlan)
 {
        u16 vid;
        int err;
@@ -4493,11 +4512,11 @@ static int rocker_port_vlans_del(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_fdb_del(struct rocker_port *rocker_port,
-                              enum switchdev_trans trans,
-                              const struct switchdev_obj_fdb *fdb)
+                              struct switchdev_trans *trans,
+                              const struct switchdev_obj_port_fdb *fdb)
 {
        __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL);
-       int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE;
+       int flags = ROCKER_OP_FLAG_REMOVE;
 
        if (!rocker_port_is_bridged(rocker_port))
                return -EINVAL;
@@ -4506,25 +4525,27 @@ static int rocker_port_fdb_del(struct rocker_port *rocker_port,
 }
 
 static int rocker_port_obj_del(struct net_device *dev,
-                              struct switchdev_obj *obj)
+                              const struct switchdev_obj *obj)
 {
        struct rocker_port *rocker_port = netdev_priv(dev);
        const struct switchdev_obj_ipv4_fib *fib4;
        int err = 0;
 
        switch (obj->id) {
-       case SWITCHDEV_OBJ_PORT_VLAN:
-               err = rocker_port_vlans_del(rocker_port, &obj->u.vlan);
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               err = rocker_port_vlans_del(rocker_port,
+                                           SWITCHDEV_OBJ_PORT_VLAN(obj));
                break;
-       case SWITCHDEV_OBJ_IPV4_FIB:
-               fib4 = &obj->u.ipv4_fib;
-               err = rocker_port_fib_ipv4(rocker_port, SWITCHDEV_TRANS_NONE,
+       case SWITCHDEV_OBJ_ID_IPV4_FIB:
+               fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
+               err = rocker_port_fib_ipv4(rocker_port, NULL,
                                           htonl(fib4->dst), fib4->dst_len,
-                                          fib4->fi, fib4->tb_id,
+                                          &fib4->fi, fib4->tb_id,
                                           ROCKER_OP_FLAG_REMOVE);
                break;
-       case SWITCHDEV_OBJ_PORT_FDB:
-               err = rocker_port_fdb_del(rocker_port, obj->trans, &obj->u.fdb);
+       case SWITCHDEV_OBJ_ID_PORT_FDB:
+               err = rocker_port_fdb_del(rocker_port, NULL,
+                                         SWITCHDEV_OBJ_PORT_FDB(obj));
                break;
        default:
                err = -EOPNOTSUPP;
@@ -4535,10 +4556,10 @@ static int rocker_port_obj_del(struct net_device *dev,
 }
 
 static int rocker_port_fdb_dump(const struct rocker_port *rocker_port,
-                               struct switchdev_obj *obj)
+                               struct switchdev_obj_port_fdb *fdb,
+                               switchdev_obj_dump_cb_t *cb)
 {
        struct rocker *rocker = rocker_port->rocker;
-       struct switchdev_obj_fdb *fdb = &obj->u.fdb;
        struct rocker_fdb_tbl_entry *found;
        struct hlist_node *tmp;
        unsigned long lock_flags;
@@ -4547,13 +4568,13 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port,
 
        spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
        hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
-               if (found->key.pport != rocker_port->pport)
+               if (found->key.rocker_port != rocker_port)
                        continue;
-               fdb->addr = found->key.addr;
+               ether_addr_copy(fdb->addr, found->key.addr);
                fdb->ndm_state = NUD_REACHABLE;
                fdb->vid = rocker_port_vlan_to_vid(rocker_port,
                                                   found->key.vlan_id);
-               err = obj->cb(rocker_port->dev, obj);
+               err = cb(&fdb->obj);
                if (err)
                        break;
        }
@@ -4563,9 +4584,9 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port,
 }
 
 static int rocker_port_vlan_dump(const struct rocker_port *rocker_port,
-                                struct switchdev_obj *obj)
+                                struct switchdev_obj_port_vlan *vlan,
+                                switchdev_obj_dump_cb_t *cb)
 {
-       struct switchdev_obj_vlan *vlan = &obj->u.vlan;
        u16 vid;
        int err = 0;
 
@@ -4576,7 +4597,7 @@ static int rocker_port_vlan_dump(const struct rocker_port *rocker_port,
                if (rocker_vlan_id_is_internal(htons(vid)))
                        vlan->flags |= BRIDGE_VLAN_INFO_PVID;
                vlan->vid_begin = vlan->vid_end = vid;
-               err = obj->cb(rocker_port->dev, obj);
+               err = cb(&vlan->obj);
                if (err)
                        break;
        }
@@ -4585,17 +4606,20 @@ static int rocker_port_vlan_dump(const struct rocker_port *rocker_port,
 }
 
 static int rocker_port_obj_dump(struct net_device *dev,
-                               struct switchdev_obj *obj)
+                               struct switchdev_obj *obj,
+                               switchdev_obj_dump_cb_t *cb)
 {
        const struct rocker_port *rocker_port = netdev_priv(dev);
        int err = 0;
 
        switch (obj->id) {
-       case SWITCHDEV_OBJ_PORT_FDB:
-               err = rocker_port_fdb_dump(rocker_port, obj);
+       case SWITCHDEV_OBJ_ID_PORT_FDB:
+               err = rocker_port_fdb_dump(rocker_port,
+                                          SWITCHDEV_OBJ_PORT_FDB(obj), cb);
                break;
-       case SWITCHDEV_OBJ_PORT_VLAN:
-               err = rocker_port_vlan_dump(rocker_port, obj);
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               err = rocker_port_vlan_dump(rocker_port,
+                                           SWITCHDEV_OBJ_PORT_VLAN(obj), cb);
                break;
        default:
                err = -EOPNOTSUPP;
@@ -4738,7 +4762,7 @@ rocker_cmd_get_port_stats_ethtool_proc(const struct rocker_port *rocker_port,
 static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,
                                             void *priv)
 {
-       return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0,
+       return rocker_cmd_exec(rocker_port, NULL, 0,
                               rocker_cmd_get_port_stats_prep, NULL,
                               rocker_cmd_get_port_stats_ethtool_proc,
                               priv);
@@ -4930,8 +4954,7 @@ static void rocker_remove_ports(const struct rocker *rocker)
                rocker_port = rocker->ports[i];
                if (!rocker_port)
                        continue;
-               rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE,
-                                  ROCKER_OP_FLAG_REMOVE);
+               rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
                unregister_netdev(rocker_port->dev);
                free_netdev(rocker_port->dev);
        }
@@ -4969,7 +4992,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
        rocker_port->port_number = port_number;
        rocker_port->pport = port_number + 1;
        rocker_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC;
-       INIT_LIST_HEAD(&rocker_port->trans_mem);
+       rocker_port->ageing_time = BR_DEFAULT_AGEING_TIME;
 
        rocker_port_dev_addr_init(rocker_port);
        dev->netdev_ops = &rocker_port_netdev_ops;
@@ -4992,9 +5015,9 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
 
        switchdev_port_fwd_mark_set(rocker_port->dev, NULL, false);
 
-       rocker_port_set_learning(rocker_port, SWITCHDEV_TRANS_NONE);
+       rocker_port_set_learning(rocker_port, NULL);
 
-       err = rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, 0);
+       err = rocker_port_ig_tbl(rocker_port, NULL, 0);
        if (err) {
                netdev_err(rocker_port->dev, "install ig port table failed\n");
                goto err_port_ig_tbl;
@@ -5003,8 +5026,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
        rocker_port->internal_vlan_id =
                rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex);
 
-       err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE,
-                                  untagged_vid, 0);
+       err = rocker_port_vlan_add(rocker_port, NULL, untagged_vid, 0);
        if (err) {
                netdev_err(rocker_port->dev, "install untagged VLAN failed\n");
                goto err_untagged_vlan;
@@ -5013,8 +5035,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
        return 0;
 
 err_untagged_vlan:
-       rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE,
-                          ROCKER_OP_FLAG_REMOVE);
+       rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
 err_port_ig_tbl:
        rocker->ports[port_number] = NULL;
        unregister_netdev(dev);
@@ -5183,6 +5204,10 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto err_init_tbls;
        }
 
+       setup_timer(&rocker->fdb_cleanup_timer, rocker_fdb_cleanup,
+                   (unsigned long) rocker);
+       mod_timer(&rocker->fdb_cleanup_timer, jiffies);
+
        err = rocker_probe_ports(rocker);
        if (err) {
                dev_err(&pdev->dev, "failed to probe ports\n");
@@ -5195,6 +5220,7 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        return 0;
 
 err_probe_ports:
+       del_timer_sync(&rocker->fdb_cleanup_timer);
        rocker_free_tbls(rocker);
 err_init_tbls:
        free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
@@ -5222,6 +5248,7 @@ static void rocker_remove(struct pci_dev *pdev)
 {
        struct rocker *rocker = pci_get_drvdata(pdev);
 
+       del_timer_sync(&rocker->fdb_cleanup_timer);
        rocker_free_tbls(rocker);
        rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);
        rocker_remove_ports(rocker);
@@ -5275,8 +5302,7 @@ static int rocker_port_bridge_join(struct rocker_port *rocker_port,
        rocker_port->bridge_dev = bridge;
        switchdev_port_fwd_mark_set(rocker_port->dev, bridge, true);
 
-       return rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE,
-                                   untagged_vid, 0);
+       return rocker_port_vlan_add(rocker_port, NULL, untagged_vid, 0);
 }
 
 static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
@@ -5298,14 +5324,12 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
                                    false);
        rocker_port->bridge_dev = NULL;
 
-       err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE,
-                                  untagged_vid, 0);
+       err = rocker_port_vlan_add(rocker_port, NULL, untagged_vid, 0);
        if (err)
                return err;
 
        if (rocker_port->dev->flags & IFF_UP)
-               err = rocker_port_fwd_enable(rocker_port,
-                                            SWITCHDEV_TRANS_NONE, 0);
+               err = rocker_port_fwd_enable(rocker_port, NULL, 0);
 
        return err;
 }
@@ -5318,10 +5342,10 @@ static int rocker_port_ovs_changed(struct rocker_port *rocker_port,
 
        rocker_port->bridge_dev = master;
 
-       err = rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE, 0);
+       err = rocker_port_fwd_disable(rocker_port, NULL, 0);
        if (err)
                return err;
-       err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0);
+       err = rocker_port_fwd_enable(rocker_port, NULL, 0);
 
        return err;
 }
@@ -5399,8 +5423,7 @@ static int rocker_neigh_update(struct net_device *dev, struct neighbour *n)
                    ROCKER_OP_FLAG_NOWAIT;
        __be32 ip_addr = *(__be32 *)n->primary_key;
 
-       return rocker_port_ipv4_neigh(rocker_port, SWITCHDEV_TRANS_NONE,
-                                     flags, ip_addr, n->ha);
+       return rocker_port_ipv4_neigh(rocker_port, NULL, flags, ip_addr, n->ha);
 }
 
 static int rocker_netevent_event(struct notifier_block *unused,