aboutsummaryrefslogtreecommitdiffstats
path: root/net/caif/cfcnfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/caif/cfcnfg.c')
-rw-r--r--net/caif/cfcnfg.c507
1 files changed, 326 insertions, 181 deletions
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index f1f98d967d8a..351c2ca7e7b9 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -10,6 +10,7 @@
10#include <linux/stddef.h> 10#include <linux/stddef.h>
11#include <linux/slab.h> 11#include <linux/slab.h>
12#include <linux/netdevice.h> 12#include <linux/netdevice.h>
13#include <linux/module.h>
13#include <net/caif/caif_layer.h> 14#include <net/caif/caif_layer.h>
14#include <net/caif/cfpkt.h> 15#include <net/caif/cfpkt.h>
15#include <net/caif/cfcnfg.h> 16#include <net/caif/cfcnfg.h>
@@ -18,11 +19,7 @@
18#include <net/caif/cffrml.h> 19#include <net/caif/cffrml.h>
19#include <net/caif/cfserl.h> 20#include <net/caif/cfserl.h>
20#include <net/caif/cfsrvl.h> 21#include <net/caif/cfsrvl.h>
21 22#include <net/caif/caif_dev.h>
22#include <linux/module.h>
23#include <asm/atomic.h>
24
25#define MAX_PHY_LAYERS 7
26 23
27#define container_obj(layr) container_of(layr, struct cfcnfg, layer) 24#define container_obj(layr) container_of(layr, struct cfcnfg, layer)
28 25
@@ -30,6 +27,9 @@
30 * to manage physical interfaces 27 * to manage physical interfaces
31 */ 28 */
32struct cfcnfg_phyinfo { 29struct cfcnfg_phyinfo {
30 struct list_head node;
31 bool up;
32
33 /* Pointer to the layer below the MUX (framing layer) */ 33 /* Pointer to the layer below the MUX (framing layer) */
34 struct cflayer *frm_layer; 34 struct cflayer *frm_layer;
35 /* Pointer to the lowest actual physical layer */ 35 /* Pointer to the lowest actual physical layer */
@@ -39,9 +39,6 @@ struct cfcnfg_phyinfo {
39 /* Preference of the physical in interface */ 39 /* Preference of the physical in interface */
40 enum cfcnfg_phy_preference pref; 40 enum cfcnfg_phy_preference pref;
41 41
42 /* Reference count, number of channels using the device */
43 int phy_ref_count;
44
45 /* Information about the physical device */ 42 /* Information about the physical device */
46 struct dev_info dev_info; 43 struct dev_info dev_info;
47 44
@@ -59,8 +56,8 @@ struct cfcnfg {
59 struct cflayer layer; 56 struct cflayer layer;
60 struct cflayer *ctrl; 57 struct cflayer *ctrl;
61 struct cflayer *mux; 58 struct cflayer *mux;
62 u8 last_phyid; 59 struct list_head phys;
63 struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS]; 60 struct mutex lock;
64}; 61};
65 62
66static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, 63static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
@@ -76,6 +73,9 @@ struct cfcnfg *cfcnfg_create(void)
76{ 73{
77 struct cfcnfg *this; 74 struct cfcnfg *this;
78 struct cfctrl_rsp *resp; 75 struct cfctrl_rsp *resp;
76
77 might_sleep();
78
79 /* Initiate this layer */ 79 /* Initiate this layer */
80 this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC); 80 this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
81 if (!this) { 81 if (!this) {
@@ -99,27 +99,33 @@ struct cfcnfg *cfcnfg_create(void)
99 resp->radioset_rsp = cfctrl_resp_func; 99 resp->radioset_rsp = cfctrl_resp_func;
100 resp->linksetup_rsp = cfcnfg_linkup_rsp; 100 resp->linksetup_rsp = cfcnfg_linkup_rsp;
101 resp->reject_rsp = cfcnfg_reject_rsp; 101 resp->reject_rsp = cfcnfg_reject_rsp;
102 102 INIT_LIST_HEAD(&this->phys);
103 this->last_phyid = 1;
104 103
105 cfmuxl_set_uplayer(this->mux, this->ctrl, 0); 104 cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
106 layer_set_dn(this->ctrl, this->mux); 105 layer_set_dn(this->ctrl, this->mux);
107 layer_set_up(this->ctrl, this); 106 layer_set_up(this->ctrl, this);
107 mutex_init(&this->lock);
108
108 return this; 109 return this;
109out_of_mem: 110out_of_mem:
110 pr_warn("Out of memory\n"); 111 pr_warn("Out of memory\n");
112
113 synchronize_rcu();
114
111 kfree(this->mux); 115 kfree(this->mux);
112 kfree(this->ctrl); 116 kfree(this->ctrl);
113 kfree(this); 117 kfree(this);
114 return NULL; 118 return NULL;
115} 119}
116EXPORT_SYMBOL(cfcnfg_create);
117 120
118void cfcnfg_remove(struct cfcnfg *cfg) 121void cfcnfg_remove(struct cfcnfg *cfg)
119{ 122{
123 might_sleep();
120 if (cfg) { 124 if (cfg) {
125 synchronize_rcu();
126
121 kfree(cfg->mux); 127 kfree(cfg->mux);
122 kfree(cfg->ctrl); 128 cfctrl_remove(cfg->ctrl);
123 kfree(cfg); 129 kfree(cfg);
124 } 130 }
125} 131}
@@ -128,132 +134,96 @@ static void cfctrl_resp_func(void)
128{ 134{
129} 135}
130 136
137static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo_rcu(struct cfcnfg *cnfg,
138 u8 phyid)
139{
140 struct cfcnfg_phyinfo *phy;
141
142 list_for_each_entry_rcu(phy, &cnfg->phys, node)
143 if (phy->id == phyid)
144 return phy;
145 return NULL;
146}
147
131static void cfctrl_enum_resp(void) 148static void cfctrl_enum_resp(void)
132{ 149{
133} 150}
134 151
135struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, 152static struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
136 enum cfcnfg_phy_preference phy_pref) 153 enum cfcnfg_phy_preference phy_pref)
137{ 154{
138 u16 i;
139
140 /* Try to match with specified preference */ 155 /* Try to match with specified preference */
141 for (i = 1; i < MAX_PHY_LAYERS; i++) { 156 struct cfcnfg_phyinfo *phy;
142 if (cnfg->phy_layers[i].id == i && 157
143 cnfg->phy_layers[i].pref == phy_pref && 158 list_for_each_entry_rcu(phy, &cnfg->phys, node) {
144 cnfg->phy_layers[i].frm_layer != NULL) { 159 if (phy->up && phy->pref == phy_pref &&
145 caif_assert(cnfg->phy_layers != NULL); 160 phy->frm_layer != NULL)
146 caif_assert(cnfg->phy_layers[i].id == i); 161
147 return &cnfg->phy_layers[i].dev_info; 162 return &phy->dev_info;
148 }
149 } 163 }
164
150 /* Otherwise just return something */ 165 /* Otherwise just return something */
151 for (i = 1; i < MAX_PHY_LAYERS; i++) { 166 list_for_each_entry_rcu(phy, &cnfg->phys, node)
152 if (cnfg->phy_layers[i].id == i) { 167 if (phy->up)
153 caif_assert(cnfg->phy_layers != NULL); 168 return &phy->dev_info;
154 caif_assert(cnfg->phy_layers[i].id == i);
155 return &cnfg->phy_layers[i].dev_info;
156 }
157 }
158 169
159 return NULL; 170 return NULL;
160} 171}
161 172
162static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg, 173static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
163 u8 phyid)
164{ 174{
165 int i; 175 struct cfcnfg_phyinfo *phy;
166 /* Try to match with specified preference */
167 for (i = 0; i < MAX_PHY_LAYERS; i++)
168 if (cnfg->phy_layers[i].frm_layer != NULL &&
169 cnfg->phy_layers[i].id == phyid)
170 return &cnfg->phy_layers[i];
171 return NULL;
172}
173
174 176
175int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) 177 list_for_each_entry_rcu(phy, &cnfg->phys, node)
176{ 178 if (phy->ifindex == ifi && phy->up)
177 int i; 179 return phy->id;
178 for (i = 0; i < MAX_PHY_LAYERS; i++)
179 if (cnfg->phy_layers[i].frm_layer != NULL &&
180 cnfg->phy_layers[i].ifindex == ifi)
181 return i;
182 return -ENODEV; 180 return -ENODEV;
183} 181}
184 182
185int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer) 183int caif_disconnect_client(struct net *net, struct cflayer *adap_layer)
186{ 184{
187 u8 channel_id = 0; 185 u8 channel_id = 0;
188 int ret = 0; 186 int ret = 0;
189 struct cflayer *servl = NULL; 187 struct cflayer *servl = NULL;
190 struct cfcnfg_phyinfo *phyinfo = NULL; 188 struct cfcnfg *cfg = get_cfcnfg(net);
191 u8 phyid = 0;
192 189
193 caif_assert(adap_layer != NULL); 190 caif_assert(adap_layer != NULL);
191
194 channel_id = adap_layer->id; 192 channel_id = adap_layer->id;
195 if (adap_layer->dn == NULL || channel_id == 0) { 193 if (adap_layer->dn == NULL || channel_id == 0) {
196 pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n"); 194 pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n");
197 ret = -ENOTCONN; 195 ret = -ENOTCONN;
198 goto end; 196 goto end;
199 } 197 }
200 servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id); 198
199 servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
201 if (servl == NULL) { 200 if (servl == NULL) {
202 pr_err("PROTOCOL ERROR - Error removing service_layer Channel_Id(%d)", 201 pr_err("PROTOCOL ERROR - "
203 channel_id); 202 "Error removing service_layer Channel_Id(%d)",
203 channel_id);
204 ret = -EINVAL; 204 ret = -EINVAL;
205 goto end; 205 goto end;
206 } 206 }
207 layer_set_up(servl, NULL); 207
208 ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer); 208 ret = cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
209 if (ret) 209
210 goto end;
211 caif_assert(channel_id == servl->id);
212 if (adap_layer->dn != NULL) {
213 phyid = cfsrvl_getphyid(adap_layer->dn);
214
215 phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
216 if (phyinfo == NULL) {
217 pr_warn("No interface to send disconnect to\n");
218 ret = -ENODEV;
219 goto end;
220 }
221 if (phyinfo->id != phyid ||
222 phyinfo->phy_layer->id != phyid ||
223 phyinfo->frm_layer->id != phyid) {
224 pr_err("Inconsistency in phy registration\n");
225 ret = -EINVAL;
226 goto end;
227 }
228 }
229 if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 &&
230 phyinfo->phy_layer != NULL &&
231 phyinfo->phy_layer->modemcmd != NULL) {
232 phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
233 _CAIF_MODEMCMD_PHYIF_USELESS);
234 }
235end: 210end:
236 cfsrvl_put(servl); 211 cfctrl_cancel_req(cfg->ctrl, adap_layer);
237 cfctrl_cancel_req(cnfg->ctrl, adap_layer); 212
213 /* Do RCU sync before initiating cleanup */
214 synchronize_rcu();
238 if (adap_layer->ctrlcmd != NULL) 215 if (adap_layer->ctrlcmd != NULL)
239 adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0); 216 adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
240 return ret; 217 return ret;
241 218
242} 219}
243EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer); 220EXPORT_SYMBOL(caif_disconnect_client);
244
245void cfcnfg_release_adap_layer(struct cflayer *adap_layer)
246{
247 if (adap_layer->dn)
248 cfsrvl_put(adap_layer->dn);
249}
250EXPORT_SYMBOL(cfcnfg_release_adap_layer);
251 221
252static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id) 222static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
253{ 223{
254} 224}
255 225
256int protohead[CFCTRL_SRV_MASK] = { 226static const int protohead[CFCTRL_SRV_MASK] = {
257 [CFCTRL_SRV_VEI] = 4, 227 [CFCTRL_SRV_VEI] = 4,
258 [CFCTRL_SRV_DATAGRAM] = 7, 228 [CFCTRL_SRV_DATAGRAM] = 7,
259 [CFCTRL_SRV_UTIL] = 4, 229 [CFCTRL_SRV_UTIL] = 4,
@@ -261,49 +231,157 @@ int protohead[CFCTRL_SRV_MASK] = {
261 [CFCTRL_SRV_DBG] = 3, 231 [CFCTRL_SRV_DBG] = 3,
262}; 232};
263 233
264int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, 234
265 struct cfctrl_link_param *param, 235static int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
266 struct cflayer *adap_layer, 236 struct caif_connect_request *s,
267 int *ifindex, 237 struct cfctrl_link_param *l)
238{
239 struct dev_info *dev_info;
240 enum cfcnfg_phy_preference pref;
241 int res;
242
243 memset(l, 0, sizeof(*l));
244 /* In caif protocol low value is high priority */
245 l->priority = CAIF_PRIO_MAX - s->priority + 1;
246
247 if (s->ifindex != 0) {
248 res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex);
249 if (res < 0)
250 return res;
251 l->phyid = res;
252 } else {
253 switch (s->link_selector) {
254 case CAIF_LINK_HIGH_BANDW:
255 pref = CFPHYPREF_HIGH_BW;
256 break;
257 case CAIF_LINK_LOW_LATENCY:
258 pref = CFPHYPREF_LOW_LAT;
259 break;
260 default:
261 return -EINVAL;
262 }
263 dev_info = cfcnfg_get_phyid(cnfg, pref);
264 if (dev_info == NULL)
265 return -ENODEV;
266 l->phyid = dev_info->id;
267 }
268 switch (s->protocol) {
269 case CAIFPROTO_AT:
270 l->linktype = CFCTRL_SRV_VEI;
271 l->endpoint = (s->sockaddr.u.at.type >> 2) & 0x3;
272 l->chtype = s->sockaddr.u.at.type & 0x3;
273 break;
274 case CAIFPROTO_DATAGRAM:
275 l->linktype = CFCTRL_SRV_DATAGRAM;
276 l->chtype = 0x00;
277 l->u.datagram.connid = s->sockaddr.u.dgm.connection_id;
278 break;
279 case CAIFPROTO_DATAGRAM_LOOP:
280 l->linktype = CFCTRL_SRV_DATAGRAM;
281 l->chtype = 0x03;
282 l->endpoint = 0x00;
283 l->u.datagram.connid = s->sockaddr.u.dgm.connection_id;
284 break;
285 case CAIFPROTO_RFM:
286 l->linktype = CFCTRL_SRV_RFM;
287 l->u.datagram.connid = s->sockaddr.u.rfm.connection_id;
288 strncpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume,
289 sizeof(l->u.rfm.volume)-1);
290 l->u.rfm.volume[sizeof(l->u.rfm.volume)-1] = 0;
291 break;
292 case CAIFPROTO_UTIL:
293 l->linktype = CFCTRL_SRV_UTIL;
294 l->endpoint = 0x00;
295 l->chtype = 0x00;
296 strncpy(l->u.utility.name, s->sockaddr.u.util.service,
297 sizeof(l->u.utility.name)-1);
298 l->u.utility.name[sizeof(l->u.utility.name)-1] = 0;
299 caif_assert(sizeof(l->u.utility.name) > 10);
300 l->u.utility.paramlen = s->param.size;
301 if (l->u.utility.paramlen > sizeof(l->u.utility.params))
302 l->u.utility.paramlen = sizeof(l->u.utility.params);
303
304 memcpy(l->u.utility.params, s->param.data,
305 l->u.utility.paramlen);
306
307 break;
308 case CAIFPROTO_DEBUG:
309 l->linktype = CFCTRL_SRV_DBG;
310 l->endpoint = s->sockaddr.u.dbg.service;
311 l->chtype = s->sockaddr.u.dbg.type;
312 break;
313 default:
314 return -EINVAL;
315 }
316 return 0;
317}
318
319int caif_connect_client(struct net *net, struct caif_connect_request *conn_req,
320 struct cflayer *adap_layer, int *ifindex,
268 int *proto_head, 321 int *proto_head,
269 int *proto_tail) 322 int *proto_tail)
270{ 323{
271 struct cflayer *frml; 324 struct cflayer *frml;
325 struct cfcnfg_phyinfo *phy;
326 int err;
327 struct cfctrl_link_param param;
328 struct cfcnfg *cfg = get_cfcnfg(net);
329 caif_assert(cfg != NULL);
330
331 rcu_read_lock();
332 err = caif_connect_req_to_link_param(cfg, conn_req, &param);
333 if (err)
334 goto unlock;
335
336 phy = cfcnfg_get_phyinfo_rcu(cfg, param.phyid);
337 if (!phy) {
338 err = -ENODEV;
339 goto unlock;
340 }
341 err = -EINVAL;
342
272 if (adap_layer == NULL) { 343 if (adap_layer == NULL) {
273 pr_err("adap_layer is zero\n"); 344 pr_err("adap_layer is zero\n");
274 return -EINVAL; 345 goto unlock;
275 } 346 }
276 if (adap_layer->receive == NULL) { 347 if (adap_layer->receive == NULL) {
277 pr_err("adap_layer->receive is NULL\n"); 348 pr_err("adap_layer->receive is NULL\n");
278 return -EINVAL; 349 goto unlock;
279 } 350 }
280 if (adap_layer->ctrlcmd == NULL) { 351 if (adap_layer->ctrlcmd == NULL) {
281 pr_err("adap_layer->ctrlcmd == NULL\n"); 352 pr_err("adap_layer->ctrlcmd == NULL\n");
282 return -EINVAL; 353 goto unlock;
283 } 354 }
284 frml = cnfg->phy_layers[param->phyid].frm_layer; 355
356 err = -ENODEV;
357 frml = phy->frm_layer;
285 if (frml == NULL) { 358 if (frml == NULL) {
286 pr_err("Specified PHY type does not exist!\n"); 359 pr_err("Specified PHY type does not exist!\n");
287 return -ENODEV; 360 goto unlock;
288 } 361 }
289 caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id); 362 caif_assert(param.phyid == phy->id);
290 caif_assert(cnfg->phy_layers[param->phyid].frm_layer->id == 363 caif_assert(phy->frm_layer->id ==
291 param->phyid); 364 param.phyid);
292 caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id == 365 caif_assert(phy->phy_layer->id ==
293 param->phyid); 366 param.phyid);
294 367
295 *ifindex = cnfg->phy_layers[param->phyid].ifindex; 368 *ifindex = phy->ifindex;
369 *proto_tail = 2;
296 *proto_head = 370 *proto_head =
297 protohead[param->linktype]+
298 (cnfg->phy_layers[param->phyid].use_stx ? 1 : 0);
299 371
300 *proto_tail = 2; 372 protohead[param.linktype] + (phy->use_stx ? 1 : 0);
373
374 rcu_read_unlock();
301 375
302 /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */ 376 /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
303 cfctrl_enum_req(cnfg->ctrl, param->phyid); 377 cfctrl_enum_req(cfg->ctrl, param.phyid);
304 return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer); 378 return cfctrl_linkup_request(cfg->ctrl, &param, adap_layer);
379
380unlock:
381 rcu_read_unlock();
382 return err;
305} 383}
306EXPORT_SYMBOL(cfcnfg_add_adaptation_layer); 384EXPORT_SYMBOL(caif_connect_client);
307 385
308static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, 386static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
309 struct cflayer *adapt_layer) 387 struct cflayer *adapt_layer)
@@ -315,32 +393,37 @@ static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
315 393
316static void 394static void
317cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, 395cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
318 u8 phyid, struct cflayer *adapt_layer) 396 u8 phyid, struct cflayer *adapt_layer)
319{ 397{
320 struct cfcnfg *cnfg = container_obj(layer); 398 struct cfcnfg *cnfg = container_obj(layer);
321 struct cflayer *servicel = NULL; 399 struct cflayer *servicel = NULL;
322 struct cfcnfg_phyinfo *phyinfo; 400 struct cfcnfg_phyinfo *phyinfo;
323 struct net_device *netdev; 401 struct net_device *netdev;
324 402
403 rcu_read_lock();
404
325 if (adapt_layer == NULL) { 405 if (adapt_layer == NULL) {
326 pr_debug("link setup response but no client exist, send linkdown back\n"); 406 pr_debug("link setup response but no client exist,"
407 "send linkdown back\n");
327 cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL); 408 cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
328 return; 409 goto unlock;
329 } 410 }
330 411
331 caif_assert(cnfg != NULL); 412 caif_assert(cnfg != NULL);
332 caif_assert(phyid != 0); 413 caif_assert(phyid != 0);
333 phyinfo = &cnfg->phy_layers[phyid]; 414
415 phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);
416 if (phyinfo == NULL) {
417 pr_err("ERROR: Link Layer Device dissapeared"
418 "while connecting\n");
419 goto unlock;
420 }
421
422 caif_assert(phyinfo != NULL);
334 caif_assert(phyinfo->id == phyid); 423 caif_assert(phyinfo->id == phyid);
335 caif_assert(phyinfo->phy_layer != NULL); 424 caif_assert(phyinfo->phy_layer != NULL);
336 caif_assert(phyinfo->phy_layer->id == phyid); 425 caif_assert(phyinfo->phy_layer->id == phyid);
337 426
338 phyinfo->phy_ref_count++;
339 if (phyinfo->phy_ref_count == 1 &&
340 phyinfo->phy_layer->modemcmd != NULL) {
341 phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
342 _CAIF_MODEMCMD_PHYIF_USEFULL);
343 }
344 adapt_layer->id = channel_id; 427 adapt_layer->id = channel_id;
345 428
346 switch (serv) { 429 switch (serv) {
@@ -348,7 +431,8 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
348 servicel = cfvei_create(channel_id, &phyinfo->dev_info); 431 servicel = cfvei_create(channel_id, &phyinfo->dev_info);
349 break; 432 break;
350 case CFCTRL_SRV_DATAGRAM: 433 case CFCTRL_SRV_DATAGRAM:
351 servicel = cfdgml_create(channel_id, &phyinfo->dev_info); 434 servicel = cfdgml_create(channel_id,
435 &phyinfo->dev_info);
352 break; 436 break;
353 case CFCTRL_SRV_RFM: 437 case CFCTRL_SRV_RFM:
354 netdev = phyinfo->dev_info.dev; 438 netdev = phyinfo->dev_info.dev;
@@ -365,94 +449,93 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
365 servicel = cfdbgl_create(channel_id, &phyinfo->dev_info); 449 servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
366 break; 450 break;
367 default: 451 default:
368 pr_err("Protocol error. Link setup response - unknown channel type\n"); 452 pr_err("Protocol error. Link setup response "
369 return; 453 "- unknown channel type\n");
454 goto unlock;
370 } 455 }
371 if (!servicel) { 456 if (!servicel) {
372 pr_warn("Out of memory\n"); 457 pr_warn("Out of memory\n");
373 return; 458 goto unlock;
374 } 459 }
375 layer_set_dn(servicel, cnfg->mux); 460 layer_set_dn(servicel, cnfg->mux);
376 cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id); 461 cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
377 layer_set_up(servicel, adapt_layer); 462 layer_set_up(servicel, adapt_layer);
378 layer_set_dn(adapt_layer, servicel); 463 layer_set_dn(adapt_layer, servicel);
379 cfsrvl_get(servicel); 464
465 rcu_read_unlock();
466
380 servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0); 467 servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
468 return;
469unlock:
470 rcu_read_unlock();
381} 471}
382 472
383void 473void
384cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, 474cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
385 struct net_device *dev, struct cflayer *phy_layer, 475 struct net_device *dev, struct cflayer *phy_layer,
386 u16 *phyid, enum cfcnfg_phy_preference pref, 476 enum cfcnfg_phy_preference pref,
387 bool fcs, bool stx) 477 bool fcs, bool stx)
388{ 478{
389 struct cflayer *frml; 479 struct cflayer *frml;
390 struct cflayer *phy_driver = NULL; 480 struct cflayer *phy_driver = NULL;
481 struct cfcnfg_phyinfo *phyinfo;
391 int i; 482 int i;
483 u8 phyid;
392 484
485 mutex_lock(&cnfg->lock);
393 486
394 if (cnfg->phy_layers[cnfg->last_phyid].frm_layer == NULL) { 487 /* CAIF protocol allow maximum 6 link-layers */
395 *phyid = cnfg->last_phyid; 488 for (i = 0; i < 7; i++) {
396 489 phyid = (dev->ifindex + i) & 0x7;
397 /* range: * 1..(MAX_PHY_LAYERS-1) */ 490 if (phyid == 0)
398 cnfg->last_phyid = 491 continue;
399 (cnfg->last_phyid % (MAX_PHY_LAYERS - 1)) + 1; 492 if (cfcnfg_get_phyinfo_rcu(cnfg, phyid) == NULL)
400 } else { 493 goto got_phyid;
401 *phyid = 0;
402 for (i = 1; i < MAX_PHY_LAYERS; i++) {
403 if (cnfg->phy_layers[i].frm_layer == NULL) {
404 *phyid = i;
405 break;
406 }
407 }
408 }
409 if (*phyid == 0) {
410 pr_err("No Available PHY ID\n");
411 return;
412 } 494 }
495 pr_warn("Too many CAIF Link Layers (max 6)\n");
496 goto out;
497
498got_phyid:
499 phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
413 500
414 switch (phy_type) { 501 switch (phy_type) {
415 case CFPHYTYPE_FRAG: 502 case CFPHYTYPE_FRAG:
416 phy_driver = 503 phy_driver =
417 cfserl_create(CFPHYTYPE_FRAG, *phyid, stx); 504 cfserl_create(CFPHYTYPE_FRAG, phyid, stx);
418 if (!phy_driver) { 505 if (!phy_driver) {
419 pr_warn("Out of memory\n"); 506 pr_warn("Out of memory\n");
420 return; 507 goto out;
421 } 508 }
422
423 break; 509 break;
424 case CFPHYTYPE_CAIF: 510 case CFPHYTYPE_CAIF:
425 phy_driver = NULL; 511 phy_driver = NULL;
426 break; 512 break;
427 default: 513 default:
428 pr_err("%d\n", phy_type); 514 goto out;
429 return;
430 break;
431 } 515 }
432 516 phy_layer->id = phyid;
433 phy_layer->id = *phyid; 517 phyinfo->pref = pref;
434 cnfg->phy_layers[*phyid].pref = pref; 518 phyinfo->id = phyid;
435 cnfg->phy_layers[*phyid].id = *phyid; 519 phyinfo->dev_info.id = phyid;
436 cnfg->phy_layers[*phyid].dev_info.id = *phyid; 520 phyinfo->dev_info.dev = dev;
437 cnfg->phy_layers[*phyid].dev_info.dev = dev; 521 phyinfo->phy_layer = phy_layer;
438 cnfg->phy_layers[*phyid].phy_layer = phy_layer; 522 phyinfo->ifindex = dev->ifindex;
439 cnfg->phy_layers[*phyid].phy_ref_count = 0; 523 phyinfo->use_stx = stx;
440 cnfg->phy_layers[*phyid].ifindex = dev->ifindex; 524 phyinfo->use_fcs = fcs;
441 cnfg->phy_layers[*phyid].use_stx = stx;
442 cnfg->phy_layers[*phyid].use_fcs = fcs;
443 525
444 phy_layer->type = phy_type; 526 phy_layer->type = phy_type;
445 frml = cffrml_create(*phyid, fcs); 527 frml = cffrml_create(phyid, fcs);
528
446 if (!frml) { 529 if (!frml) {
447 pr_warn("Out of memory\n"); 530 pr_warn("Out of memory\n");
448 return; 531 kfree(phyinfo);
532 goto out;
449 } 533 }
450 cnfg->phy_layers[*phyid].frm_layer = frml; 534 phyinfo->frm_layer = frml;
451 cfmuxl_set_dnlayer(cnfg->mux, frml, *phyid);
452 layer_set_up(frml, cnfg->mux); 535 layer_set_up(frml, cnfg->mux);
453 536
454 if (phy_driver != NULL) { 537 if (phy_driver != NULL) {
455 phy_driver->id = *phyid; 538 phy_driver->id = phyid;
456 layer_set_dn(frml, phy_driver); 539 layer_set_dn(frml, phy_driver);
457 layer_set_up(phy_driver, frml); 540 layer_set_up(phy_driver, frml);
458 layer_set_dn(phy_driver, phy_layer); 541 layer_set_dn(phy_driver, phy_layer);
@@ -461,33 +544,95 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
461 layer_set_dn(frml, phy_layer); 544 layer_set_dn(frml, phy_layer);
462 layer_set_up(phy_layer, frml); 545 layer_set_up(phy_layer, frml);
463 } 546 }
547
548 list_add_rcu(&phyinfo->node, &cnfg->phys);
549out:
550 mutex_unlock(&cnfg->lock);
464} 551}
465EXPORT_SYMBOL(cfcnfg_add_phy_layer); 552EXPORT_SYMBOL(cfcnfg_add_phy_layer);
466 553
554int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer,
555 bool up)
556{
557 struct cfcnfg_phyinfo *phyinfo;
558
559 rcu_read_lock();
560 phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phy_layer->id);
561 if (phyinfo == NULL) {
562 rcu_read_unlock();
563 return -ENODEV;
564 }
565
566 if (phyinfo->up == up) {
567 rcu_read_unlock();
568 return 0;
569 }
570 phyinfo->up = up;
571
572 if (up) {
573 cffrml_hold(phyinfo->frm_layer);
574 cfmuxl_set_dnlayer(cnfg->mux, phyinfo->frm_layer,
575 phy_layer->id);
576 } else {
577 cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
578 cffrml_put(phyinfo->frm_layer);
579 }
580
581 rcu_read_unlock();
582 return 0;
583}
584EXPORT_SYMBOL(cfcnfg_set_phy_state);
585
467int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) 586int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
468{ 587{
469 struct cflayer *frml, *frml_dn; 588 struct cflayer *frml, *frml_dn;
470 u16 phyid; 589 u16 phyid;
590 struct cfcnfg_phyinfo *phyinfo;
591
592 might_sleep();
593
594 mutex_lock(&cnfg->lock);
595
471 phyid = phy_layer->id; 596 phyid = phy_layer->id;
472 caif_assert(phyid == cnfg->phy_layers[phyid].id); 597 phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);
473 caif_assert(phy_layer == cnfg->phy_layers[phyid].phy_layer); 598
599 if (phyinfo == NULL) {
600 mutex_unlock(&cnfg->lock);
601 return 0;
602 }
603 caif_assert(phyid == phyinfo->id);
604 caif_assert(phy_layer == phyinfo->phy_layer);
474 caif_assert(phy_layer->id == phyid); 605 caif_assert(phy_layer->id == phyid);
475 caif_assert(cnfg->phy_layers[phyid].frm_layer->id == phyid); 606 caif_assert(phyinfo->frm_layer->id == phyid);
476 607
477 memset(&cnfg->phy_layers[phy_layer->id], 0, 608 list_del_rcu(&phyinfo->node);
478 sizeof(struct cfcnfg_phyinfo)); 609 synchronize_rcu();
479 frml = cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id); 610
611 /* Fail if reference count is not zero */
612 if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) {
613 pr_info("Wait for device inuse\n");
614 list_add_rcu(&phyinfo->node, &cnfg->phys);
615 mutex_unlock(&cnfg->lock);
616 return -EAGAIN;
617 }
618
619 frml = phyinfo->frm_layer;
480 frml_dn = frml->dn; 620 frml_dn = frml->dn;
481 cffrml_set_uplayer(frml, NULL); 621 cffrml_set_uplayer(frml, NULL);
482 cffrml_set_dnlayer(frml, NULL); 622 cffrml_set_dnlayer(frml, NULL);
483 kfree(frml);
484
485 if (phy_layer != frml_dn) { 623 if (phy_layer != frml_dn) {
486 layer_set_up(frml_dn, NULL); 624 layer_set_up(frml_dn, NULL);
487 layer_set_dn(frml_dn, NULL); 625 layer_set_dn(frml_dn, NULL);
488 kfree(frml_dn);
489 } 626 }
490 layer_set_up(phy_layer, NULL); 627 layer_set_up(phy_layer, NULL);
628
629 if (phyinfo->phy_layer != frml_dn)
630 kfree(frml_dn);
631
632 cffrml_free(frml);
633 kfree(phyinfo);
634 mutex_unlock(&cnfg->lock);
635
491 return 0; 636 return 0;
492} 637}
493EXPORT_SYMBOL(cfcnfg_del_phy_layer); 638EXPORT_SYMBOL(cfcnfg_del_phy_layer);