diff options
Diffstat (limited to 'net/caif/cfctrl.c')
-rw-r--r-- | net/caif/cfctrl.c | 196 |
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 |
22 | static int handle_loop(struct cfctrl *ctrl, | 21 | static 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 | ||
61 | static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2) | 62 | void 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 | |||
76 | static 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 | ||
103 | bool cfctrl_req_eq(struct cfctrl_request_info *r1, | 119 | static 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 */ |
115 | void cfctrl_insert_req(struct cfctrl *ctrl, | 131 | static 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 */ |
126 | struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, | 142 | static 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; |
146 | out: | 161 | out: |
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 | ||
157 | void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn) | ||
158 | { | ||
159 | this->dn = dn; | ||
160 | } | ||
161 | |||
162 | void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up) | ||
163 | { | ||
164 | this->up = up; | ||
165 | } | ||
166 | |||
167 | static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl) | 171 | static 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 | ||
197 | int cfctrl_linkup_request(struct cflayer *layer, | 197 | int 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 | ||
307 | void cfctrl_sleep_req(struct cflayer *layer) | 319 | int 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 | |||
324 | void 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 | |||
341 | void 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 | |||
359 | void 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 | ||
376 | static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) | 338 | static 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, | |||
599 | static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt) | 581 | static 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; | ||
615 | found: | 600 | found: |
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; |