aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/ti-st
diff options
context:
space:
mode:
authorPavan Savoy <pavan_savoy@ti.com>2011-12-15 11:38:20 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2012-01-04 18:21:03 -0500
commitbfb88d6c91a2cf507ff7763ebec94d72b4c98b07 (patch)
treeddb098bbb0ee412d6121d2e22061850d602b0a30 /drivers/misc/ti-st
parent1ff97647f066aef72ae68042c9abc4a837a12e6d (diff)
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>
Diffstat (limited to 'drivers/misc/ti-st')
-rw-r--r--drivers/misc/ti-st/st_core.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index ba168a7d54d4..2b62232c2c6a 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -137,6 +137,8 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
137 * st_reg_complete - 137 * st_reg_complete -
138 * to call registration complete callbacks 138 * to call registration complete callbacks
139 * of all protocol stack drivers 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 */
141void st_reg_complete(struct st_data_s *st_gdata, char err) 143void st_reg_complete(struct st_data_s *st_gdata, char err)
142{ 144{
@@ -538,11 +540,12 @@ long st_register(struct st_proto_s *new_proto)
538 set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 540 set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
539 st_recv = st_kim_recv; 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 /* release lock previously held - re-locked below */ 546 /* release lock previously held - re-locked below */
542 spin_unlock_irqrestore(&st_gdata->lock, flags); 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 /* this may take a while to complete 549 /* this may take a while to complete
547 * since it involves BT fw download 550 * since it involves BT fw download
548 */ 551 */
@@ -553,10 +556,13 @@ long st_register(struct st_proto_s *new_proto)
553 (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 556 (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
554 pr_err(" KIM failure complete callback "); 557 pr_err(" KIM failure complete callback ");
555 st_reg_complete(st_gdata, err); 558 st_reg_complete(st_gdata, err);
559 clear_bit(ST_REG_PENDING, &st_gdata->st_state);
556 } 560 }
557 return -EINVAL; 561 return -EINVAL;
558 } 562 }
559 563
564 spin_lock_irqsave(&st_gdata->lock, flags);
565
560 clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 566 clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
561 st_recv = st_int_recv; 567 st_recv = st_int_recv;
562 568
@@ -576,10 +582,10 @@ long st_register(struct st_proto_s *new_proto)
576 if (st_gdata->is_registered[new_proto->chnl_id] == true) { 582 if (st_gdata->is_registered[new_proto->chnl_id] == true) {
577 pr_err(" proto %d already registered ", 583 pr_err(" proto %d already registered ",
578 new_proto->chnl_id); 584 new_proto->chnl_id);
585 spin_unlock_irqrestore(&st_gdata->lock, flags);
579 return -EALREADY; 586 return -EALREADY;
580 } 587 }
581 588
582 spin_lock_irqsave(&st_gdata->lock, flags);
583 add_channel_to_table(st_gdata, new_proto); 589 add_channel_to_table(st_gdata, new_proto);
584 st_gdata->protos_registered++; 590 st_gdata->protos_registered++;
585 new_proto->write = st_write; 591 new_proto->write = st_write;
@@ -619,7 +625,7 @@ long st_unregister(struct st_proto_s *proto)
619 625
620 spin_lock_irqsave(&st_gdata->lock, flags); 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 pr_err(" chnl_id %d not registered", proto->chnl_id); 629 pr_err(" chnl_id %d not registered", proto->chnl_id);
624 spin_unlock_irqrestore(&st_gdata->lock, flags); 630 spin_unlock_irqrestore(&st_gdata->lock, flags);
625 return -EPROTONOSUPPORT; 631 return -EPROTONOSUPPORT;
@@ -629,6 +635,10 @@ long st_unregister(struct st_proto_s *proto)
629 remove_channel_from_table(st_gdata, proto); 635 remove_channel_from_table(st_gdata, proto);
630 spin_unlock_irqrestore(&st_gdata->lock, flags); 636 spin_unlock_irqrestore(&st_gdata->lock, flags);
631 637
638 /* paranoid check */
639 if (st_gdata->protos_registered < ST_EMPTY)
640 st_gdata->protos_registered = ST_EMPTY;
641
632 if ((st_gdata->protos_registered == ST_EMPTY) && 642 if ((st_gdata->protos_registered == ST_EMPTY) &&
633 (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 643 (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
634 pr_info(" all chnl_ids unregistered "); 644 pr_info(" all chnl_ids unregistered ");