Commit bfb88d6c91a2cf507ff7763ebec94d72b4c98b07
Committed by
Greg Kroah-Hartman
1 parent
1ff97647f0
Exists in
master
and in
6 other branches
drivers:misc: ti-st: protect registrations
Concurrent access to UART2/combo-interface by multiple protocol drivers such as BT, FM and GPS caused issues during firmware download failure cases or cases when the firmware download took longer than usual. This was because of un-safe access to protos_registered & st_states. Protecting this will also make the registration complete callback un-safe for sleep. Signed-off-by: Pavan Savoy <pavan_savoy@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 1 changed file with 14 additions and 4 deletions Side-by-side Diff
drivers/misc/ti-st/st_core.c
... | ... | @@ -137,6 +137,8 @@ |
137 | 137 | * st_reg_complete - |
138 | 138 | * to call registration complete callbacks |
139 | 139 | * of all protocol stack drivers |
140 | + * This function is being called with spin lock held, protocol drivers are | |
141 | + * only expected to complete their waits and do nothing more than that. | |
140 | 142 | */ |
141 | 143 | void st_reg_complete(struct st_data_s *st_gdata, char err) |
142 | 144 | { |
143 | 145 | |
... | ... | @@ -538,11 +540,12 @@ |
538 | 540 | set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); |
539 | 541 | st_recv = st_kim_recv; |
540 | 542 | |
543 | + /* enable the ST LL - to set default chip state */ | |
544 | + st_ll_enable(st_gdata); | |
545 | + | |
541 | 546 | /* release lock previously held - re-locked below */ |
542 | 547 | spin_unlock_irqrestore(&st_gdata->lock, flags); |
543 | 548 | |
544 | - /* enable the ST LL - to set default chip state */ | |
545 | - st_ll_enable(st_gdata); | |
546 | 549 | /* this may take a while to complete |
547 | 550 | * since it involves BT fw download |
548 | 551 | */ |
549 | 552 | |
... | ... | @@ -553,10 +556,13 @@ |
553 | 556 | (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { |
554 | 557 | pr_err(" KIM failure complete callback "); |
555 | 558 | st_reg_complete(st_gdata, err); |
559 | + clear_bit(ST_REG_PENDING, &st_gdata->st_state); | |
556 | 560 | } |
557 | 561 | return -EINVAL; |
558 | 562 | } |
559 | 563 | |
564 | + spin_lock_irqsave(&st_gdata->lock, flags); | |
565 | + | |
560 | 566 | clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); |
561 | 567 | st_recv = st_int_recv; |
562 | 568 | |
563 | 569 | |
... | ... | @@ -576,10 +582,10 @@ |
576 | 582 | if (st_gdata->is_registered[new_proto->chnl_id] == true) { |
577 | 583 | pr_err(" proto %d already registered ", |
578 | 584 | new_proto->chnl_id); |
585 | + spin_unlock_irqrestore(&st_gdata->lock, flags); | |
579 | 586 | return -EALREADY; |
580 | 587 | } |
581 | 588 | |
582 | - spin_lock_irqsave(&st_gdata->lock, flags); | |
583 | 589 | add_channel_to_table(st_gdata, new_proto); |
584 | 590 | st_gdata->protos_registered++; |
585 | 591 | new_proto->write = st_write; |
... | ... | @@ -619,7 +625,7 @@ |
619 | 625 | |
620 | 626 | spin_lock_irqsave(&st_gdata->lock, flags); |
621 | 627 | |
622 | - if (st_gdata->list[proto->chnl_id] == NULL) { | |
628 | + if (st_gdata->is_registered[proto->chnl_id] == false) { | |
623 | 629 | pr_err(" chnl_id %d not registered", proto->chnl_id); |
624 | 630 | spin_unlock_irqrestore(&st_gdata->lock, flags); |
625 | 631 | return -EPROTONOSUPPORT; |
... | ... | @@ -628,6 +634,10 @@ |
628 | 634 | st_gdata->protos_registered--; |
629 | 635 | remove_channel_from_table(st_gdata, proto); |
630 | 636 | spin_unlock_irqrestore(&st_gdata->lock, flags); |
637 | + | |
638 | + /* paranoid check */ | |
639 | + if (st_gdata->protos_registered < ST_EMPTY) | |
640 | + st_gdata->protos_registered = ST_EMPTY; | |
631 | 641 | |
632 | 642 | if ((st_gdata->protos_registered == ST_EMPTY) && |
633 | 643 | (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { |