1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2017 - 2019 Pensando Systems, Inc */ 3 4 #include <linux/netdevice.h> 5 #include <linux/dynamic_debug.h> 6 #include <linux/etherdevice.h> 7 8 #include "ionic.h" 9 #include "ionic_lif.h" 10 #include "ionic_rx_filter.h" 11 12 void ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f) 13 { 14 struct device *dev = lif->ionic->dev; 15 16 hlist_del(&f->by_id); 17 hlist_del(&f->by_hash); 18 devm_kfree(dev, f); 19 } 20 21 void ionic_rx_filter_replay(struct ionic_lif *lif) 22 { 23 struct ionic_rx_filter_add_cmd *ac; 24 struct hlist_head new_id_list; 25 struct ionic_admin_ctx ctx; 26 struct ionic_rx_filter *f; 27 struct hlist_head *head; 28 struct hlist_node *tmp; 29 unsigned int key; 30 unsigned int i; 31 int err; 32 33 INIT_HLIST_HEAD(&new_id_list); 34 ac = &ctx.cmd.rx_filter_add; 35 36 for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { 37 head = &lif->rx_filters.by_id[i]; 38 hlist_for_each_entry_safe(f, tmp, head, by_id) { 39 ctx.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work); 40 memcpy(ac, &f->cmd, sizeof(f->cmd)); 41 dev_dbg(&lif->netdev->dev, "replay filter command:\n"); 42 dynamic_hex_dump("cmd ", DUMP_PREFIX_OFFSET, 16, 1, 43 &ctx.cmd, sizeof(ctx.cmd), true); 44 45 err = ionic_adminq_post_wait(lif, &ctx); 46 if (err) { 47 switch (le16_to_cpu(ac->match)) { 48 case IONIC_RX_FILTER_MATCH_VLAN: 49 netdev_info(lif->netdev, "Replay failed - %d: vlan %d\n", 50 err, 51 le16_to_cpu(ac->vlan.vlan)); 52 break; 53 case IONIC_RX_FILTER_MATCH_MAC: 54 netdev_info(lif->netdev, "Replay failed - %d: mac %pM\n", 55 err, ac->mac.addr); 56 break; 57 case IONIC_RX_FILTER_MATCH_MAC_VLAN: 58 netdev_info(lif->netdev, "Replay failed - %d: vlan %d mac %pM\n", 59 err, 60 le16_to_cpu(ac->vlan.vlan), 61 ac->mac.addr); 62 break; 63 } 64 spin_lock_bh(&lif->rx_filters.lock); 65 ionic_rx_filter_free(lif, f); 66 spin_unlock_bh(&lif->rx_filters.lock); 67 68 continue; 69 } 70 71 /* remove from old id list, save new id in tmp list */ 72 spin_lock_bh(&lif->rx_filters.lock); 73 hlist_del(&f->by_id); 74 spin_unlock_bh(&lif->rx_filters.lock); 75 f->filter_id = le32_to_cpu(ctx.comp.rx_filter_add.filter_id); 76 hlist_add_head(&f->by_id, &new_id_list); 77 } 78 } 79 80 /* rebuild the by_id hash lists with the new filter ids */ 81 spin_lock_bh(&lif->rx_filters.lock); 82 hlist_for_each_entry_safe(f, tmp, &new_id_list, by_id) { 83 key = f->filter_id & IONIC_RX_FILTER_HLISTS_MASK; 84 head = &lif->rx_filters.by_id[key]; 85 hlist_add_head(&f->by_id, head); 86 } 87 spin_unlock_bh(&lif->rx_filters.lock); 88 } 89 90 int ionic_rx_filters_init(struct ionic_lif *lif) 91 { 92 unsigned int i; 93 94 spin_lock_init(&lif->rx_filters.lock); 95 96 spin_lock_bh(&lif->rx_filters.lock); 97 for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { 98 INIT_HLIST_HEAD(&lif->rx_filters.by_hash[i]); 99 INIT_HLIST_HEAD(&lif->rx_filters.by_id[i]); 100 } 101 spin_unlock_bh(&lif->rx_filters.lock); 102 103 return 0; 104 } 105 106 void ionic_rx_filters_deinit(struct ionic_lif *lif) 107 { 108 struct ionic_rx_filter *f; 109 struct hlist_head *head; 110 struct hlist_node *tmp; 111 unsigned int i; 112 113 spin_lock_bh(&lif->rx_filters.lock); 114 for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { 115 head = &lif->rx_filters.by_id[i]; 116 hlist_for_each_entry_safe(f, tmp, head, by_id) 117 ionic_rx_filter_free(lif, f); 118 } 119 spin_unlock_bh(&lif->rx_filters.lock); 120 } 121 122 int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index, 123 u32 hash, struct ionic_admin_ctx *ctx) 124 { 125 struct device *dev = lif->ionic->dev; 126 struct ionic_rx_filter_add_cmd *ac; 127 struct ionic_rx_filter *f; 128 struct hlist_head *head; 129 unsigned int key; 130 131 ac = &ctx->cmd.rx_filter_add; 132 133 switch (le16_to_cpu(ac->match)) { 134 case IONIC_RX_FILTER_MATCH_VLAN: 135 key = le16_to_cpu(ac->vlan.vlan); 136 break; 137 case IONIC_RX_FILTER_MATCH_MAC: 138 key = *(u32 *)ac->mac.addr; 139 break; 140 case IONIC_RX_FILTER_MATCH_MAC_VLAN: 141 key = le16_to_cpu(ac->mac_vlan.vlan); 142 break; 143 default: 144 return -EINVAL; 145 } 146 147 f = devm_kzalloc(dev, sizeof(*f), GFP_KERNEL); 148 if (!f) 149 return -ENOMEM; 150 151 f->flow_id = flow_id; 152 f->filter_id = le32_to_cpu(ctx->comp.rx_filter_add.filter_id); 153 f->rxq_index = rxq_index; 154 memcpy(&f->cmd, ac, sizeof(f->cmd)); 155 netdev_dbg(lif->netdev, "rx_filter add filter_id %d\n", f->filter_id); 156 157 INIT_HLIST_NODE(&f->by_hash); 158 INIT_HLIST_NODE(&f->by_id); 159 160 spin_lock_bh(&lif->rx_filters.lock); 161 162 key = hash_32(key, IONIC_RX_FILTER_HASH_BITS); 163 head = &lif->rx_filters.by_hash[key]; 164 hlist_add_head(&f->by_hash, head); 165 166 key = f->filter_id & IONIC_RX_FILTER_HLISTS_MASK; 167 head = &lif->rx_filters.by_id[key]; 168 hlist_add_head(&f->by_id, head); 169 170 spin_unlock_bh(&lif->rx_filters.lock); 171 172 return 0; 173 } 174 175 struct ionic_rx_filter *ionic_rx_filter_by_vlan(struct ionic_lif *lif, u16 vid) 176 { 177 struct ionic_rx_filter *f; 178 struct hlist_head *head; 179 unsigned int key; 180 181 key = hash_32(vid, IONIC_RX_FILTER_HASH_BITS); 182 head = &lif->rx_filters.by_hash[key]; 183 184 hlist_for_each_entry(f, head, by_hash) { 185 if (le16_to_cpu(f->cmd.match) != IONIC_RX_FILTER_MATCH_VLAN) 186 continue; 187 if (le16_to_cpu(f->cmd.vlan.vlan) == vid) 188 return f; 189 } 190 191 return NULL; 192 } 193 194 struct ionic_rx_filter *ionic_rx_filter_by_addr(struct ionic_lif *lif, 195 const u8 *addr) 196 { 197 struct ionic_rx_filter *f; 198 struct hlist_head *head; 199 unsigned int key; 200 201 key = hash_32(*(u32 *)addr, IONIC_RX_FILTER_HASH_BITS); 202 head = &lif->rx_filters.by_hash[key]; 203 204 hlist_for_each_entry(f, head, by_hash) { 205 if (le16_to_cpu(f->cmd.match) != IONIC_RX_FILTER_MATCH_MAC) 206 continue; 207 if (memcmp(addr, f->cmd.mac.addr, ETH_ALEN) == 0) 208 return f; 209 } 210 211 return NULL; 212 } 213