diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 4a080612142a..893a80e36632 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1273,7 +1273,7 @@ void ionic_lif_rx_mode(struct ionic_lif *lif) rx_mode |= (nd_flags & IFF_PROMISC) ? IONIC_RX_MODE_F_PROMISC : 0; rx_mode |= (nd_flags & IFF_ALLMULTI) ? IONIC_RX_MODE_F_ALLMULTI : 0; - /* sync the mac filters */ + /* sync the filters */ ionic_rx_filter_sync(lif); /* check for overflow state @@ -1284,7 +1284,8 @@ void ionic_lif_rx_mode(struct ionic_lif *lif) */ nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters); - if ((lif->nucast + lif->nmcast) >= nfilters) { + if (((lif->nucast + lif->nmcast) >= nfilters) || + (lif->max_vlans && lif->nvlans >= lif->max_vlans)) { rx_mode |= IONIC_RX_MODE_F_PROMISC; rx_mode |= IONIC_RX_MODE_F_ALLMULTI; } else { @@ -1672,59 +1673,30 @@ static int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) { struct ionic_lif *lif = netdev_priv(netdev); - struct ionic_admin_ctx ctx = { - .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work), - .cmd.rx_filter_add = { - .opcode = IONIC_CMD_RX_FILTER_ADD, - .lif_index = cpu_to_le16(lif->index), - .match = cpu_to_le16(IONIC_RX_FILTER_MATCH_VLAN), - .vlan.vlan = cpu_to_le16(vid), - }, - }; int err; - netdev_dbg(netdev, "rx_filter add VLAN %d\n", vid); - err = ionic_adminq_post_wait(lif, &ctx); + err = ionic_lif_vlan_add(lif, vid); if (err) return err; - spin_lock_bh(&lif->rx_filters.lock); - err = ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx, - IONIC_FILTER_STATE_SYNCED); - spin_unlock_bh(&lif->rx_filters.lock); + ionic_lif_rx_mode(lif); - return err; + return 0; } static int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) { struct ionic_lif *lif = netdev_priv(netdev); - struct ionic_admin_ctx ctx = { - .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work), - .cmd.rx_filter_del = { - .opcode = IONIC_CMD_RX_FILTER_DEL, - .lif_index = cpu_to_le16(lif->index), - }, - }; - struct ionic_rx_filter *f; + int err; - spin_lock_bh(&lif->rx_filters.lock); + err = ionic_lif_vlan_del(lif, vid); + if (err) + return err; - f = ionic_rx_filter_by_vlan(lif, vid); - if (!f) { - spin_unlock_bh(&lif->rx_filters.lock); - return -ENOENT; - } + ionic_lif_rx_mode(lif); - netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n", - vid, f->filter_id); - - ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id); - ionic_rx_filter_free(lif, f); - spin_unlock_bh(&lif->rx_filters.lock); - - return ionic_adminq_post_wait(lif, &ctx); + return 0; } int ionic_lif_rss_config(struct ionic_lif *lif, const u16 types, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index 541aa54e4ffd..9f7ab2f17f93 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -192,6 +192,8 @@ struct ionic_lif { u16 lif_type; unsigned int nmcast; unsigned int nucast; + unsigned int nvlans; + unsigned int max_vlans; char name[IONIC_LIF_NAME_MAX_SZ]; union ionic_lif_identity *identity; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c index 40a12b9df982..366f15794866 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.c @@ -337,8 +337,16 @@ static int ionic_lif_filter_add(struct ionic_lif *lif, /* Don't bother with the write to FW if we know there's no room, * we can try again on the next sync attempt. + * Since the FW doesn't have a way to tell us the vlan limit, + * we start max_vlans at 0 until we hit the ENOSPC error. */ switch (le16_to_cpu(ctx.cmd.rx_filter_add.match)) { + case IONIC_RX_FILTER_MATCH_VLAN: + netdev_dbg(lif->netdev, "%s: rx_filter add VLAN %d\n", + __func__, ctx.cmd.rx_filter_add.vlan.vlan); + if (lif->max_vlans && lif->nvlans >= lif->max_vlans) + err = -ENOSPC; + break; case IONIC_RX_FILTER_MATCH_MAC: netdev_dbg(lif->netdev, "%s: rx_filter add ADDR %pM\n", __func__, ctx.cmd.rx_filter_add.mac.addr); @@ -368,13 +376,19 @@ static int ionic_lif_filter_add(struct ionic_lif *lif, spin_unlock_bh(&lif->rx_filters.lock); - if (err == -ENOSPC) + if (err == -ENOSPC) { + if (le16_to_cpu(ctx.cmd.rx_filter_add.match) == IONIC_RX_FILTER_MATCH_VLAN) + lif->max_vlans = lif->nvlans; return 0; + } return err; } switch (le16_to_cpu(ctx.cmd.rx_filter_add.match)) { + case IONIC_RX_FILTER_MATCH_VLAN: + lif->nvlans++; + break; case IONIC_RX_FILTER_MATCH_MAC: if (is_multicast_ether_addr(ctx.cmd.rx_filter_add.mac.addr)) lif->nmcast++; @@ -413,6 +427,16 @@ int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr) return ionic_lif_filter_add(lif, &ac); } +int ionic_lif_vlan_add(struct ionic_lif *lif, const u16 vid) +{ + struct ionic_rx_filter_add_cmd ac = { + .match = cpu_to_le16(IONIC_RX_FILTER_MATCH_VLAN), + .vlan.vlan = cpu_to_le16(vid), + }; + + return ionic_lif_filter_add(lif, &ac); +} + static int ionic_lif_filter_del(struct ionic_lif *lif, struct ionic_rx_filter_add_cmd *ac) { @@ -435,6 +459,11 @@ static int ionic_lif_filter_del(struct ionic_lif *lif, } switch (le16_to_cpu(ac->match)) { + case IONIC_RX_FILTER_MATCH_VLAN: + netdev_dbg(lif->netdev, "%s: rx_filter del VLAN %d id %d\n", + __func__, ac->vlan.vlan, f->filter_id); + lif->nvlans--; + break; case IONIC_RX_FILTER_MATCH_MAC: netdev_dbg(lif->netdev, "%s: rx_filter del ADDR %pM id %d\n", __func__, ac->mac.addr, f->filter_id); @@ -471,6 +500,16 @@ int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr) return ionic_lif_filter_del(lif, &ac); } +int ionic_lif_vlan_del(struct ionic_lif *lif, const u16 vid) +{ + struct ionic_rx_filter_add_cmd ac = { + .match = cpu_to_le16(IONIC_RX_FILTER_MATCH_VLAN), + .vlan.vlan = cpu_to_le16(vid), + }; + + return ionic_lif_filter_del(lif, &ac); +} + struct sync_item { struct list_head list; struct ionic_rx_filter f; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h index a66e35f0833b..87b2666f248b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_rx_filter.h @@ -44,5 +44,7 @@ struct ionic_rx_filter *ionic_rx_filter_rxsteer(struct ionic_lif *lif); void ionic_rx_filter_sync(struct ionic_lif *lif); int ionic_lif_list_addr(struct ionic_lif *lif, const u8 *addr, bool mode); int ionic_rx_filters_need_sync(struct ionic_lif *lif); +int ionic_lif_vlan_add(struct ionic_lif *lif, const u16 vid); +int ionic_lif_vlan_del(struct ionic_lif *lif, const u16 vid); #endif /* _IONIC_RX_FILTER_H_ */