--- zzzz-none-000/linux-3.10.107/drivers/misc/ti-st/st_core.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/misc/ti-st/st_core.c 2021-02-04 17:41:59.000000000 +0000 @@ -22,7 +22,6 @@ #define pr_fmt(fmt) "(stc): " fmt #include #include -#include #include #include @@ -154,8 +153,9 @@ (st_gdata->list[i]->priv_data, err); pr_info("protocol %d's cb sent %d\n", i, err); if (err) { /* cleanup registered protocol */ - st_gdata->protos_registered--; st_gdata->is_registered[i] = false; + if (st_gdata->protos_registered) + st_gdata->protos_registered--; } } } @@ -343,12 +343,26 @@ /* Unknow packet? */ default: type = *ptr; - if (st_gdata->list[type] == NULL) { - pr_err("chip/interface misbehavior dropping" - " frame starting with 0x%02x", type); - goto done; + /* Default case means non-HCILL packets, + * possibilities are packets for: + * (a) valid protocol - Supported Protocols within + * the ST_MAX_CHANNELS. + * (b) registered protocol - Checked by + * "st_gdata->list[type] == NULL)" are supported + * protocols only. + * Rules out any invalid protocol and + * unregistered protocols with channel ID < 16. + */ + + if ((type >= ST_MAX_CHANNELS) || + (st_gdata->list[type] == NULL)) { + pr_err("chip/interface misbehavior: " + "dropping frame starting " + "with 0x%02x\n", type); + goto done; } + st_gdata->rx_skb = alloc_skb( st_gdata->list[type]->max_frame_size, GFP_ATOMIC); @@ -446,6 +460,13 @@ * - TTY layer when write's finished * - st_write (in context of the protocol stack) */ +static void work_fn_write_wakeup(struct work_struct *work) +{ + struct st_data_s *st_gdata = container_of(work, struct st_data_s, + work_write_wakeup); + + st_tx_wakeup((void *)st_gdata); +} void st_tx_wakeup(struct st_data_s *st_data) { struct sk_buff *skb; @@ -562,7 +583,9 @@ if ((st_gdata->protos_registered != ST_EMPTY) && (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { pr_err(" KIM failure complete callback "); + spin_lock_irqsave(&st_gdata->lock, flags); st_reg_complete(st_gdata, err); + spin_unlock_irqrestore(&st_gdata->lock, flags); clear_bit(ST_REG_PENDING, &st_gdata->st_state); } return -EINVAL; @@ -638,14 +661,12 @@ return -EPROTONOSUPPORT; } - st_gdata->protos_registered--; + if (st_gdata->protos_registered) + st_gdata->protos_registered--; + remove_channel_from_table(st_gdata, proto); spin_unlock_irqrestore(&st_gdata->lock, flags); - /* paranoid check */ - if (st_gdata->protos_registered < ST_EMPTY) - st_gdata->protos_registered = ST_EMPTY; - if ((st_gdata->protos_registered == ST_EMPTY) && (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { pr_info(" all chnl_ids unregistered "); @@ -798,8 +819,12 @@ /* don't do an wakeup for now */ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - /* call our internal wakeup */ - st_tx_wakeup((void *)st_gdata); + /* + * schedule the internal wakeup instead of calling directly to + * avoid lockup (port->lock needed in tty->ops->write is + * already taken here + */ + schedule_work(&st_gdata->work_write_wakeup); } static void st_tty_flush_buffer(struct tty_struct *tty) @@ -810,7 +835,7 @@ kfree_skb(st_gdata->tx_skb); st_gdata->tx_skb = NULL; - tty->ops->flush_buffer(tty); + tty_driver_flush_buffer(tty); return; } @@ -867,6 +892,9 @@ pr_err("unable to un-register ldisc"); return err; } + + INIT_WORK(&st_gdata->work_write_wakeup, work_fn_write_wakeup); + *core_data = st_gdata; return 0; } @@ -893,5 +921,3 @@ kfree(st_gdata); } } - -