aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-07-21 23:22:52 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-21 23:22:52 -0400
commitbc3bd3f41480d378b12ba6f1c16fd3310815ad1d (patch)
tree1a67ff907fb9a2ba706d692e3bc25505a689c1cb
parent1042cab8627a2d11491e8b0dd40c4dda3180285a (diff)
parent3762ff8f0e95f50f78d94e3f62e839103d1303aa (diff)
Merge branch 'enic-next'
Govindarajulu Varadarajan says: ==================== enic: Display classifier filters using ethtool This series adds ethtool support to show classifier filters added by driver. v2: The patch 1/2 removes the $ifdef's around the filter structure. Making it available always. So that .get_rxnfc() can be implimented without any #ifdefs ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/cisco/enic/enic.h5
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_clsf.c87
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_clsf.h23
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_ethtool.c98
4 files changed, 168 insertions, 45 deletions
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index 4ecbbb3c024a..962510f391df 100644
--- a/drivers/net/ethernet/cisco/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h
@@ -99,7 +99,6 @@ struct enic_port_profile {
99 u8 mac_addr[ETH_ALEN]; 99 u8 mac_addr[ETH_ALEN];
100}; 100};
101 101
102#ifdef CONFIG_RFS_ACCEL
103/* enic_rfs_fltr_node - rfs filter node in hash table 102/* enic_rfs_fltr_node - rfs filter node in hash table
104 * @@keys: IPv4 5 tuple 103 * @@keys: IPv4 5 tuple
105 * @flow_id: flow_id of clsf filter provided by kernel 104 * @flow_id: flow_id of clsf filter provided by kernel
@@ -135,8 +134,6 @@ struct enic_rfs_flw_tbl {
135 struct timer_list rfs_may_expire; 134 struct timer_list rfs_may_expire;
136}; 135};
137 136
138#endif /* CONFIG_RFS_ACCEL */
139
140/* Per-instance private data structure */ 137/* Per-instance private data structure */
141struct enic { 138struct enic {
142 struct net_device *netdev; 139 struct net_device *netdev;
@@ -188,9 +185,7 @@ struct enic {
188 /* completion queue cache line section */ 185 /* completion queue cache line section */
189 ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX]; 186 ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX];
190 unsigned int cq_count; 187 unsigned int cq_count;
191#ifdef CONFIG_RFS_ACCEL
192 struct enic_rfs_flw_tbl rfs_h; 188 struct enic_rfs_flw_tbl rfs_h;
193#endif
194}; 189};
195 190
196static inline struct device *enic_get_dev(struct enic *enic) 191static inline struct device *enic_get_dev(struct enic *enic)
diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c
index bc451baac4cd..69dfd3c9e529 100644
--- a/drivers/net/ethernet/cisco/enic/enic_clsf.c
+++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c
@@ -65,37 +65,6 @@ int enic_delfltr(struct enic *enic, u16 filter_id)
65 return ret; 65 return ret;
66} 66}
67 67
68#ifdef CONFIG_RFS_ACCEL
69void enic_flow_may_expire(unsigned long data)
70{
71 struct enic *enic = (struct enic *)data;
72 bool res;
73 int j;
74
75 spin_lock(&enic->rfs_h.lock);
76 for (j = 0; j < ENIC_CLSF_EXPIRE_COUNT; j++) {
77 struct hlist_head *hhead;
78 struct hlist_node *tmp;
79 struct enic_rfs_fltr_node *n;
80
81 hhead = &enic->rfs_h.ht_head[enic->rfs_h.toclean++];
82 hlist_for_each_entry_safe(n, tmp, hhead, node) {
83 res = rps_may_expire_flow(enic->netdev, n->rq_id,
84 n->flow_id, n->fltr_id);
85 if (res) {
86 res = enic_delfltr(enic, n->fltr_id);
87 if (unlikely(res))
88 continue;
89 hlist_del(&n->node);
90 kfree(n);
91 enic->rfs_h.free++;
92 }
93 }
94 }
95 spin_unlock(&enic->rfs_h.lock);
96 mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4);
97}
98
99/* enic_rfs_flw_tbl_init - initialize enic->rfs_h members 68/* enic_rfs_flw_tbl_init - initialize enic->rfs_h members
100 * @enic: enic data 69 * @enic: enic data
101 */ 70 */
@@ -109,17 +78,14 @@ void enic_rfs_flw_tbl_init(struct enic *enic)
109 enic->rfs_h.max = enic->config.num_arfs; 78 enic->rfs_h.max = enic->config.num_arfs;
110 enic->rfs_h.free = enic->rfs_h.max; 79 enic->rfs_h.free = enic->rfs_h.max;
111 enic->rfs_h.toclean = 0; 80 enic->rfs_h.toclean = 0;
112 init_timer(&enic->rfs_h.rfs_may_expire); 81 enic_rfs_timer_start(enic);
113 enic->rfs_h.rfs_may_expire.function = enic_flow_may_expire;
114 enic->rfs_h.rfs_may_expire.data = (unsigned long)enic;
115 mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4);
116} 82}
117 83
118void enic_rfs_flw_tbl_free(struct enic *enic) 84void enic_rfs_flw_tbl_free(struct enic *enic)
119{ 85{
120 int i; 86 int i;
121 87
122 del_timer_sync(&enic->rfs_h.rfs_may_expire); 88 enic_rfs_timer_stop(enic);
123 spin_lock(&enic->rfs_h.lock); 89 spin_lock(&enic->rfs_h.lock);
124 enic->rfs_h.free = 0; 90 enic->rfs_h.free = 0;
125 for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) { 91 for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) {
@@ -137,6 +103,55 @@ void enic_rfs_flw_tbl_free(struct enic *enic)
137 spin_unlock(&enic->rfs_h.lock); 103 spin_unlock(&enic->rfs_h.lock);
138} 104}
139 105
106struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id)
107{
108 int i;
109
110 for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) {
111 struct hlist_head *hhead;
112 struct hlist_node *tmp;
113 struct enic_rfs_fltr_node *n;
114
115 hhead = &enic->rfs_h.ht_head[i];
116 hlist_for_each_entry_safe(n, tmp, hhead, node)
117 if (n->fltr_id == fltr_id)
118 return n;
119 }
120
121 return NULL;
122}
123
124#ifdef CONFIG_RFS_ACCEL
125void enic_flow_may_expire(unsigned long data)
126{
127 struct enic *enic = (struct enic *)data;
128 bool res;
129 int j;
130
131 spin_lock(&enic->rfs_h.lock);
132 for (j = 0; j < ENIC_CLSF_EXPIRE_COUNT; j++) {
133 struct hlist_head *hhead;
134 struct hlist_node *tmp;
135 struct enic_rfs_fltr_node *n;
136
137 hhead = &enic->rfs_h.ht_head[enic->rfs_h.toclean++];
138 hlist_for_each_entry_safe(n, tmp, hhead, node) {
139 res = rps_may_expire_flow(enic->netdev, n->rq_id,
140 n->flow_id, n->fltr_id);
141 if (res) {
142 res = enic_delfltr(enic, n->fltr_id);
143 if (unlikely(res))
144 continue;
145 hlist_del(&n->node);
146 kfree(n);
147 enic->rfs_h.free++;
148 }
149 }
150 }
151 spin_unlock(&enic->rfs_h.lock);
152 mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4);
153}
154
140static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h, 155static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h,
141 struct flow_keys *k) 156 struct flow_keys *k)
142{ 157{
diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.h b/drivers/net/ethernet/cisco/enic/enic_clsf.h
index d572704cd117..6aa9f89d073b 100644
--- a/drivers/net/ethernet/cisco/enic/enic_clsf.h
+++ b/drivers/net/ethernet/cisco/enic/enic_clsf.h
@@ -8,15 +8,30 @@
8 8
9int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq); 9int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq);
10int enic_delfltr(struct enic *enic, u16 filter_id); 10int enic_delfltr(struct enic *enic, u16 filter_id);
11
12#ifdef CONFIG_RFS_ACCEL
13void enic_rfs_flw_tbl_init(struct enic *enic); 11void enic_rfs_flw_tbl_init(struct enic *enic);
14void enic_rfs_flw_tbl_free(struct enic *enic); 12void enic_rfs_flw_tbl_free(struct enic *enic);
13struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id);
14
15#ifdef CONFIG_RFS_ACCEL
15int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, 16int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
16 u16 rxq_index, u32 flow_id); 17 u16 rxq_index, u32 flow_id);
18void enic_flow_may_expire(unsigned long data);
19
20static inline void enic_rfs_timer_start(struct enic *enic)
21{
22 init_timer(&enic->rfs_h.rfs_may_expire);
23 enic->rfs_h.rfs_may_expire.function = enic_flow_may_expire;
24 enic->rfs_h.rfs_may_expire.data = (unsigned long)enic;
25 mod_timer(&enic->rfs_h.rfs_may_expire, jiffies + HZ/4);
26}
27
28static inline void enic_rfs_timer_stop(struct enic *enic)
29{
30 del_timer_sync(&enic->rfs_h.rfs_may_expire);
31}
17#else 32#else
18static inline void enic_rfs_flw_tbl_init(struct enic *enic) {} 33static inline void enic_rfs_timer_start(struct enic *enic) {}
19static inline void enic_rfs_flw_tbl_free(struct enic *enic) {} 34static inline void enic_rfs_timer_stop(struct enic *enic) {}
20#endif /* CONFIG_RFS_ACCEL */ 35#endif /* CONFIG_RFS_ACCEL */
21 36
22#endif /* _ENIC_CLSF_H_ */ 37#endif /* _ENIC_CLSF_H_ */
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
index c75f84b42751..523c9ceb04c0 100644
--- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -22,6 +22,7 @@
22#include "enic_res.h" 22#include "enic_res.h"
23#include "enic.h" 23#include "enic.h"
24#include "enic_dev.h" 24#include "enic_dev.h"
25#include "enic_clsf.h"
25 26
26struct enic_stat { 27struct enic_stat {
27 char name[ETH_GSTRING_LEN]; 28 char name[ETH_GSTRING_LEN];
@@ -282,6 +283,102 @@ static int enic_set_coalesce(struct net_device *netdev,
282 return 0; 283 return 0;
283} 284}
284 285
286static int enic_grxclsrlall(struct enic *enic, struct ethtool_rxnfc *cmd,
287 u32 *rule_locs)
288{
289 int j, ret = 0, cnt = 0;
290
291 cmd->data = enic->rfs_h.max - enic->rfs_h.free;
292 for (j = 0; j < (1 << ENIC_RFS_FLW_BITSHIFT); j++) {
293 struct hlist_head *hhead;
294 struct hlist_node *tmp;
295 struct enic_rfs_fltr_node *n;
296
297 hhead = &enic->rfs_h.ht_head[j];
298 hlist_for_each_entry_safe(n, tmp, hhead, node) {
299 if (cnt == cmd->rule_cnt)
300 return -EMSGSIZE;
301 rule_locs[cnt] = n->fltr_id;
302 cnt++;
303 }
304 }
305 cmd->rule_cnt = cnt;
306
307 return ret;
308}
309
310static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd)
311{
312 struct ethtool_rx_flow_spec *fsp =
313 (struct ethtool_rx_flow_spec *)&cmd->fs;
314 struct enic_rfs_fltr_node *n;
315
316 n = htbl_fltr_search(enic, (u16)fsp->location);
317 if (!n)
318 return -EINVAL;
319 switch (n->keys.ip_proto) {
320 case IPPROTO_TCP:
321 fsp->flow_type = TCP_V4_FLOW;
322 break;
323 case IPPROTO_UDP:
324 fsp->flow_type = UDP_V4_FLOW;
325 break;
326 default:
327 return -EINVAL;
328 break;
329 }
330
331 fsp->h_u.tcp_ip4_spec.ip4src = n->keys.src;
332 fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0;
333
334 fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.dst;
335 fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0;
336
337 fsp->h_u.tcp_ip4_spec.psrc = n->keys.port16[0];
338 fsp->m_u.tcp_ip4_spec.psrc = (__u16)~0;
339
340 fsp->h_u.tcp_ip4_spec.pdst = n->keys.port16[1];
341 fsp->m_u.tcp_ip4_spec.pdst = (__u16)~0;
342
343 fsp->ring_cookie = n->rq_id;
344
345 return 0;
346}
347
348static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
349 u32 *rule_locs)
350{
351 struct enic *enic = netdev_priv(dev);
352 int ret = 0;
353
354 switch (cmd->cmd) {
355 case ETHTOOL_GRXRINGS:
356 cmd->data = enic->rq_count;
357 break;
358 case ETHTOOL_GRXCLSRLCNT:
359 spin_lock_bh(&enic->rfs_h.lock);
360 cmd->rule_cnt = enic->rfs_h.max - enic->rfs_h.free;
361 cmd->data = enic->rfs_h.max;
362 spin_unlock_bh(&enic->rfs_h.lock);
363 break;
364 case ETHTOOL_GRXCLSRLALL:
365 spin_lock_bh(&enic->rfs_h.lock);
366 ret = enic_grxclsrlall(enic, cmd, rule_locs);
367 spin_unlock_bh(&enic->rfs_h.lock);
368 break;
369 case ETHTOOL_GRXCLSRULE:
370 spin_lock_bh(&enic->rfs_h.lock);
371 ret = enic_grxclsrule(enic, cmd);
372 spin_unlock_bh(&enic->rfs_h.lock);
373 break;
374 default:
375 ret = -EOPNOTSUPP;
376 break;
377 }
378
379 return ret;
380}
381
285static const struct ethtool_ops enic_ethtool_ops = { 382static const struct ethtool_ops enic_ethtool_ops = {
286 .get_settings = enic_get_settings, 383 .get_settings = enic_get_settings,
287 .get_drvinfo = enic_get_drvinfo, 384 .get_drvinfo = enic_get_drvinfo,
@@ -293,6 +390,7 @@ static const struct ethtool_ops enic_ethtool_ops = {
293 .get_ethtool_stats = enic_get_ethtool_stats, 390 .get_ethtool_stats = enic_get_ethtool_stats,
294 .get_coalesce = enic_get_coalesce, 391 .get_coalesce = enic_get_coalesce,
295 .set_coalesce = enic_set_coalesce, 392 .set_coalesce = enic_set_coalesce,
393 .get_rxnfc = enic_get_rxnfc,
296}; 394};
297 395
298void enic_set_ethtool_ops(struct net_device *netdev) 396void enic_set_ethtool_ops(struct net_device *netdev)