2 * This file is part of the Chelsio T4 Ethernet driver for Linux.
3 * Copyright (C) 2003-2014 Chelsio Communications. All rights reserved.
5 * Written by Deepak (deepak.s@chelsio.com)
7 * This program is distributed in the hope that it will be useful, but WITHOUT
8 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this
10 * release for licensing terms and conditions.
13 #include <linux/module.h>
14 #include <linux/netdevice.h>
15 #include <linux/jhash.h>
16 #include <linux/if_vlan.h>
17 #include <net/addrconf.h>
21 static inline unsigned int ipv4_clip_hash(struct clip_tbl
*c
, const u32
*key
)
23 unsigned int clipt_size_half
= c
->clipt_size
/ 2;
25 return jhash_1word(*key
, 0) % clipt_size_half
;
28 static inline unsigned int ipv6_clip_hash(struct clip_tbl
*d
, const u32
*key
)
30 unsigned int clipt_size_half
= d
->clipt_size
/ 2;
31 u32
xor = key
[0] ^ key
[1] ^ key
[2] ^ key
[3];
33 return clipt_size_half
+
34 (jhash_1word(xor, 0) % clipt_size_half
);
37 static unsigned int clip_addr_hash(struct clip_tbl
*ctbl
, const u32
*addr
,
40 return v6
? ipv6_clip_hash(ctbl
, addr
) :
41 ipv4_clip_hash(ctbl
, addr
);
44 static int clip6_get_mbox(const struct net_device
*dev
,
45 const struct in6_addr
*lip
)
47 struct adapter
*adap
= netdev2adap(dev
);
50 memset(&c
, 0, sizeof(c
));
51 c
.op_to_write
= htonl(FW_CMD_OP_V(FW_CLIP_CMD
) |
52 FW_CMD_REQUEST_F
| FW_CMD_WRITE_F
);
53 c
.alloc_to_len16
= htonl(FW_CLIP_CMD_ALLOC_F
| FW_LEN16(c
));
54 *(__be64
*)&c
.ip_hi
= *(__be64
*)(lip
->s6_addr
);
55 *(__be64
*)&c
.ip_lo
= *(__be64
*)(lip
->s6_addr
+ 8);
56 return t4_wr_mbox_meat(adap
, adap
->mbox
, &c
, sizeof(c
), &c
, false);
59 static int clip6_release_mbox(const struct net_device
*dev
,
60 const struct in6_addr
*lip
)
62 struct adapter
*adap
= netdev2adap(dev
);
65 memset(&c
, 0, sizeof(c
));
66 c
.op_to_write
= htonl(FW_CMD_OP_V(FW_CLIP_CMD
) |
67 FW_CMD_REQUEST_F
| FW_CMD_READ_F
);
68 c
.alloc_to_len16
= htonl(FW_CLIP_CMD_FREE_F
| FW_LEN16(c
));
69 *(__be64
*)&c
.ip_hi
= *(__be64
*)(lip
->s6_addr
);
70 *(__be64
*)&c
.ip_lo
= *(__be64
*)(lip
->s6_addr
+ 8);
71 return t4_wr_mbox_meat(adap
, adap
->mbox
, &c
, sizeof(c
), &c
, false);
74 int cxgb4_clip_get(const struct net_device
*dev
, const u32
*lip
, u8 v6
)
76 struct adapter
*adap
= netdev2adap(dev
);
77 struct clip_tbl
*ctbl
= adap
->clipt
;
78 struct clip_entry
*ce
, *cte
;
79 u32
*addr
= (u32
*)lip
;
86 hash
= clip_addr_hash(ctbl
, addr
, v6
);
88 read_lock_bh(&ctbl
->lock
);
89 list_for_each_entry(cte
, &ctbl
->hash_list
[hash
], list
) {
90 if (cte
->addr6
.sin6_family
== AF_INET6
&& v6
)
91 ret
= memcmp(lip
, cte
->addr6
.sin6_addr
.s6_addr
,
92 sizeof(struct in6_addr
));
93 else if (cte
->addr
.sin_family
== AF_INET
&& !v6
)
94 ret
= memcmp(lip
, (char *)(&cte
->addr
.sin_addr
),
95 sizeof(struct in_addr
));
98 read_unlock_bh(&ctbl
->lock
);
99 refcount_inc(&ce
->refcnt
);
103 read_unlock_bh(&ctbl
->lock
);
105 write_lock_bh(&ctbl
->lock
);
106 if (!list_empty(&ctbl
->ce_free_head
)) {
107 ce
= list_first_entry(&ctbl
->ce_free_head
,
108 struct clip_entry
, list
);
110 INIT_LIST_HEAD(&ce
->list
);
111 spin_lock_init(&ce
->lock
);
112 refcount_set(&ce
->refcnt
, 0);
113 atomic_dec(&ctbl
->nfree
);
114 list_add_tail(&ce
->list
, &ctbl
->hash_list
[hash
]);
116 ce
->addr6
.sin6_family
= AF_INET6
;
117 memcpy(ce
->addr6
.sin6_addr
.s6_addr
,
118 lip
, sizeof(struct in6_addr
));
119 ret
= clip6_get_mbox(dev
, (const struct in6_addr
*)lip
);
121 write_unlock_bh(&ctbl
->lock
);
122 dev_err(adap
->pdev_dev
,
123 "CLIP FW cmd failed with error %d, "
124 "Connections using %pI6c wont be "
126 ret
, ce
->addr6
.sin6_addr
.s6_addr
);
130 ce
->addr
.sin_family
= AF_INET
;
131 memcpy((char *)(&ce
->addr
.sin_addr
), lip
,
132 sizeof(struct in_addr
));
135 write_unlock_bh(&ctbl
->lock
);
136 dev_info(adap
->pdev_dev
, "CLIP table overflow, "
137 "Connections using %pI6c wont be offloaded",
141 write_unlock_bh(&ctbl
->lock
);
142 refcount_set(&ce
->refcnt
, 1);
145 EXPORT_SYMBOL(cxgb4_clip_get
);
147 void cxgb4_clip_release(const struct net_device
*dev
, const u32
*lip
, u8 v6
)
149 struct adapter
*adap
= netdev2adap(dev
);
150 struct clip_tbl
*ctbl
= adap
->clipt
;
151 struct clip_entry
*ce
, *cte
;
152 u32
*addr
= (u32
*)lip
;
159 hash
= clip_addr_hash(ctbl
, addr
, v6
);
161 read_lock_bh(&ctbl
->lock
);
162 list_for_each_entry(cte
, &ctbl
->hash_list
[hash
], list
) {
163 if (cte
->addr6
.sin6_family
== AF_INET6
&& v6
)
164 ret
= memcmp(lip
, cte
->addr6
.sin6_addr
.s6_addr
,
165 sizeof(struct in6_addr
));
166 else if (cte
->addr
.sin_family
== AF_INET
&& !v6
)
167 ret
= memcmp(lip
, (char *)(&cte
->addr
.sin_addr
),
168 sizeof(struct in_addr
));
171 read_unlock_bh(&ctbl
->lock
);
175 read_unlock_bh(&ctbl
->lock
);
179 write_lock_bh(&ctbl
->lock
);
180 spin_lock_bh(&ce
->lock
);
181 if (refcount_dec_and_test(&ce
->refcnt
)) {
183 INIT_LIST_HEAD(&ce
->list
);
184 list_add_tail(&ce
->list
, &ctbl
->ce_free_head
);
185 atomic_inc(&ctbl
->nfree
);
187 clip6_release_mbox(dev
, (const struct in6_addr
*)lip
);
189 spin_unlock_bh(&ce
->lock
);
190 write_unlock_bh(&ctbl
->lock
);
192 EXPORT_SYMBOL(cxgb4_clip_release
);
194 /* Retrieves IPv6 addresses from a root device (bond, vlan) associated with
196 * The physical device reference is needed to send the actul CLIP command.
198 static int cxgb4_update_dev_clip(struct net_device
*root_dev
,
199 struct net_device
*dev
)
201 struct inet6_dev
*idev
= NULL
;
202 struct inet6_ifaddr
*ifa
;
205 idev
= __in6_dev_get(root_dev
);
209 read_lock_bh(&idev
->lock
);
210 list_for_each_entry(ifa
, &idev
->addr_list
, if_list
) {
211 ret
= cxgb4_clip_get(dev
, (const u32
*)ifa
->addr
.s6_addr
, 1);
215 read_unlock_bh(&idev
->lock
);
220 int cxgb4_update_root_dev_clip(struct net_device
*dev
)
222 struct net_device
*root_dev
= NULL
;
225 /* First populate the real net device's IPv6 addresses */
226 ret
= cxgb4_update_dev_clip(dev
, dev
);
230 /* Parse all bond and vlan devices layered on top of the physical dev */
231 root_dev
= netdev_master_upper_dev_get_rcu(dev
);
233 ret
= cxgb4_update_dev_clip(root_dev
, dev
);
238 for (i
= 0; i
< VLAN_N_VID
; i
++) {
239 root_dev
= __vlan_find_dev_deep_rcu(dev
, htons(ETH_P_8021Q
), i
);
243 ret
= cxgb4_update_dev_clip(root_dev
, dev
);
250 EXPORT_SYMBOL(cxgb4_update_root_dev_clip
);
252 int clip_tbl_show(struct seq_file
*seq
, void *v
)
254 struct adapter
*adapter
= seq
->private;
255 struct clip_tbl
*ctbl
= adapter
->clipt
;
256 struct clip_entry
*ce
;
260 read_lock_bh(&ctbl
->lock
);
262 seq_puts(seq
, "IP Address Users\n");
263 for (i
= 0 ; i
< ctbl
->clipt_size
; ++i
) {
264 list_for_each_entry(ce
, &ctbl
->hash_list
[i
], list
) {
266 sprintf(ip
, "%pISc", &ce
->addr
);
267 seq_printf(seq
, "%-25s %u\n", ip
,
268 refcount_read(&ce
->refcnt
));
271 seq_printf(seq
, "Free clip entries : %d\n", atomic_read(&ctbl
->nfree
));
273 read_unlock_bh(&ctbl
->lock
);
278 struct clip_tbl
*t4_init_clip_tbl(unsigned int clipt_start
,
279 unsigned int clipt_end
)
281 struct clip_entry
*cl_list
;
282 struct clip_tbl
*ctbl
;
283 unsigned int clipt_size
;
286 if (clipt_start
>= clipt_end
)
288 clipt_size
= clipt_end
- clipt_start
+ 1;
289 if (clipt_size
< CLIPT_MIN_HASH_BUCKETS
)
292 ctbl
= kvzalloc(struct_size(ctbl
, hash_list
, clipt_size
), GFP_KERNEL
);
296 ctbl
->clipt_start
= clipt_start
;
297 ctbl
->clipt_size
= clipt_size
;
298 INIT_LIST_HEAD(&ctbl
->ce_free_head
);
300 atomic_set(&ctbl
->nfree
, clipt_size
);
301 rwlock_init(&ctbl
->lock
);
303 for (i
= 0; i
< ctbl
->clipt_size
; ++i
)
304 INIT_LIST_HEAD(&ctbl
->hash_list
[i
]);
306 cl_list
= kvcalloc(clipt_size
, sizeof(struct clip_entry
), GFP_KERNEL
);
311 ctbl
->cl_list
= (void *)cl_list
;
313 for (i
= 0; i
< clipt_size
; i
++) {
314 INIT_LIST_HEAD(&cl_list
[i
].list
);
315 list_add_tail(&cl_list
[i
].list
, &ctbl
->ce_free_head
);
321 void t4_cleanup_clip_tbl(struct adapter
*adap
)
323 struct clip_tbl
*ctbl
= adap
->clipt
;
327 kvfree(ctbl
->cl_list
);
331 EXPORT_SYMBOL(t4_cleanup_clip_tbl
);