aboutsummaryrefslogtreecommitdiffstats
path: root/net/caif/cfctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/caif/cfctrl.c')
-rw-r--r--net/caif/cfctrl.c196
1 files changed, 92 insertions, 104 deletions
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index 3cd8f978e309..0c00a6015dda 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -17,7 +17,6 @@
17#define UTILITY_NAME_LENGTH 16 17#define UTILITY_NAME_LENGTH 16
18#define CFPKT_CTRL_PKT_LEN 20 18#define CFPKT_CTRL_PKT_LEN 20
19 19
20
21#ifdef CAIF_NO_LOOP 20#ifdef CAIF_NO_LOOP
22static int handle_loop(struct cfctrl *ctrl, 21static int handle_loop(struct cfctrl *ctrl,
23 int cmd, struct cfpkt *pkt){ 22 int cmd, struct cfpkt *pkt){
@@ -51,14 +50,31 @@ struct cflayer *cfctrl_create(void)
51 this->serv.layer.receive = cfctrl_recv; 50 this->serv.layer.receive = cfctrl_recv;
52 sprintf(this->serv.layer.name, "ctrl"); 51 sprintf(this->serv.layer.name, "ctrl");
53 this->serv.layer.ctrlcmd = cfctrl_ctrlcmd; 52 this->serv.layer.ctrlcmd = cfctrl_ctrlcmd;
53#ifndef CAIF_NO_LOOP
54 spin_lock_init(&this->loop_linkid_lock); 54 spin_lock_init(&this->loop_linkid_lock);
55 this->loop_linkid = 1;
56#endif
55 spin_lock_init(&this->info_list_lock); 57 spin_lock_init(&this->info_list_lock);
56 INIT_LIST_HEAD(&this->list); 58 INIT_LIST_HEAD(&this->list);
57 this->loop_linkid = 1;
58 return &this->serv.layer; 59 return &this->serv.layer;
59} 60}
60 61
61static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2) 62void cfctrl_remove(struct cflayer *layer)
63{
64 struct cfctrl_request_info *p, *tmp;
65 struct cfctrl *ctrl = container_obj(layer);
66
67 spin_lock_bh(&ctrl->info_list_lock);
68 list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
69 list_del(&p->list);
70 kfree(p);
71 }
72 spin_unlock_bh(&ctrl->info_list_lock);
73 kfree(layer);
74}
75
76static bool param_eq(const struct cfctrl_link_param *p1,
77 const struct cfctrl_link_param *p2)
62{ 78{
63 bool eq = 79 bool eq =
64 p1->linktype == p2->linktype && 80 p1->linktype == p2->linktype &&
@@ -100,8 +116,8 @@ static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2)
100 return false; 116 return false;
101} 117}
102 118
103bool cfctrl_req_eq(struct cfctrl_request_info *r1, 119static bool cfctrl_req_eq(const struct cfctrl_request_info *r1,
104 struct cfctrl_request_info *r2) 120 const struct cfctrl_request_info *r2)
105{ 121{
106 if (r1->cmd != r2->cmd) 122 if (r1->cmd != r2->cmd)
107 return false; 123 return false;
@@ -112,23 +128,22 @@ bool cfctrl_req_eq(struct cfctrl_request_info *r1,
112} 128}
113 129
114/* Insert request at the end */ 130/* Insert request at the end */
115void cfctrl_insert_req(struct cfctrl *ctrl, 131static void cfctrl_insert_req(struct cfctrl *ctrl,
116 struct cfctrl_request_info *req) 132 struct cfctrl_request_info *req)
117{ 133{
118 spin_lock(&ctrl->info_list_lock); 134 spin_lock_bh(&ctrl->info_list_lock);
119 atomic_inc(&ctrl->req_seq_no); 135 atomic_inc(&ctrl->req_seq_no);
120 req->sequence_no = atomic_read(&ctrl->req_seq_no); 136 req->sequence_no = atomic_read(&ctrl->req_seq_no);
121 list_add_tail(&req->list, &ctrl->list); 137 list_add_tail(&req->list, &ctrl->list);
122 spin_unlock(&ctrl->info_list_lock); 138 spin_unlock_bh(&ctrl->info_list_lock);
123} 139}
124 140
125/* Compare and remove request */ 141/* Compare and remove request */
126struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, 142static struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
127 struct cfctrl_request_info *req) 143 struct cfctrl_request_info *req)
128{ 144{
129 struct cfctrl_request_info *p, *tmp, *first; 145 struct cfctrl_request_info *p, *tmp, *first;
130 146
131 spin_lock(&ctrl->info_list_lock);
132 first = list_first_entry(&ctrl->list, struct cfctrl_request_info, list); 147 first = list_first_entry(&ctrl->list, struct cfctrl_request_info, list);
133 148
134 list_for_each_entry_safe(p, tmp, &ctrl->list, list) { 149 list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
@@ -144,7 +159,6 @@ struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
144 } 159 }
145 p = NULL; 160 p = NULL;
146out: 161out:
147 spin_unlock(&ctrl->info_list_lock);
148 return p; 162 return p;
149} 163}
150 164
@@ -154,16 +168,6 @@ struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer)
154 return &this->res; 168 return &this->res;
155} 169}
156 170
157void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn)
158{
159 this->dn = dn;
160}
161
162void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up)
163{
164 this->up = up;
165}
166
167static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl) 171static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl)
168{ 172{
169 info->hdr_len = 0; 173 info->hdr_len = 0;
@@ -188,10 +192,6 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
188 cfpkt_addbdy(pkt, physlinkid); 192 cfpkt_addbdy(pkt, physlinkid);
189 ret = 193 ret =
190 cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); 194 cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
191 if (ret < 0) {
192 pr_err("Could not transmit enum message\n");
193 cfpkt_destroy(pkt);
194 }
195} 195}
196 196
197int cfctrl_linkup_request(struct cflayer *layer, 197int cfctrl_linkup_request(struct cflayer *layer,
@@ -205,14 +205,23 @@ int cfctrl_linkup_request(struct cflayer *layer,
205 struct cfctrl_request_info *req; 205 struct cfctrl_request_info *req;
206 int ret; 206 int ret;
207 char utility_name[16]; 207 char utility_name[16];
208 struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); 208 struct cfpkt *pkt;
209
210 if (cfctrl_cancel_req(layer, user_layer) > 0) {
211 /* Slight Paranoia, check if already connecting */
212 pr_err("Duplicate connect request for same client\n");
213 WARN_ON(1);
214 return -EALREADY;
215 }
216
217 pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
209 if (!pkt) { 218 if (!pkt) {
210 pr_warn("Out of memory\n"); 219 pr_warn("Out of memory\n");
211 return -ENOMEM; 220 return -ENOMEM;
212 } 221 }
213 cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP); 222 cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP);
214 cfpkt_addbdy(pkt, (param->chtype << 4) + param->linktype); 223 cfpkt_addbdy(pkt, (param->chtype << 4) | param->linktype);
215 cfpkt_addbdy(pkt, (param->priority << 3) + param->phyid); 224 cfpkt_addbdy(pkt, (param->priority << 3) | param->phyid);
216 cfpkt_addbdy(pkt, param->endpoint & 0x03); 225 cfpkt_addbdy(pkt, param->endpoint & 0x03);
217 226
218 switch (param->linktype) { 227 switch (param->linktype) {
@@ -275,9 +284,13 @@ int cfctrl_linkup_request(struct cflayer *layer,
275 ret = 284 ret =
276 cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); 285 cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
277 if (ret < 0) { 286 if (ret < 0) {
278 pr_err("Could not transmit linksetup request\n"); 287 int count;
279 cfpkt_destroy(pkt); 288
280 return -ENODEV; 289 count = cfctrl_cancel_req(&cfctrl->serv.layer,
290 user_layer);
291 if (count != 1)
292 pr_err("Could not remove request (%d)", count);
293 return -ENODEV;
281 } 294 }
282 return 0; 295 return 0;
283} 296}
@@ -297,80 +310,29 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
297 init_info(cfpkt_info(pkt), cfctrl); 310 init_info(cfpkt_info(pkt), cfctrl);
298 ret = 311 ret =
299 cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); 312 cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
300 if (ret < 0) { 313#ifndef CAIF_NO_LOOP
301 pr_err("Could not transmit link-down request\n"); 314 cfctrl->loop_linkused[channelid] = 0;
302 cfpkt_destroy(pkt); 315#endif
303 }
304 return ret; 316 return ret;
305} 317}
306 318
307void cfctrl_sleep_req(struct cflayer *layer) 319int cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
308{
309 int ret;
310 struct cfctrl *cfctrl = container_obj(layer);
311 struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
312 if (!pkt) {
313 pr_warn("Out of memory\n");
314 return;
315 }
316 cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP);
317 init_info(cfpkt_info(pkt), cfctrl);
318 ret =
319 cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
320 if (ret < 0)
321 cfpkt_destroy(pkt);
322}
323
324void cfctrl_wake_req(struct cflayer *layer)
325{
326 int ret;
327 struct cfctrl *cfctrl = container_obj(layer);
328 struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
329 if (!pkt) {
330 pr_warn("Out of memory\n");
331 return;
332 }
333 cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE);
334 init_info(cfpkt_info(pkt), cfctrl);
335 ret =
336 cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
337 if (ret < 0)
338 cfpkt_destroy(pkt);
339}
340
341void cfctrl_getstartreason_req(struct cflayer *layer)
342{
343 int ret;
344 struct cfctrl *cfctrl = container_obj(layer);
345 struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
346 if (!pkt) {
347 pr_warn("Out of memory\n");
348 return;
349 }
350 cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON);
351 init_info(cfpkt_info(pkt), cfctrl);
352 ret =
353 cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
354 if (ret < 0)
355 cfpkt_destroy(pkt);
356}
357
358
359void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
360{ 320{
361 struct cfctrl_request_info *p, *tmp; 321 struct cfctrl_request_info *p, *tmp;
362 struct cfctrl *ctrl = container_obj(layr); 322 struct cfctrl *ctrl = container_obj(layr);
363 spin_lock(&ctrl->info_list_lock); 323 int found = 0;
324 spin_lock_bh(&ctrl->info_list_lock);
364 325
365 list_for_each_entry_safe(p, tmp, &ctrl->list, list) { 326 list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
366 if (p->client_layer == adap_layer) { 327 if (p->client_layer == adap_layer) {
367 pr_debug("cancel req :%d\n", p->sequence_no);
368 list_del(&p->list); 328 list_del(&p->list);
369 kfree(p); 329 kfree(p);
330 found++;
370 } 331 }
371 } 332 }
372 333
373 spin_unlock(&ctrl->info_list_lock); 334 spin_unlock_bh(&ctrl->info_list_lock);
335 return found;
374} 336}
375 337
376static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) 338static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
@@ -522,6 +484,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
522 484
523 rsp.cmd = cmd; 485 rsp.cmd = cmd;
524 rsp.param = linkparam; 486 rsp.param = linkparam;
487 spin_lock_bh(&cfctrl->info_list_lock);
525 req = cfctrl_remove_req(cfctrl, &rsp); 488 req = cfctrl_remove_req(cfctrl, &rsp);
526 489
527 if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) || 490 if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) ||
@@ -541,6 +504,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
541 504
542 if (req != NULL) 505 if (req != NULL)
543 kfree(req); 506 kfree(req);
507
508 spin_unlock_bh(&cfctrl->info_list_lock);
544 } 509 }
545 break; 510 break;
546 case CFCTRL_CMD_LINK_DESTROY: 511 case CFCTRL_CMD_LINK_DESTROY:
@@ -584,12 +549,29 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
584 switch (ctrl) { 549 switch (ctrl) {
585 case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: 550 case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
586 case CAIF_CTRLCMD_FLOW_OFF_IND: 551 case CAIF_CTRLCMD_FLOW_OFF_IND:
587 spin_lock(&this->info_list_lock); 552 spin_lock_bh(&this->info_list_lock);
588 if (!list_empty(&this->list)) { 553 if (!list_empty(&this->list)) {
589 pr_debug("Received flow off in control layer\n"); 554 pr_debug("Received flow off in control layer\n");
590 } 555 }
591 spin_unlock(&this->info_list_lock); 556 spin_unlock_bh(&this->info_list_lock);
592 break; 557 break;
558 case _CAIF_CTRLCMD_PHYIF_DOWN_IND: {
559 struct cfctrl_request_info *p, *tmp;
560
561 /* Find all connect request and report failure */
562 spin_lock_bh(&this->info_list_lock);
563 list_for_each_entry_safe(p, tmp, &this->list, list) {
564 if (p->param.phyid == phyid) {
565 list_del(&p->list);
566 p->client_layer->ctrlcmd(p->client_layer,
567 CAIF_CTRLCMD_INIT_FAIL_RSP,
568 phyid);
569 kfree(p);
570 }
571 }
572 spin_unlock_bh(&this->info_list_lock);
573 break;
574 }
593 default: 575 default:
594 break; 576 break;
595 } 577 }
@@ -599,27 +581,33 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
599static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt) 581static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt)
600{ 582{
601 static int last_linkid; 583 static int last_linkid;
584 static int dec;
602 u8 linkid, linktype, tmp; 585 u8 linkid, linktype, tmp;
603 switch (cmd) { 586 switch (cmd) {
604 case CFCTRL_CMD_LINK_SETUP: 587 case CFCTRL_CMD_LINK_SETUP:
605 spin_lock(&ctrl->loop_linkid_lock); 588 spin_lock_bh(&ctrl->loop_linkid_lock);
606 for (linkid = last_linkid + 1; linkid < 255; linkid++) 589 if (!dec) {
607 if (!ctrl->loop_linkused[linkid]) 590 for (linkid = last_linkid + 1; linkid < 255; linkid++)
608 goto found; 591 if (!ctrl->loop_linkused[linkid])
592 goto found;
593 }
594 dec = 1;
609 for (linkid = last_linkid - 1; linkid > 0; linkid--) 595 for (linkid = last_linkid - 1; linkid > 0; linkid--)
610 if (!ctrl->loop_linkused[linkid]) 596 if (!ctrl->loop_linkused[linkid])
611 goto found; 597 goto found;
612 spin_unlock(&ctrl->loop_linkid_lock); 598 spin_unlock_bh(&ctrl->loop_linkid_lock);
613 pr_err("Out of link-ids\n"); 599
614 return -EINVAL;
615found: 600found:
601 if (linkid < 10)
602 dec = 0;
603
616 if (!ctrl->loop_linkused[linkid]) 604 if (!ctrl->loop_linkused[linkid])
617 ctrl->loop_linkused[linkid] = 1; 605 ctrl->loop_linkused[linkid] = 1;
618 606
619 last_linkid = linkid; 607 last_linkid = linkid;
620 608
621 cfpkt_add_trail(pkt, &linkid, 1); 609 cfpkt_add_trail(pkt, &linkid, 1);
622 spin_unlock(&ctrl->loop_linkid_lock); 610 spin_unlock_bh(&ctrl->loop_linkid_lock);
623 cfpkt_peek_head(pkt, &linktype, 1); 611 cfpkt_peek_head(pkt, &linktype, 1);
624 if (linktype == CFCTRL_SRV_UTIL) { 612 if (linktype == CFCTRL_SRV_UTIL) {
625 tmp = 0x01; 613 tmp = 0x01;
@@ -629,10 +617,10 @@ found:
629 break; 617 break;
630 618
631 case CFCTRL_CMD_LINK_DESTROY: 619 case CFCTRL_CMD_LINK_DESTROY:
632 spin_lock(&ctrl->loop_linkid_lock); 620 spin_lock_bh(&ctrl->loop_linkid_lock);
633 cfpkt_peek_head(pkt, &linkid, 1); 621 cfpkt_peek_head(pkt, &linkid, 1);
634 ctrl->loop_linkused[linkid] = 0; 622 ctrl->loop_linkused[linkid] = 0;
635 spin_unlock(&ctrl->loop_linkid_lock); 623 spin_unlock_bh(&ctrl->loop_linkid_lock);
636 break; 624 break;
637 default: 625 default:
638 break; 626 break;