Blame view
net/caif/cfcnfg.c
14.2 KB
af873fcec
|
1 |
// SPDX-License-Identifier: GPL-2.0-only |
15c9ac0c8
|
2 3 |
/* * Copyright (C) ST-Ericsson AB 2010 |
26ee65e68
|
4 |
* Author: Sjur Brendeland |
15c9ac0c8
|
5 |
*/ |
b31fa5bad
|
6 7 |
#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ |
15c9ac0c8
|
8 9 |
#include <linux/kernel.h> #include <linux/stddef.h> |
6c5799069
|
10 |
#include <linux/slab.h> |
2aa40aef9
|
11 |
#include <linux/netdevice.h> |
f36214408
|
12 |
#include <linux/module.h> |
15c9ac0c8
|
13 14 15 16 17 18 19 20 |
#include <net/caif/caif_layer.h> #include <net/caif/cfpkt.h> #include <net/caif/cfcnfg.h> #include <net/caif/cfctrl.h> #include <net/caif/cfmuxl.h> #include <net/caif/cffrml.h> #include <net/caif/cfserl.h> #include <net/caif/cfsrvl.h> |
f36214408
|
21 |
#include <net/caif/caif_dev.h> |
15c9ac0c8
|
22 23 24 25 26 27 28 |
#define container_obj(layr) container_of(layr, struct cfcnfg, layer) /* Information about CAIF physical interfaces held by Config Module in order * to manage physical interfaces */ struct cfcnfg_phyinfo { |
f36214408
|
29 30 |
struct list_head node; bool up; |
15c9ac0c8
|
31 32 33 34 35 36 37 38 |
/* Pointer to the layer below the MUX (framing layer) */ struct cflayer *frm_layer; /* Pointer to the lowest actual physical layer */ struct cflayer *phy_layer; /* Unique identifier of the physical interface */ unsigned int id; /* Preference of the physical in interface */ enum cfcnfg_phy_preference pref; |
15c9ac0c8
|
39 40 |
/* Information about the physical device */ struct dev_info dev_info; |
2aa40aef9
|
41 42 43 |
/* Interface index */ int ifindex; |
7c18d2205
|
44 45 |
/* Protocol head room added for CAIF link layer */ int head_room; |
2aa40aef9
|
46 47 48 |
/* Use Start of frame checksum */ bool use_fcs; |
15c9ac0c8
|
49 50 51 52 53 54 |
}; struct cfcnfg { struct cflayer layer; struct cflayer *ctrl; struct cflayer *mux; |
f36214408
|
55 56 |
struct list_head phys; struct mutex lock; |
15c9ac0c8
|
57 |
}; |
e539d83cc
|
58 |
static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, |
3bffc475f
|
59 60 |
enum cfctrl_srv serv, u8 phyid, struct cflayer *adapt_layer); |
8d545c8f9
|
61 |
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id); |
e539d83cc
|
62 |
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, |
3bffc475f
|
63 |
struct cflayer *adapt_layer); |
15c9ac0c8
|
64 65 66 67 68 69 70 |
static void cfctrl_resp_func(void); static void cfctrl_enum_resp(void); struct cfcnfg *cfcnfg_create(void) { struct cfcnfg *this; struct cfctrl_rsp *resp; |
f36214408
|
71 72 |
might_sleep(); |
15c9ac0c8
|
73 |
/* Initiate this layer */ |
49afa55b5
|
74 |
this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC); |
7ac2ed0ce
|
75 |
if (!this) |
15c9ac0c8
|
76 |
return NULL; |
15c9ac0c8
|
77 78 79 80 81 82 83 84 85 86 |
this->mux = cfmuxl_create(); if (!this->mux) goto out_of_mem; this->ctrl = cfctrl_create(); if (!this->ctrl) goto out_of_mem; /* Initiate response functions */ resp = cfctrl_get_respfuncs(this->ctrl); resp->enum_rsp = cfctrl_enum_resp; resp->linkerror_ind = cfctrl_resp_func; |
e539d83cc
|
87 |
resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp; |
15c9ac0c8
|
88 89 90 91 |
resp->sleep_rsp = cfctrl_resp_func; resp->wake_rsp = cfctrl_resp_func; resp->restart_rsp = cfctrl_resp_func; resp->radioset_rsp = cfctrl_resp_func; |
e539d83cc
|
92 93 |
resp->linksetup_rsp = cfcnfg_linkup_rsp; resp->reject_rsp = cfcnfg_reject_rsp; |
f36214408
|
94 |
INIT_LIST_HEAD(&this->phys); |
15c9ac0c8
|
95 96 97 98 |
cfmuxl_set_uplayer(this->mux, this->ctrl, 0); layer_set_dn(this->ctrl, this->mux); layer_set_up(this->ctrl, this); |
f36214408
|
99 |
mutex_init(&this->lock); |
15c9ac0c8
|
100 101 |
return this; out_of_mem: |
f36214408
|
102 |
synchronize_rcu(); |
15c9ac0c8
|
103 104 105 106 107 |
kfree(this->mux); kfree(this->ctrl); kfree(this); return NULL; } |
15c9ac0c8
|
108 109 110 |
void cfcnfg_remove(struct cfcnfg *cfg) { |
f36214408
|
111 |
might_sleep(); |
15c9ac0c8
|
112 |
if (cfg) { |
f36214408
|
113 |
synchronize_rcu(); |
15c9ac0c8
|
114 |
kfree(cfg->mux); |
c85c2951d
|
115 |
cfctrl_remove(cfg->ctrl); |
15c9ac0c8
|
116 117 118 119 120 121 122 |
kfree(cfg); } } static void cfctrl_resp_func(void) { } |
f36214408
|
123 |
static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo_rcu(struct cfcnfg *cnfg, |
3bffc475f
|
124 |
u8 phyid) |
f36214408
|
125 126 127 128 129 130 131 132 |
{ struct cfcnfg_phyinfo *phy; list_for_each_entry_rcu(phy, &cnfg->phys, node) if (phy->id == phyid) return phy; return NULL; } |
15c9ac0c8
|
133 134 135 |
static void cfctrl_enum_resp(void) { } |
bee925db9
|
136 |
static struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, |
15c9ac0c8
|
137 138 |
enum cfcnfg_phy_preference phy_pref) { |
15c9ac0c8
|
139 |
/* Try to match with specified preference */ |
f36214408
|
140 141 142 143 144 145 146 |
struct cfcnfg_phyinfo *phy; list_for_each_entry_rcu(phy, &cnfg->phys, node) { if (phy->up && phy->pref == phy_pref && phy->frm_layer != NULL) return &phy->dev_info; |
15c9ac0c8
|
147 |
} |
f36214408
|
148 149 150 151 |
/* Otherwise just return something */ list_for_each_entry_rcu(phy, &cnfg->phys, node) if (phy->up) return &phy->dev_info; |
15c9ac0c8
|
152 |
|
15c9ac0c8
|
153 154 |
return NULL; } |
bee925db9
|
155 |
static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) |
15c9ac0c8
|
156 |
{ |
f36214408
|
157 158 159 160 161 |
struct cfcnfg_phyinfo *phy; list_for_each_entry_rcu(phy, &cnfg->phys, node) if (phy->ifindex == ifi && phy->up) return phy->id; |
f2527ec43
|
162 |
return -ENODEV; |
15c9ac0c8
|
163 |
} |
bee925db9
|
164 |
int caif_disconnect_client(struct net *net, struct cflayer *adap_layer) |
15c9ac0c8
|
165 |
{ |
54e90fb5c
|
166 |
u8 channel_id; |
bee925db9
|
167 |
struct cfcnfg *cfg = get_cfcnfg(net); |
01a859014
|
168 |
|
15c9ac0c8
|
169 |
caif_assert(adap_layer != NULL); |
f36214408
|
170 |
cfctrl_cancel_req(cfg->ctrl, adap_layer); |
54e90fb5c
|
171 172 173 174 |
channel_id = adap_layer->id; if (channel_id != 0) { struct cflayer *servl; servl = cfmuxl_remove_uplayer(cfg->mux, channel_id); |
7c18d2205
|
175 |
cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer); |
54e90fb5c
|
176 177 178 179 180 |
if (servl != NULL) layer_set_up(servl, NULL); } else pr_debug("nothing to disconnect "); |
f36214408
|
181 182 183 |
/* Do RCU sync before initiating cleanup */ synchronize_rcu(); |
8d545c8f9
|
184 185 |
if (adap_layer->ctrlcmd != NULL) adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0); |
54e90fb5c
|
186 |
return 0; |
15c9ac0c8
|
187 188 |
} |
bee925db9
|
189 |
EXPORT_SYMBOL(caif_disconnect_client); |
5b2086567
|
190 |
|
8d545c8f9
|
191 |
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id) |
15c9ac0c8
|
192 |
{ |
15c9ac0c8
|
193 |
} |
73d6ac633
|
194 |
static const int protohead[CFCTRL_SRV_MASK] = { |
2aa40aef9
|
195 196 197 198 199 200 |
[CFCTRL_SRV_VEI] = 4, [CFCTRL_SRV_DATAGRAM] = 7, [CFCTRL_SRV_UTIL] = 4, [CFCTRL_SRV_RFM] = 3, [CFCTRL_SRV_DBG] = 3, }; |
bee925db9
|
201 202 |
static int caif_connect_req_to_link_param(struct cfcnfg *cnfg, |
3bffc475f
|
203 204 |
struct caif_connect_request *s, struct cfctrl_link_param *l) |
bee925db9
|
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
{ struct dev_info *dev_info; enum cfcnfg_phy_preference pref; int res; memset(l, 0, sizeof(*l)); /* In caif protocol low value is high priority */ l->priority = CAIF_PRIO_MAX - s->priority + 1; if (s->ifindex != 0) { res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex); if (res < 0) return res; l->phyid = res; } else { switch (s->link_selector) { case CAIF_LINK_HIGH_BANDW: pref = CFPHYPREF_HIGH_BW; break; case CAIF_LINK_LOW_LATENCY: pref = CFPHYPREF_LOW_LAT; break; default: return -EINVAL; } dev_info = cfcnfg_get_phyid(cnfg, pref); if (dev_info == NULL) return -ENODEV; l->phyid = dev_info->id; } switch (s->protocol) { case CAIFPROTO_AT: l->linktype = CFCTRL_SRV_VEI; l->endpoint = (s->sockaddr.u.at.type >> 2) & 0x3; l->chtype = s->sockaddr.u.at.type & 0x3; break; case CAIFPROTO_DATAGRAM: l->linktype = CFCTRL_SRV_DATAGRAM; l->chtype = 0x00; l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; break; case CAIFPROTO_DATAGRAM_LOOP: l->linktype = CFCTRL_SRV_DATAGRAM; l->chtype = 0x03; l->endpoint = 0x00; l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; break; case CAIFPROTO_RFM: l->linktype = CFCTRL_SRV_RFM; l->u.datagram.connid = s->sockaddr.u.rfm.connection_id; |
3dc2fa475
|
255 256 |
strlcpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume, sizeof(l->u.rfm.volume)); |
bee925db9
|
257 258 259 260 261 |
break; case CAIFPROTO_UTIL: l->linktype = CFCTRL_SRV_UTIL; l->endpoint = 0x00; l->chtype = 0x00; |
3dc2fa475
|
262 263 |
strlcpy(l->u.utility.name, s->sockaddr.u.util.service, sizeof(l->u.utility.name)); |
bee925db9
|
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
caif_assert(sizeof(l->u.utility.name) > 10); l->u.utility.paramlen = s->param.size; if (l->u.utility.paramlen > sizeof(l->u.utility.params)) l->u.utility.paramlen = sizeof(l->u.utility.params); memcpy(l->u.utility.params, s->param.data, l->u.utility.paramlen); break; case CAIFPROTO_DEBUG: l->linktype = CFCTRL_SRV_DBG; l->endpoint = s->sockaddr.u.dbg.service; l->chtype = s->sockaddr.u.dbg.type; break; default: return -EINVAL; } return 0; } int caif_connect_client(struct net *net, struct caif_connect_request *conn_req, struct cflayer *adap_layer, int *ifindex, |
3bffc475f
|
286 |
int *proto_head, int *proto_tail) |
15c9ac0c8
|
287 288 |
{ struct cflayer *frml; |
f36214408
|
289 290 |
struct cfcnfg_phyinfo *phy; int err; |
bee925db9
|
291 292 |
struct cfctrl_link_param param; struct cfcnfg *cfg = get_cfcnfg(net); |
f36214408
|
293 294 |
rcu_read_lock(); |
bee925db9
|
295 296 297 298 299 |
err = caif_connect_req_to_link_param(cfg, conn_req, ¶m); if (err) goto unlock; phy = cfcnfg_get_phyinfo_rcu(cfg, param.phyid); |
f36214408
|
300 301 302 303 304 |
if (!phy) { err = -ENODEV; goto unlock; } err = -EINVAL; |
15c9ac0c8
|
305 |
if (adap_layer == NULL) { |
b31fa5bad
|
306 307 |
pr_err("adap_layer is zero "); |
f36214408
|
308 |
goto unlock; |
15c9ac0c8
|
309 310 |
} if (adap_layer->receive == NULL) { |
b31fa5bad
|
311 312 |
pr_err("adap_layer->receive is NULL "); |
f36214408
|
313 |
goto unlock; |
15c9ac0c8
|
314 315 |
} if (adap_layer->ctrlcmd == NULL) { |
b31fa5bad
|
316 317 |
pr_err("adap_layer->ctrlcmd == NULL "); |
f36214408
|
318 |
goto unlock; |
15c9ac0c8
|
319 |
} |
f36214408
|
320 321 322 |
err = -ENODEV; frml = phy->frm_layer; |
15c9ac0c8
|
323 |
if (frml == NULL) { |
b31fa5bad
|
324 325 |
pr_err("Specified PHY type does not exist! "); |
f36214408
|
326 |
goto unlock; |
15c9ac0c8
|
327 |
} |
bee925db9
|
328 |
caif_assert(param.phyid == phy->id); |
f36214408
|
329 |
caif_assert(phy->frm_layer->id == |
bee925db9
|
330 |
param.phyid); |
f36214408
|
331 |
caif_assert(phy->phy_layer->id == |
bee925db9
|
332 |
param.phyid); |
2aa40aef9
|
333 |
|
f36214408
|
334 335 |
*ifindex = phy->ifindex; *proto_tail = 2; |
7c18d2205
|
336 |
*proto_head = protohead[param.linktype] + phy->head_room; |
2aa40aef9
|
337 |
|
f36214408
|
338 |
rcu_read_unlock(); |
2aa40aef9
|
339 |
|
15c9ac0c8
|
340 |
/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */ |
bee925db9
|
341 342 |
cfctrl_enum_req(cfg->ctrl, param.phyid); return cfctrl_linkup_request(cfg->ctrl, ¶m, adap_layer); |
f36214408
|
343 344 345 346 |
unlock: rcu_read_unlock(); return err; |
15c9ac0c8
|
347 |
} |
bee925db9
|
348 |
EXPORT_SYMBOL(caif_connect_client); |
15c9ac0c8
|
349 |
|
e539d83cc
|
350 |
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, |
3bffc475f
|
351 |
struct cflayer *adapt_layer) |
15c9ac0c8
|
352 353 354 355 356 357 358 |
{ if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL) adapt_layer->ctrlcmd(adapt_layer, CAIF_CTRLCMD_INIT_FAIL_RSP, 0); } static void |
e539d83cc
|
359 |
cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, |
f36214408
|
360 |
u8 phyid, struct cflayer *adapt_layer) |
15c9ac0c8
|
361 362 363 364 |
{ struct cfcnfg *cnfg = container_obj(layer); struct cflayer *servicel = NULL; struct cfcnfg_phyinfo *phyinfo; |
2aa40aef9
|
365 |
struct net_device *netdev; |
54e90fb5c
|
366 367 368 369 370 371 372 373 |
if (channel_id == 0) { pr_warn("received channel_id zero "); if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL) adapt_layer->ctrlcmd(adapt_layer, CAIF_CTRLCMD_INIT_FAIL_RSP, 0); return; } |
f36214408
|
374 |
rcu_read_lock(); |
15c9ac0c8
|
375 |
if (adapt_layer == NULL) { |
b09edbd07
|
376 377 |
pr_debug("link setup response but no client exist, send linkdown back "); |
8d545c8f9
|
378 |
cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL); |
f36214408
|
379 |
goto unlock; |
15c9ac0c8
|
380 381 382 383 |
} caif_assert(cnfg != NULL); caif_assert(phyid != 0); |
f36214408
|
384 385 386 |
phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); if (phyinfo == NULL) { |
b09edbd07
|
387 388 |
pr_err("ERROR: Link Layer Device disappeared while connecting "); |
f36214408
|
389 390 391 392 |
goto unlock; } caif_assert(phyinfo != NULL); |
15c9ac0c8
|
393 394 395 |
caif_assert(phyinfo->id == phyid); caif_assert(phyinfo->phy_layer != NULL); caif_assert(phyinfo->phy_layer->id == phyid); |
e539d83cc
|
396 |
adapt_layer->id = channel_id; |
15c9ac0c8
|
397 398 399 |
switch (serv) { case CFCTRL_SRV_VEI: |
e539d83cc
|
400 |
servicel = cfvei_create(channel_id, &phyinfo->dev_info); |
15c9ac0c8
|
401 402 |
break; case CFCTRL_SRV_DATAGRAM: |
f36214408
|
403 404 |
servicel = cfdgml_create(channel_id, &phyinfo->dev_info); |
15c9ac0c8
|
405 406 |
break; case CFCTRL_SRV_RFM: |
2aa40aef9
|
407 |
netdev = phyinfo->dev_info.dev; |
a7da1f55a
|
408 |
servicel = cfrfml_create(channel_id, &phyinfo->dev_info, |
2aa40aef9
|
409 |
netdev->mtu); |
15c9ac0c8
|
410 411 |
break; case CFCTRL_SRV_UTIL: |
e539d83cc
|
412 |
servicel = cfutill_create(channel_id, &phyinfo->dev_info); |
15c9ac0c8
|
413 414 |
break; case CFCTRL_SRV_VIDEO: |
e539d83cc
|
415 |
servicel = cfvidl_create(channel_id, &phyinfo->dev_info); |
15c9ac0c8
|
416 417 |
break; case CFCTRL_SRV_DBG: |
e539d83cc
|
418 |
servicel = cfdbgl_create(channel_id, &phyinfo->dev_info); |
15c9ac0c8
|
419 420 |
break; default: |
b09edbd07
|
421 422 |
pr_err("Protocol error. Link setup response - unknown channel type "); |
f36214408
|
423 |
goto unlock; |
15c9ac0c8
|
424 |
} |
7ac2ed0ce
|
425 |
if (!servicel) |
f36214408
|
426 |
goto unlock; |
15c9ac0c8
|
427 |
layer_set_dn(servicel, cnfg->mux); |
e539d83cc
|
428 |
cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id); |
15c9ac0c8
|
429 430 |
layer_set_up(servicel, adapt_layer); layer_set_dn(adapt_layer, servicel); |
f36214408
|
431 432 |
rcu_read_unlock(); |
15c9ac0c8
|
433 |
servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0); |
f36214408
|
434 435 436 |
return; unlock: rcu_read_unlock(); |
15c9ac0c8
|
437 438 439 |
} void |
7c18d2205
|
440 |
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, |
2aa40aef9
|
441 |
struct net_device *dev, struct cflayer *phy_layer, |
bee925db9
|
442 |
enum cfcnfg_phy_preference pref, |
7c18d2205
|
443 444 |
struct cflayer *link_support, bool fcs, int head_room) |
15c9ac0c8
|
445 446 |
{ struct cflayer *frml; |
5bb20ed86
|
447 |
struct cfcnfg_phyinfo *phyinfo = NULL; |
15c9ac0c8
|
448 |
int i; |
f36214408
|
449 |
u8 phyid; |
15c9ac0c8
|
450 |
|
f36214408
|
451 |
mutex_lock(&cnfg->lock); |
15c9ac0c8
|
452 |
|
f36214408
|
453 454 455 456 457 458 459 |
/* CAIF protocol allow maximum 6 link-layers */ for (i = 0; i < 7; i++) { phyid = (dev->ifindex + i) & 0x7; if (phyid == 0) continue; if (cfcnfg_get_phyinfo_rcu(cnfg, phyid) == NULL) goto got_phyid; |
15c9ac0c8
|
460 |
} |
f36214408
|
461 462 |
pr_warn("Too many CAIF Link Layers (max 6) "); |
7c18d2205
|
463 |
goto out; |
f36214408
|
464 465 466 |
got_phyid: phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC); |
5bb20ed86
|
467 468 |
if (!phyinfo) goto out_err; |
15c9ac0c8
|
469 |
|
f36214408
|
470 471 472 473 474 475 476 |
phy_layer->id = phyid; phyinfo->pref = pref; phyinfo->id = phyid; phyinfo->dev_info.id = phyid; phyinfo->dev_info.dev = dev; phyinfo->phy_layer = phy_layer; phyinfo->ifindex = dev->ifindex; |
7c18d2205
|
477 |
phyinfo->head_room = head_room; |
f36214408
|
478 |
phyinfo->use_fcs = fcs; |
2aa40aef9
|
479 |
|
f36214408
|
480 |
frml = cffrml_create(phyid, fcs); |
5bb20ed86
|
481 482 |
if (!frml) goto out_err; |
f36214408
|
483 |
phyinfo->frm_layer = frml; |
15c9ac0c8
|
484 |
layer_set_up(frml, cnfg->mux); |
7c18d2205
|
485 486 487 488 489 490 |
if (link_support != NULL) { link_support->id = phyid; layer_set_dn(frml, link_support); layer_set_up(link_support, frml); layer_set_dn(link_support, phy_layer); layer_set_up(phy_layer, link_support); |
15c9ac0c8
|
491 492 493 494 |
} else { layer_set_dn(frml, phy_layer); layer_set_up(phy_layer, frml); } |
f36214408
|
495 496 |
list_add_rcu(&phyinfo->node, &cnfg->phys); |
7c18d2205
|
497 |
out: |
5bb20ed86
|
498 499 500 501 |
mutex_unlock(&cnfg->lock); return; out_err: |
5bb20ed86
|
502 |
kfree(phyinfo); |
f36214408
|
503 |
mutex_unlock(&cnfg->lock); |
15c9ac0c8
|
504 505 |
} EXPORT_SYMBOL(cfcnfg_add_phy_layer); |
f36214408
|
506 |
int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer, |
3bffc475f
|
507 |
bool up) |
f36214408
|
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
{ struct cfcnfg_phyinfo *phyinfo; rcu_read_lock(); phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phy_layer->id); if (phyinfo == NULL) { rcu_read_unlock(); return -ENODEV; } if (phyinfo->up == up) { rcu_read_unlock(); return 0; } phyinfo->up = up; if (up) { cffrml_hold(phyinfo->frm_layer); cfmuxl_set_dnlayer(cnfg->mux, phyinfo->frm_layer, phy_layer->id); } else { cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id); cffrml_put(phyinfo->frm_layer); } rcu_read_unlock(); return 0; } EXPORT_SYMBOL(cfcnfg_set_phy_state); |
15c9ac0c8
|
537 538 539 540 |
int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) { struct cflayer *frml, *frml_dn; u16 phyid; |
f36214408
|
541 542 543 544 545 |
struct cfcnfg_phyinfo *phyinfo; might_sleep(); mutex_lock(&cnfg->lock); |
15c9ac0c8
|
546 |
phyid = phy_layer->id; |
f36214408
|
547 |
phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); |
bee925db9
|
548 549 |
if (phyinfo == NULL) { mutex_unlock(&cnfg->lock); |
f36214408
|
550 |
return 0; |
bee925db9
|
551 |
} |
f36214408
|
552 553 |
caif_assert(phyid == phyinfo->id); caif_assert(phy_layer == phyinfo->phy_layer); |
15c9ac0c8
|
554 |
caif_assert(phy_layer->id == phyid); |
f36214408
|
555 |
caif_assert(phyinfo->frm_layer->id == phyid); |
bee925db9
|
556 557 |
list_del_rcu(&phyinfo->node); synchronize_rcu(); |
cb3cb423a
|
558 559 560 561 |
/* Fail if reference count is not zero */ if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) { pr_info("Wait for device inuse "); |
bee925db9
|
562 |
list_add_rcu(&phyinfo->node, &cnfg->phys); |
cb3cb423a
|
563 564 565 |
mutex_unlock(&cnfg->lock); return -EAGAIN; } |
f36214408
|
566 |
frml = phyinfo->frm_layer; |
15c9ac0c8
|
567 568 569 |
frml_dn = frml->dn; cffrml_set_uplayer(frml, NULL); cffrml_set_dnlayer(frml, NULL); |
15c9ac0c8
|
570 571 572 |
if (phy_layer != frml_dn) { layer_set_up(frml_dn, NULL); layer_set_dn(frml_dn, NULL); |
15c9ac0c8
|
573 574 |
} layer_set_up(phy_layer, NULL); |
f36214408
|
575 |
|
f36214408
|
576 577 |
if (phyinfo->phy_layer != frml_dn) kfree(frml_dn); |
cb3cb423a
|
578 |
cffrml_free(frml); |
f36214408
|
579 580 |
kfree(phyinfo); mutex_unlock(&cnfg->lock); |
15c9ac0c8
|
581 582 583 |
return 0; } EXPORT_SYMBOL(cfcnfg_del_phy_layer); |