Commit bfb88d6c91a2cf507ff7763ebec94d72b4c98b07

Authored by Pavan Savoy
Committed by Greg Kroah-Hartman
1 parent 1ff97647f0

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))) {