Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/caif/caif_dev.c
15109 views
1
/*
2
* CAIF Interface registration.
3
* Copyright (C) ST-Ericsson AB 2010
4
* Author: Sjur Brendeland/[email protected]
5
* License terms: GNU General Public License (GPL) version 2
6
*
7
* Borrowed heavily from file: pn_dev.c. Thanks to
8
* Remi Denis-Courmont <[email protected]>
9
* and Sakari Ailus <[email protected]>
10
*/
11
12
#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
13
14
#include <linux/version.h>
15
#include <linux/kernel.h>
16
#include <linux/if_arp.h>
17
#include <linux/net.h>
18
#include <linux/netdevice.h>
19
#include <linux/mutex.h>
20
#include <net/netns/generic.h>
21
#include <net/net_namespace.h>
22
#include <net/pkt_sched.h>
23
#include <net/caif/caif_device.h>
24
#include <net/caif/caif_layer.h>
25
#include <net/caif/cfpkt.h>
26
#include <net/caif/cfcnfg.h>
27
28
MODULE_LICENSE("GPL");
29
30
/* Used for local tracking of the CAIF net devices */
31
struct caif_device_entry {
32
struct cflayer layer;
33
struct list_head list;
34
struct net_device *netdev;
35
int __percpu *pcpu_refcnt;
36
};
37
38
struct caif_device_entry_list {
39
struct list_head list;
40
/* Protects simulanous deletes in list */
41
struct mutex lock;
42
};
43
44
struct caif_net {
45
struct cfcnfg *cfg;
46
struct caif_device_entry_list caifdevs;
47
};
48
49
static int caif_net_id;
50
51
struct cfcnfg *get_cfcnfg(struct net *net)
52
{
53
struct caif_net *caifn;
54
BUG_ON(!net);
55
caifn = net_generic(net, caif_net_id);
56
BUG_ON(!caifn);
57
return caifn->cfg;
58
}
59
EXPORT_SYMBOL(get_cfcnfg);
60
61
static struct caif_device_entry_list *caif_device_list(struct net *net)
62
{
63
struct caif_net *caifn;
64
BUG_ON(!net);
65
caifn = net_generic(net, caif_net_id);
66
BUG_ON(!caifn);
67
return &caifn->caifdevs;
68
}
69
70
static void caifd_put(struct caif_device_entry *e)
71
{
72
irqsafe_cpu_dec(*e->pcpu_refcnt);
73
}
74
75
static void caifd_hold(struct caif_device_entry *e)
76
{
77
irqsafe_cpu_inc(*e->pcpu_refcnt);
78
}
79
80
static int caifd_refcnt_read(struct caif_device_entry *e)
81
{
82
int i, refcnt = 0;
83
for_each_possible_cpu(i)
84
refcnt += *per_cpu_ptr(e->pcpu_refcnt, i);
85
return refcnt;
86
}
87
88
/* Allocate new CAIF device. */
89
static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
90
{
91
struct caif_device_entry_list *caifdevs;
92
struct caif_device_entry *caifd;
93
94
caifdevs = caif_device_list(dev_net(dev));
95
BUG_ON(!caifdevs);
96
97
caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC);
98
if (!caifd)
99
return NULL;
100
caifd->pcpu_refcnt = alloc_percpu(int);
101
caifd->netdev = dev;
102
dev_hold(dev);
103
return caifd;
104
}
105
106
static struct caif_device_entry *caif_get(struct net_device *dev)
107
{
108
struct caif_device_entry_list *caifdevs =
109
caif_device_list(dev_net(dev));
110
struct caif_device_entry *caifd;
111
BUG_ON(!caifdevs);
112
list_for_each_entry_rcu(caifd, &caifdevs->list, list) {
113
if (caifd->netdev == dev)
114
return caifd;
115
}
116
return NULL;
117
}
118
119
static int transmit(struct cflayer *layer, struct cfpkt *pkt)
120
{
121
int err;
122
struct caif_device_entry *caifd =
123
container_of(layer, struct caif_device_entry, layer);
124
struct sk_buff *skb;
125
126
skb = cfpkt_tonative(pkt);
127
skb->dev = caifd->netdev;
128
129
err = dev_queue_xmit(skb);
130
if (err > 0)
131
err = -EIO;
132
133
return err;
134
}
135
136
/*
137
* Stuff received packets into the CAIF stack.
138
* On error, returns non-zero and releases the skb.
139
*/
140
static int receive(struct sk_buff *skb, struct net_device *dev,
141
struct packet_type *pkttype, struct net_device *orig_dev)
142
{
143
struct cfpkt *pkt;
144
struct caif_device_entry *caifd;
145
int err;
146
147
pkt = cfpkt_fromnative(CAIF_DIR_IN, skb);
148
149
rcu_read_lock();
150
caifd = caif_get(dev);
151
152
if (!caifd || !caifd->layer.up || !caifd->layer.up->receive ||
153
!netif_oper_up(caifd->netdev)) {
154
rcu_read_unlock();
155
kfree_skb(skb);
156
return NET_RX_DROP;
157
}
158
159
/* Hold reference to netdevice while using CAIF stack */
160
caifd_hold(caifd);
161
rcu_read_unlock();
162
163
err = caifd->layer.up->receive(caifd->layer.up, pkt);
164
165
/* For -EILSEQ the packet is not freed so so it now */
166
if (err == -EILSEQ)
167
cfpkt_destroy(pkt);
168
169
/* Release reference to stack upwards */
170
caifd_put(caifd);
171
return 0;
172
}
173
174
static struct packet_type caif_packet_type __read_mostly = {
175
.type = cpu_to_be16(ETH_P_CAIF),
176
.func = receive,
177
};
178
179
static void dev_flowctrl(struct net_device *dev, int on)
180
{
181
struct caif_device_entry *caifd;
182
183
rcu_read_lock();
184
185
caifd = caif_get(dev);
186
if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) {
187
rcu_read_unlock();
188
return;
189
}
190
191
caifd_hold(caifd);
192
rcu_read_unlock();
193
194
caifd->layer.up->ctrlcmd(caifd->layer.up,
195
on ?
196
_CAIF_CTRLCMD_PHYIF_FLOW_ON_IND :
197
_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
198
caifd->layer.id);
199
caifd_put(caifd);
200
}
201
202
/* notify Caif of device events */
203
static int caif_device_notify(struct notifier_block *me, unsigned long what,
204
void *arg)
205
{
206
struct net_device *dev = arg;
207
struct caif_device_entry *caifd = NULL;
208
struct caif_dev_common *caifdev;
209
enum cfcnfg_phy_preference pref;
210
enum cfcnfg_phy_type phy_type;
211
struct cfcnfg *cfg;
212
struct caif_device_entry_list *caifdevs =
213
caif_device_list(dev_net(dev));
214
215
if (dev->type != ARPHRD_CAIF)
216
return 0;
217
218
cfg = get_cfcnfg(dev_net(dev));
219
if (cfg == NULL)
220
return 0;
221
222
switch (what) {
223
case NETDEV_REGISTER:
224
caifd = caif_device_alloc(dev);
225
if (!caifd)
226
return 0;
227
228
caifdev = netdev_priv(dev);
229
caifdev->flowctrl = dev_flowctrl;
230
231
caifd->layer.transmit = transmit;
232
233
if (caifdev->use_frag)
234
phy_type = CFPHYTYPE_FRAG;
235
else
236
phy_type = CFPHYTYPE_CAIF;
237
238
switch (caifdev->link_select) {
239
case CAIF_LINK_HIGH_BANDW:
240
pref = CFPHYPREF_HIGH_BW;
241
break;
242
case CAIF_LINK_LOW_LATENCY:
243
pref = CFPHYPREF_LOW_LAT;
244
break;
245
default:
246
pref = CFPHYPREF_HIGH_BW;
247
break;
248
}
249
strncpy(caifd->layer.name, dev->name,
250
sizeof(caifd->layer.name) - 1);
251
caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;
252
253
mutex_lock(&caifdevs->lock);
254
list_add_rcu(&caifd->list, &caifdevs->list);
255
256
cfcnfg_add_phy_layer(cfg,
257
phy_type,
258
dev,
259
&caifd->layer,
260
pref,
261
caifdev->use_fcs,
262
caifdev->use_stx);
263
mutex_unlock(&caifdevs->lock);
264
break;
265
266
case NETDEV_UP:
267
rcu_read_lock();
268
269
caifd = caif_get(dev);
270
if (caifd == NULL) {
271
rcu_read_unlock();
272
break;
273
}
274
275
cfcnfg_set_phy_state(cfg, &caifd->layer, true);
276
rcu_read_unlock();
277
278
break;
279
280
case NETDEV_DOWN:
281
rcu_read_lock();
282
283
caifd = caif_get(dev);
284
if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) {
285
rcu_read_unlock();
286
return -EINVAL;
287
}
288
289
cfcnfg_set_phy_state(cfg, &caifd->layer, false);
290
caifd_hold(caifd);
291
rcu_read_unlock();
292
293
caifd->layer.up->ctrlcmd(caifd->layer.up,
294
_CAIF_CTRLCMD_PHYIF_DOWN_IND,
295
caifd->layer.id);
296
caifd_put(caifd);
297
break;
298
299
case NETDEV_UNREGISTER:
300
mutex_lock(&caifdevs->lock);
301
302
caifd = caif_get(dev);
303
if (caifd == NULL) {
304
mutex_unlock(&caifdevs->lock);
305
break;
306
}
307
list_del_rcu(&caifd->list);
308
309
/*
310
* NETDEV_UNREGISTER is called repeatedly until all reference
311
* counts for the net-device are released. If references to
312
* caifd is taken, simply ignore NETDEV_UNREGISTER and wait for
313
* the next call to NETDEV_UNREGISTER.
314
*
315
* If any packets are in flight down the CAIF Stack,
316
* cfcnfg_del_phy_layer will return nonzero.
317
* If no packets are in flight, the CAIF Stack associated
318
* with the net-device un-registering is freed.
319
*/
320
321
if (caifd_refcnt_read(caifd) != 0 ||
322
cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0) {
323
324
pr_info("Wait for device inuse\n");
325
/* Enrole device if CAIF Stack is still in use */
326
list_add_rcu(&caifd->list, &caifdevs->list);
327
mutex_unlock(&caifdevs->lock);
328
break;
329
}
330
331
synchronize_rcu();
332
dev_put(caifd->netdev);
333
free_percpu(caifd->pcpu_refcnt);
334
kfree(caifd);
335
336
mutex_unlock(&caifdevs->lock);
337
break;
338
}
339
return 0;
340
}
341
342
static struct notifier_block caif_device_notifier = {
343
.notifier_call = caif_device_notify,
344
.priority = 0,
345
};
346
347
/* Per-namespace Caif devices handling */
348
static int caif_init_net(struct net *net)
349
{
350
struct caif_net *caifn = net_generic(net, caif_net_id);
351
BUG_ON(!caifn);
352
INIT_LIST_HEAD(&caifn->caifdevs.list);
353
mutex_init(&caifn->caifdevs.lock);
354
355
caifn->cfg = cfcnfg_create();
356
if (!caifn->cfg) {
357
pr_warn("can't create cfcnfg\n");
358
return -ENOMEM;
359
}
360
361
return 0;
362
}
363
364
static void caif_exit_net(struct net *net)
365
{
366
struct caif_device_entry *caifd, *tmp;
367
struct caif_device_entry_list *caifdevs =
368
caif_device_list(net);
369
struct cfcnfg *cfg;
370
371
rtnl_lock();
372
mutex_lock(&caifdevs->lock);
373
374
cfg = get_cfcnfg(net);
375
if (cfg == NULL) {
376
mutex_unlock(&caifdevs->lock);
377
return;
378
}
379
380
list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) {
381
int i = 0;
382
list_del_rcu(&caifd->list);
383
cfcnfg_set_phy_state(cfg, &caifd->layer, false);
384
385
while (i < 10 &&
386
(caifd_refcnt_read(caifd) != 0 ||
387
cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0)) {
388
389
pr_info("Wait for device inuse\n");
390
msleep(250);
391
i++;
392
}
393
synchronize_rcu();
394
dev_put(caifd->netdev);
395
free_percpu(caifd->pcpu_refcnt);
396
kfree(caifd);
397
}
398
cfcnfg_remove(cfg);
399
400
mutex_unlock(&caifdevs->lock);
401
rtnl_unlock();
402
}
403
404
static struct pernet_operations caif_net_ops = {
405
.init = caif_init_net,
406
.exit = caif_exit_net,
407
.id = &caif_net_id,
408
.size = sizeof(struct caif_net),
409
};
410
411
/* Initialize Caif devices list */
412
static int __init caif_device_init(void)
413
{
414
int result;
415
416
result = register_pernet_device(&caif_net_ops);
417
418
if (result)
419
return result;
420
421
register_netdevice_notifier(&caif_device_notifier);
422
dev_add_pack(&caif_packet_type);
423
424
return result;
425
}
426
427
static void __exit caif_device_exit(void)
428
{
429
unregister_pernet_device(&caif_net_ops);
430
unregister_netdevice_notifier(&caif_device_notifier);
431
dev_remove_pack(&caif_packet_type);
432
}
433
434
module_init(caif_device_init);
435
module_exit(caif_device_exit);
436
437