diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index a9d15590743eb59b955c7c6ce39ea9c8bb9a77bc..a06b93da6283abd5bb8e146bf7f0f42b61f8f5b7 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -326,10 +326,18 @@ static bool rocker_port_is_bridged(const struct rocker_port *rocker_port) return !!rocker_port->bridge_dev; } +#define ROCKER_OP_FLAG_REMOVE BIT(0) +#define ROCKER_OP_FLAG_NOWAIT BIT(1) +#define ROCKER_OP_FLAG_LEARNED BIT(2) +#define ROCKER_OP_FLAG_REFRESH BIT(3) + static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port, - enum switchdev_trans trans, size_t size) + enum switchdev_trans trans, int flags, + size_t size) { struct list_head *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 @@ -342,7 +350,7 @@ static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port, switch (trans) { case SWITCHDEV_TRANS_PREPARE: - elem = kzalloc(size + sizeof(*elem), GFP_KERNEL); + elem = kzalloc(size + sizeof(*elem), gfp_flags); if (!elem) return NULL; list_add_tail(elem, &rocker_port->trans_mem); @@ -353,7 +361,7 @@ static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port, list_del_init(elem); break; case SWITCHDEV_TRANS_NONE: - elem = kzalloc(size + sizeof(*elem), GFP_KERNEL); + elem = kzalloc(size + sizeof(*elem), gfp_flags); if (elem) INIT_LIST_HEAD(elem); break; @@ -365,16 +373,17 @@ static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port, } static void *rocker_port_kzalloc(struct rocker_port *rocker_port, - enum switchdev_trans trans, size_t size) + enum switchdev_trans trans, int flags, + size_t size) { - return __rocker_port_mem_alloc(rocker_port, trans, 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, size_t n, - size_t size) + enum switchdev_trans trans, int flags, + size_t n, size_t size) { - return __rocker_port_mem_alloc(rocker_port, trans, n * size); + return __rocker_port_mem_alloc(rocker_port, trans, flags, n * size); } static void rocker_port_kfree(enum switchdev_trans trans, const void *mem) @@ -397,11 +406,13 @@ static void rocker_port_kfree(enum switchdev_trans trans, const void *mem) struct rocker_wait { wait_queue_head_t wait; bool done; + bool nowait; }; static void rocker_wait_reset(struct rocker_wait *wait) { wait->done = false; + wait->nowait = false; } static void rocker_wait_init(struct rocker_wait *wait) @@ -411,11 +422,12 @@ 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) + enum switchdev_trans trans, + int flags) { struct rocker_wait *wait; - wait = rocker_port_kzalloc(rocker_port, trans, sizeof(*wait)); + wait = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*wait)); if (!wait) return NULL; rocker_wait_init(wait); @@ -1386,7 +1398,12 @@ static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id) spin_lock(&rocker->cmd_ring_lock); while ((desc_info = rocker_desc_tail_get(&rocker->cmd_ring))) { wait = rocker_desc_cookie_ptr_get(desc_info); - rocker_wait_wake_up(wait); + if (wait->nowait) { + rocker_desc_gen_clear(desc_info); + rocker_wait_destroy(SWITCHDEV_TRANS_NONE, wait); + } else { + rocker_wait_wake_up(wait); + } credits++; } spin_unlock(&rocker->cmd_ring_lock); @@ -1437,45 +1454,19 @@ static int rocker_event_link_change(const struct rocker *rocker, return 0; } -#define ROCKER_OP_FLAG_REMOVE BIT(0) -#define ROCKER_OP_FLAG_LEARNED BIT(1) -#define ROCKER_OP_FLAG_REFRESH BIT(2) - static int rocker_port_fdb(struct rocker_port *rocker_port, enum switchdev_trans trans, const unsigned char *addr, __be16 vlan_id, int flags); -struct rocker_mac_vlan_seen_work { - struct work_struct work; - struct rocker_port *rocker_port; - int flags; - unsigned char addr[ETH_ALEN]; - __be16 vlan_id; -}; - -static void rocker_event_mac_vlan_seen_work(struct work_struct *work) -{ - const struct rocker_mac_vlan_seen_work *sw = - container_of(work, struct rocker_mac_vlan_seen_work, work); - - rtnl_lock(); - rocker_port_fdb(sw->rocker_port, SWITCHDEV_TRANS_NONE, - sw->addr, sw->vlan_id, sw->flags); - rtnl_unlock(); - - kfree(work); -} - static int rocker_event_mac_vlan_seen(const struct rocker *rocker, const struct rocker_tlv *info) { - struct rocker_mac_vlan_seen_work *sw; const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAX + 1]; unsigned int port_number; struct rocker_port *rocker_port; const unsigned char *addr; - int flags = ROCKER_OP_FLAG_LEARNED; + int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_LEARNED; __be16 vlan_id; rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info); @@ -1497,20 +1488,8 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker, rocker_port->stp_state != BR_STATE_FORWARDING) return 0; - sw = kmalloc(sizeof(*sw), GFP_ATOMIC); - if (!sw) - return -ENOMEM; - - INIT_WORK(&sw->work, rocker_event_mac_vlan_seen_work); - - sw->rocker_port = rocker_port; - sw->flags = flags; - ether_addr_copy(sw->addr, addr); - sw->vlan_id = vlan_id; - - schedule_work(&sw->work); - - return 0; + return rocker_port_fdb(rocker_port, SWITCHDEV_TRANS_NONE, + addr, vlan_id, flags); } static int rocker_event_process(const struct rocker *rocker, @@ -1595,32 +1574,34 @@ 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, + enum switchdev_trans trans, int flags, rocker_cmd_prep_cb_t prepare, void *prepare_priv, rocker_cmd_proc_cb_t process, void *process_priv) { struct rocker *rocker = rocker_port->rocker; struct rocker_desc_info *desc_info; struct rocker_wait *wait; - unsigned long flags; + bool nowait = !!(flags & ROCKER_OP_FLAG_NOWAIT); + unsigned long lock_flags; int err; - wait = rocker_wait_create(rocker_port, trans); + wait = rocker_wait_create(rocker_port, trans, flags); if (!wait) return -ENOMEM; + wait->nowait = nowait; - spin_lock_irqsave(&rocker->cmd_ring_lock, flags); + spin_lock_irqsave(&rocker->cmd_ring_lock, lock_flags); desc_info = rocker_desc_head_get(&rocker->cmd_ring); if (!desc_info) { - spin_unlock_irqrestore(&rocker->cmd_ring_lock, flags); + spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags); err = -EAGAIN; goto out; } err = prepare(rocker_port, desc_info, prepare_priv); if (err) { - spin_unlock_irqrestore(&rocker->cmd_ring_lock, flags); + spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags); goto out; } @@ -1629,7 +1610,10 @@ static int rocker_cmd_exec(struct rocker_port *rocker_port, if (trans != SWITCHDEV_TRANS_PREPARE) rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info); - spin_unlock_irqrestore(&rocker->cmd_ring_lock, flags); + spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags); + + if (nowait) + return 0; if (trans != SWITCHDEV_TRANS_PREPARE) if (!rocker_wait_event_timeout(wait, HZ / 10)) @@ -1859,7 +1843,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, + return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, rocker_cmd_get_port_settings_prep, NULL, rocker_cmd_get_port_settings_ethtool_proc, ecmd); @@ -1868,7 +1852,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, + return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, rocker_cmd_get_port_settings_prep, NULL, rocker_cmd_get_port_settings_macaddr_proc, macaddr); @@ -1877,7 +1861,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, + return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, rocker_cmd_set_port_settings_ethtool_prep, ecmd, NULL, NULL); } @@ -1885,7 +1869,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, + return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, rocker_cmd_set_port_settings_macaddr_prep, macaddr, NULL, NULL); } @@ -1893,7 +1877,7 @@ static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port, static int rocker_port_set_learning(struct rocker_port *rocker_port, enum switchdev_trans trans) { - return rocker_cmd_exec(rocker_port, trans, + return rocker_cmd_exec(rocker_port, trans, 0, rocker_cmd_set_port_learning_prep, NULL, NULL, NULL); } @@ -2409,17 +2393,17 @@ rocker_flow_tbl_find(const struct rocker *rocker, } static int rocker_flow_tbl_add(struct rocker_port *rocker_port, - enum switchdev_trans trans, + enum switchdev_trans trans, int flags, struct rocker_flow_tbl_entry *match) { struct rocker *rocker = rocker_port->rocker; struct rocker_flow_tbl_entry *found; size_t key_len = match->key_len ? match->key_len : sizeof(found->key); - unsigned long flags; + unsigned long lock_flags; match->key_crc32 = crc32(~0, &match->key, key_len); - spin_lock_irqsave(&rocker->flow_tbl_lock, flags); + spin_lock_irqsave(&rocker->flow_tbl_lock, lock_flags); found = rocker_flow_tbl_find(rocker, match); @@ -2439,25 +2423,25 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port, if (trans != SWITCHDEV_TRANS_PREPARE) hash_add(rocker->flow_tbl, &found->entry, found->key_crc32); - spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags); + spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags); - return rocker_cmd_exec(rocker_port, trans, rocker_cmd_flow_tbl_add, - found, NULL, NULL); + return rocker_cmd_exec(rocker_port, trans, flags, + rocker_cmd_flow_tbl_add, found, NULL, NULL); } static int rocker_flow_tbl_del(struct rocker_port *rocker_port, - enum switchdev_trans trans, + enum switchdev_trans trans, int flags, struct rocker_flow_tbl_entry *match) { struct rocker *rocker = rocker_port->rocker; struct rocker_flow_tbl_entry *found; size_t key_len = match->key_len ? match->key_len : sizeof(found->key); - unsigned long flags; + unsigned long lock_flags; int err = 0; match->key_crc32 = crc32(~0, &match->key, key_len); - spin_lock_irqsave(&rocker->flow_tbl_lock, flags); + spin_lock_irqsave(&rocker->flow_tbl_lock, lock_flags); found = rocker_flow_tbl_find(rocker, match); @@ -2467,12 +2451,12 @@ static int rocker_flow_tbl_del(struct rocker_port *rocker_port, found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL; } - spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags); + spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags); rocker_port_kfree(trans, match); if (found) { - err = rocker_cmd_exec(rocker_port, trans, + err = rocker_cmd_exec(rocker_port, trans, flags, rocker_cmd_flow_tbl_del, found, NULL, NULL); rocker_port_kfree(trans, found); @@ -2486,9 +2470,9 @@ static int rocker_flow_tbl_do(struct rocker_port *rocker_port, struct rocker_flow_tbl_entry *entry) { if (flags & ROCKER_OP_FLAG_REMOVE) - return rocker_flow_tbl_del(rocker_port, trans, entry); + return rocker_flow_tbl_del(rocker_port, trans, flags, entry); else - return rocker_flow_tbl_add(rocker_port, trans, entry); + return rocker_flow_tbl_add(rocker_port, trans, flags, entry); } static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port, @@ -2498,7 +2482,7 @@ static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port, { struct rocker_flow_tbl_entry *entry; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -2520,7 +2504,7 @@ static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port, { struct rocker_flow_tbl_entry *entry; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -2547,7 +2531,7 @@ static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port, { struct rocker_flow_tbl_entry *entry; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -2587,7 +2571,7 @@ static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port, bool dflt = !eth_dst || (eth_dst && eth_dst_mask); bool wild = false; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -2637,7 +2621,7 @@ static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port, { struct rocker_flow_tbl_entry *entry; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -2667,7 +2651,7 @@ static int rocker_flow_tbl_acl(struct rocker_port *rocker_port, u32 priority; struct rocker_flow_tbl_entry *entry; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -2735,14 +2719,14 @@ 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, + enum switchdev_trans trans, int flags, struct rocker_group_tbl_entry *match) { struct rocker *rocker = rocker_port->rocker; struct rocker_group_tbl_entry *found; - unsigned long flags; + unsigned long lock_flags; - spin_lock_irqsave(&rocker->group_tbl_lock, flags); + spin_lock_irqsave(&rocker->group_tbl_lock, lock_flags); found = rocker_group_tbl_find(rocker, match); @@ -2760,22 +2744,22 @@ static int rocker_group_tbl_add(struct rocker_port *rocker_port, if (trans != SWITCHDEV_TRANS_PREPARE) hash_add(rocker->group_tbl, &found->entry, found->group_id); - spin_unlock_irqrestore(&rocker->group_tbl_lock, flags); + spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags); - return rocker_cmd_exec(rocker_port, trans, rocker_cmd_group_tbl_add, - found, NULL, NULL); + return rocker_cmd_exec(rocker_port, trans, flags, + rocker_cmd_group_tbl_add, found, NULL, NULL); } static int rocker_group_tbl_del(struct rocker_port *rocker_port, - enum switchdev_trans trans, + enum switchdev_trans trans, int flags, struct rocker_group_tbl_entry *match) { struct rocker *rocker = rocker_port->rocker; struct rocker_group_tbl_entry *found; - unsigned long flags; + unsigned long lock_flags; int err = 0; - spin_lock_irqsave(&rocker->group_tbl_lock, flags); + spin_lock_irqsave(&rocker->group_tbl_lock, lock_flags); found = rocker_group_tbl_find(rocker, match); @@ -2785,12 +2769,12 @@ static int rocker_group_tbl_del(struct rocker_port *rocker_port, found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL; } - spin_unlock_irqrestore(&rocker->group_tbl_lock, flags); + spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags); rocker_group_tbl_entry_free(trans, match); if (found) { - err = rocker_cmd_exec(rocker_port, trans, + err = rocker_cmd_exec(rocker_port, trans, flags, rocker_cmd_group_tbl_del, found, NULL, NULL); rocker_group_tbl_entry_free(trans, found); @@ -2804,9 +2788,9 @@ static int rocker_group_tbl_do(struct rocker_port *rocker_port, struct rocker_group_tbl_entry *entry) { if (flags & ROCKER_OP_FLAG_REMOVE) - return rocker_group_tbl_del(rocker_port, trans, entry); + return rocker_group_tbl_del(rocker_port, trans, flags, entry); else - return rocker_group_tbl_add(rocker_port, trans, entry); + return rocker_group_tbl_add(rocker_port, trans, flags, entry); } static int rocker_group_l2_interface(struct rocker_port *rocker_port, @@ -2816,7 +2800,7 @@ static int rocker_group_l2_interface(struct rocker_port *rocker_port, { struct rocker_group_tbl_entry *entry; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -2833,15 +2817,15 @@ static int rocker_group_l2_fan_out(struct rocker_port *rocker_port, { struct rocker_group_tbl_entry *entry; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; entry->group_id = group_id; entry->group_count = group_count; - entry->group_ids = rocker_port_kcalloc(rocker_port, trans, group_count, - sizeof(u32)); + entry->group_ids = rocker_port_kcalloc(rocker_port, trans, flags, + group_count, sizeof(u32)); if (!entry->group_ids) { rocker_port_kfree(trans, entry); return -ENOMEM; @@ -2868,7 +2852,7 @@ static int rocker_group_l3_unicast(struct rocker_port *rocker_port, { struct rocker_group_tbl_entry *entry; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -2951,7 +2935,7 @@ static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port, bool removing; int err = 0; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -3067,7 +3051,7 @@ static int rocker_port_ipv4_nh(struct rocker_port *rocker_port, bool resolved = true; int err = 0; - entry = rocker_port_kzalloc(rocker_port, trans, sizeof(*entry)); + entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry)); if (!entry) return -ENOMEM; @@ -3124,8 +3108,8 @@ static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port, int err = 0; int i; - group_ids = rocker_port_kcalloc(rocker_port, trans, rocker->port_count, - sizeof(u32)); + group_ids = rocker_port_kcalloc(rocker_port, trans, flags, + rocker->port_count, sizeof(u32)); if (!group_ids) return -ENOMEM; @@ -3550,7 +3534,7 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port, if (!rocker_port_is_bridged(rocker_port)) return 0; - lw = rocker_port_kzalloc(rocker_port, trans, sizeof(*lw)); + lw = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*lw)); if (!lw) return -ENOMEM; @@ -3594,7 +3578,7 @@ static int rocker_port_fdb(struct rocker_port *rocker_port, bool removing = (flags & ROCKER_OP_FLAG_REMOVE); unsigned long lock_flags; - fdb = rocker_port_kzalloc(rocker_port, trans, sizeof(*fdb)); + fdb = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*fdb)); if (!fdb) return -ENOMEM; @@ -3632,12 +3616,11 @@ 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) + enum switchdev_trans trans, int flags) { struct rocker *rocker = rocker_port->rocker; struct rocker_fdb_tbl_entry *found; unsigned long lock_flags; - int flags = ROCKER_OP_FLAG_REMOVE; struct hlist_node *tmp; int bkt; int err = 0; @@ -3646,6 +3629,8 @@ 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; + spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags); hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) { @@ -3702,13 +3687,12 @@ 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) + enum switchdev_trans trans, int flags) { bool pop_vlan; u32 out_pport; __be16 vlan_id; u16 vid; - int flags = 0; int err; /* Port will be forwarding-enabled if its STP state is LEARNING @@ -3742,12 +3726,12 @@ 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, u8 state) + enum switchdev_trans trans, int flags, + u8 state) { bool want[ROCKER_CTRL_MAX] = { 0, }; bool prev_ctrls[ROCKER_CTRL_MAX]; u8 prev_state; - int flags; int err; int i; @@ -3783,8 +3767,9 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port, for (i = 0; i < ROCKER_CTRL_MAX; i++) { if (want[i] != rocker_port->ctrls[i]) { - flags = (want[i] ? 0 : ROCKER_OP_FLAG_REMOVE); - err = rocker_port_ctrl(rocker_port, trans, flags, + int ctrl_flags = flags | + (want[i] ? 0 : ROCKER_OP_FLAG_REMOVE); + err = rocker_port_ctrl(rocker_port, trans, ctrl_flags, &rocker_ctrls[i]); if (err) goto err_out; @@ -3792,11 +3777,11 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port, } } - err = rocker_port_fdb_flush(rocker_port, trans); + err = rocker_port_fdb_flush(rocker_port, trans, flags); if (err) goto err_out; - err = rocker_port_fwding(rocker_port, trans); + err = rocker_port_fwding(rocker_port, trans, flags); err_out: if (trans == SWITCHDEV_TRANS_PREPARE) { @@ -3808,25 +3793,27 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port, } static int rocker_port_fwd_enable(struct rocker_port *rocker_port, - enum switchdev_trans trans) + enum switchdev_trans trans, int flags) { if (rocker_port_is_bridged(rocker_port)) /* bridge STP will enable port */ return 0; /* port is not bridged, so simulate going to FORWARDING state */ - return rocker_port_stp_update(rocker_port, trans, BR_STATE_FORWARDING); + return rocker_port_stp_update(rocker_port, trans, flags, + BR_STATE_FORWARDING); } static int rocker_port_fwd_disable(struct rocker_port *rocker_port, - enum switchdev_trans trans) + enum switchdev_trans trans, int flags) { if (rocker_port_is_bridged(rocker_port)) /* bridge STP will disable port */ return 0; /* port is not bridged, so simulate going to DISABLED state */ - return rocker_port_stp_update(rocker_port, trans, BR_STATE_DISABLED); + return rocker_port_stp_update(rocker_port, trans, flags, + BR_STATE_DISABLED); } static struct rocker_internal_vlan_tbl_entry * @@ -3990,7 +3977,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); + err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0); if (err) goto err_fwd_enable; @@ -4017,7 +4004,8 @@ 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, SWITCHDEV_TRANS_NONE, + ROCKER_OP_FLAG_NOWAIT); free_irq(rocker_msix_rx_vector(rocker_port), rocker_port); free_irq(rocker_msix_tx_vector(rocker_port), rocker_port); rocker_port_dma_rings_fini(rocker_port); @@ -4171,7 +4159,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, + err = rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, rocker_cmd_get_port_settings_prep, NULL, rocker_cmd_get_port_settings_phys_name_proc, &name); @@ -4266,6 +4254,7 @@ static int rocker_port_attr_set(struct net_device *dev, switch (attr->id) { case SWITCHDEV_ATTR_PORT_STP_STATE: err = rocker_port_stp_update(rocker_port, attr->trans, + ROCKER_OP_FLAG_NOWAIT, attr->u.stp_state); break; case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS: @@ -4618,7 +4607,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, + return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, rocker_cmd_get_port_stats_prep, NULL, rocker_cmd_get_port_stats_ethtool_proc, priv); @@ -5170,7 +5159,8 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port) return err; if (rocker_port->dev->flags & IFF_UP) - err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE); + err = rocker_port_fwd_enable(rocker_port, + SWITCHDEV_TRANS_NONE, 0); return err; } @@ -5229,7 +5219,8 @@ static struct notifier_block rocker_netdevice_nb __read_mostly = { static int rocker_neigh_update(struct net_device *dev, struct neighbour *n) { struct rocker_port *rocker_port = netdev_priv(dev); - int flags = (n->nud_state & NUD_VALID) ? 0 : ROCKER_OP_FLAG_REMOVE; + int flags = (n->nud_state & NUD_VALID ? 0 : ROCKER_OP_FLAG_REMOVE) | + ROCKER_OP_FLAG_NOWAIT; __be32 ip_addr = *(__be32 *)n->primary_key; return rocker_port_ipv4_neigh(rocker_port, SWITCHDEV_TRANS_NONE,