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