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 ionic_admin_ctx ctx; 25 struct ionic_rx_filter *f; 26 struct hlist_head *head; 27 struct hlist_node *tmp; 28 unsigned int i; 29 int err; 30 31 ac = &ctx.cmd.rx_filter_add; 32 33 for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { 34 head = &lif->rx_filters.by_id[i]; 35 hlist_for_each_entry_safe(f, tmp, head, by_id) { 36 ctx.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work); 37 memcpy(ac, &f->cmd, sizeof(f->cmd)); 38 dev_dbg(&lif->netdev->dev, "replay filter command:\n"); 39 dynamic_hex_dump("cmd ", DUMP_PREFIX_OFFSET, 16, 1, 40 &ctx.cmd, sizeof(ctx.cmd), true); 41 42 err = ionic_adminq_post_wait(lif, &ctx); 43 if (err) { 44 switch (le16_to_cpu(ac->match)) { 45 case IONIC_RX_FILTER_MATCH_VLAN: 46 netdev_info(lif->netdev, "Replay failed - %d: vlan %d\n", 47 err, 48 le16_to_cpu(ac->vlan.vlan)); 49 break; 50 case IONIC_RX_FILTER_MATCH_MAC: 51 netdev_info(lif->netdev, "Replay failed - %d: mac %pM\n", 52 err, ac->mac.addr); 53 break; 54 case IONIC_RX_FILTER_MATCH_MAC_VLAN: 55 netdev_info(lif->netdev, "Replay failed - %d: vlan %d mac %pM\n", 56 err, 57 le16_to_cpu(ac->vlan.vlan), 58 ac->mac.addr); 59 break; 60 } 61 } 62 } 63 } 64 } 65 66 int ionic_rx_filters_init(struct ionic_lif *lif) 67 { 68 unsigned int i; 69 70 spin_lock_init(&lif->rx_filters.lock); 71 72 for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { 73 INIT_HLIST_HEAD(&lif->rx_filters.by_hash[i]); 74 INIT_HLIST_HEAD(&lif->rx_filters.by_id[i]); 75 } 76 77 return 0; 78 } 79 80 void ionic_rx_filters_deinit(struct ionic_lif *lif) 81 { 82 struct ionic_rx_filter *f; 83 struct hlist_head *head; 84 struct hlist_node *tmp; 85 unsigned int i; 86 87 for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { 88 head = &lif->rx_filters.by_id[i]; 89 hlist_for_each_entry_safe(f, tmp, head, by_id) 90 ionic_rx_filter_free(lif, f); 91 } 92 } 93 94 int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index, 95 u32 hash, struct ionic_admin_ctx *ctx) 96 { 97 struct device *dev = lif->ionic->dev; 98 struct ionic_rx_filter_add_cmd *ac; 99 struct ionic_rx_filter *f; 100 struct hlist_head *head; 101 unsigned int key; 102 103 ac = &ctx->cmd.rx_filter_add; 104 105 switch (le16_to_cpu(ac->match)) { 106 case IONIC_RX_FILTER_MATCH_VLAN: 107 key = le16_to_cpu(ac->vlan.vlan); 108 break; 109 case IONIC_RX_FILTER_MATCH_MAC: 110 key = *(u32 *)ac->mac.addr; 111 break; 112 case IONIC_RX_FILTER_MATCH_MAC_VLAN: 113 key = le16_to_cpu(ac->mac_vlan.vlan); 114 break; 115 default: 116 return -EINVAL; 117 } 118 119 f = devm_kzalloc(dev, sizeof(*f), GFP_KERNEL); 120 if (!f) 121 return -ENOMEM; 122 123 f->flow_id = flow_id; 124 f->filter_id = le32_to_cpu(ctx->comp.rx_filter_add.filter_id); 125 f->rxq_index = rxq_index; 126 memcpy(&f->cmd, ac, sizeof(f->cmd)); 127 128 INIT_HLIST_NODE(&f->by_hash); 129 INIT_HLIST_NODE(&f->by_id); 130 131 spin_lock_bh(&lif->rx_filters.lock); 132 133 key = hash_32(key, IONIC_RX_FILTER_HASH_BITS); 134 head = &lif->rx_filters.by_hash[key]; 135 hlist_add_head(&f->by_hash, head); 136 137 key = f->filter_id & IONIC_RX_FILTER_HLISTS_MASK; 138 head = &lif->rx_filters.by_id[key]; 139 hlist_add_head(&f->by_id, head); 140 141 spin_unlock_bh(&lif->rx_filters.lock); 142 143 return 0; 144 } 145 146 struct ionic_rx_filter *ionic_rx_filter_by_vlan(struct ionic_lif *lif, u16 vid) 147 { 148 struct ionic_rx_filter *f; 149 struct hlist_head *head; 150 unsigned int key; 151 152 key = hash_32(vid, IONIC_RX_FILTER_HASH_BITS); 153 head = &lif->rx_filters.by_hash[key]; 154 155 hlist_for_each_entry(f, head, by_hash) { 156 if (le16_to_cpu(f->cmd.match) != IONIC_RX_FILTER_MATCH_VLAN) 157 continue; 158 if (le16_to_cpu(f->cmd.vlan.vlan) == vid) 159 return f; 160 } 161 162 return NULL; 163 } 164 165 struct ionic_rx_filter *ionic_rx_filter_by_addr(struct ionic_lif *lif, 166 const u8 *addr) 167 { 168 struct ionic_rx_filter *f; 169 struct hlist_head *head; 170 unsigned int key; 171 172 key = hash_32(*(u32 *)addr, IONIC_RX_FILTER_HASH_BITS); 173 head = &lif->rx_filters.by_hash[key]; 174 175 hlist_for_each_entry(f, head, by_hash) { 176 if (le16_to_cpu(f->cmd.match) != IONIC_RX_FILTER_MATCH_MAC) 177 continue; 178 if (memcmp(addr, f->cmd.mac.addr, ETH_ALEN) == 0) 179 return f; 180 } 181 182 return NULL; 183 } 184