On Fri, Dec 28, 2018 at 05:18:19PM +0530, Balakrishna Godavarthi wrote: > Latest qualcomm chips are not sending an command complete event for > every firmware packet sent to chip. They only respond with a vendor > specific event for the last firmware packet. This optimization will > decrease the BT ON time. Due to this we are seeing a timeout error > message logs on the console during firmware download. Now we are > injecting a command complete event once we receive an vendor specific > event for the last RAM firmware packet. > > Signed-off-by: Balakrishna Godavarthi <bgodavar@xxxxxxxxxxxxxx> > --- > drivers/bluetooth/btqca.c | 39 ++++++++++++++++++++++++++++++++++++++- > drivers/bluetooth/btqca.h | 3 +++ > 2 files changed, 41 insertions(+), 1 deletion(-) > > diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c > index ec9e03a6b778..0b533f65f652 100644 > --- a/drivers/bluetooth/btqca.c > +++ b/drivers/bluetooth/btqca.c > @@ -144,6 +144,7 @@ static void qca_tlv_check_data(struct rome_config *config, > * In case VSE is skipped, only the last segment is acked. > */ > config->dnld_mode = tlv_patch->download_mode; > + config->dnld_type = config->dnld_mode; > > BT_DBG("Total Length : %d bytes", > le32_to_cpu(tlv_patch->total_size)); > @@ -264,6 +265,31 @@ static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size, > return err; > } > > +static int qca_inject_cmd_complete_event(struct hci_dev *hdev) > +{ > + struct hci_event_hdr *hdr; > + struct hci_ev_cmd_complete *evt; > + struct sk_buff *skb; > + > + skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL); > + if (!skb) > + return -ENOMEM; > + > + hdr = skb_put(skb, sizeof(*hdr)); > + hdr->evt = HCI_EV_CMD_COMPLETE; > + hdr->plen = sizeof(*evt) + 1; > + > + evt = skb_put(skb, sizeof(*evt)); > + evt->ncmd = 1; > + evt->opcode = HCI_OP_NOP; > + > + skb_put_u8(skb, QCA_HCI_CC_SUCCESS); > + > + hci_skb_pkt_type(skb) = HCI_EVENT_PKT; > + > + return hci_recv_frame(hdev, skb); > +} > + > static int qca_download_firmware(struct hci_dev *hdev, > struct rome_config *config) > { > @@ -297,11 +323,22 @@ static int qca_download_firmware(struct hci_dev *hdev, > ret = qca_tlv_send_segment(hdev, segsize, segment, > config->dnld_mode); > if (ret) > - break; > + goto out; > > segment += segsize; > } > > + /* Latest qualcomm chipsets are not sending a command complete event > + * for every fw packet sent. They only respond with a vendor specific > + * event for the last packet. This optimization in the chip will > + * decrease the BT in initialization time. Here we will inject a command > + * complete event to avoid a command timeout error message. > + */ > + if ((config->dnld_type == ROME_SKIP_EVT_VSE_CC || > + config->dnld_type == ROME_SKIP_EVT_VSE)) > + return qca_inject_cmd_complete_event(hdev); > + > +out: > release_firmware(fw); > > return ret; > diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h > index 0c01f375fe83..5c8fc54133e3 100644 > --- a/drivers/bluetooth/btqca.h > +++ b/drivers/bluetooth/btqca.h > @@ -40,6 +40,8 @@ > #define QCA_WCN3990_POWERON_PULSE 0xFC > #define QCA_WCN3990_POWEROFF_PULSE 0xC0 > > +#define QCA_HCI_CC_SUCCESS 0x00 > + > enum qca_bardrate { > QCA_BAUDRATE_115200 = 0, > QCA_BAUDRATE_57600, > @@ -81,6 +83,7 @@ struct rome_config { > char fwname[64]; > uint8_t user_baud_rate; > enum rome_tlv_dnld_mode dnld_mode; > + enum rome_tlv_dnld_mode dnld_type; The ->dnld_type vs ->dnld_mode is a bit confusing, I don't have a better suggestion though. > }; > > struct edl_event_hdr { I'm not an expert in dealing with HCI SKBs, as far as I can tell the above looks sane to me and I confirmed that it fixes the timeout when downloading firmware. Tested-by: Matthias Kaehlcke <mka@xxxxxxxxxxxx> Reviewed-by: Matthias Kaehlcke <mka@xxxxxxxxxxxx>