diff options
author | David S. Miller <davem@davemloft.net> | 2014-07-21 23:22:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-21 23:22:52 -0400 |
commit | bc3bd3f41480d378b12ba6f1c16fd3310815ad1d (patch) | |
tree | 1a67ff907fb9a2ba706d692e3bc25505a689c1cb | |
parent | 1042cab8627a2d11491e8b0dd40c4dda3180285a (diff) | |
parent | 3762ff8f0e95f50f78d94e3f62e839103d1303aa (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.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/cisco/enic/enic_clsf.c | 87 | ||||
-rw-r--r-- | drivers/net/ethernet/cisco/enic/enic_clsf.h | 23 | ||||
-rw-r--r-- | drivers/net/ethernet/cisco/enic/enic_ethtool.c | 98 |
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 */ |
141 | struct enic { | 138 | struct 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 | ||
196 | static inline struct device *enic_get_dev(struct enic *enic) | 191 | static 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 | ||
69 | void 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 | ||
118 | void enic_rfs_flw_tbl_free(struct enic *enic) | 84 | void 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 | ||
106 | struct 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 | ||
125 | void 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 | |||
140 | static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h, | 155 | static 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 | ||
9 | int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq); | 9 | int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq); |
10 | int enic_delfltr(struct enic *enic, u16 filter_id); | 10 | int enic_delfltr(struct enic *enic, u16 filter_id); |
11 | |||
12 | #ifdef CONFIG_RFS_ACCEL | ||
13 | void enic_rfs_flw_tbl_init(struct enic *enic); | 11 | void enic_rfs_flw_tbl_init(struct enic *enic); |
14 | void enic_rfs_flw_tbl_free(struct enic *enic); | 12 | void enic_rfs_flw_tbl_free(struct enic *enic); |
13 | struct enic_rfs_fltr_node *htbl_fltr_search(struct enic *enic, u16 fltr_id); | ||
14 | |||
15 | #ifdef CONFIG_RFS_ACCEL | ||
15 | int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, | 16 | int 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); |
18 | void enic_flow_may_expire(unsigned long data); | ||
19 | |||
20 | static 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 | |||
28 | static 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 |
18 | static inline void enic_rfs_flw_tbl_init(struct enic *enic) {} | 33 | static inline void enic_rfs_timer_start(struct enic *enic) {} |
19 | static inline void enic_rfs_flw_tbl_free(struct enic *enic) {} | 34 | static 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 | ||
26 | struct enic_stat { | 27 | struct 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 | ||
286 | static 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 | |||
310 | static 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 | |||
348 | static 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 | |||
285 | static const struct ethtool_ops enic_ethtool_ops = { | 382 | static 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 | ||
298 | void enic_set_ethtool_ops(struct net_device *netdev) | 396 | void enic_set_ethtool_ops(struct net_device *netdev) |