pinctrl: qcom: Handle broken/missing PDC dual edge IRQs on sc7180
[linux-2.6-microblaze.git] / drivers / net / ethernet / pensando / ionic / ionic_rx_filter.c
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 }