diff options
author | Balakrishna Godavarthi <bgodavar@codeaurora.org> | 2019-05-28 17:43:22 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2019-07-06 06:45:02 -0400 |
commit | 32646db8cc2862a14788de1bb4c365d0a27fb532 (patch) | |
tree | ac088126ff11fc18ab30d62b8e0a2a1b344dc666 /drivers/bluetooth | |
parent | 82b7d856649988b5ddaad5f17abb787f6909107f (diff) |
Bluetooth: btqca: inject command complete event during fw download
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@codeaurora.org>
Tested-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/btqca.c | 39 | ||||
-rw-r--r-- | drivers/bluetooth/btqca.h | 4 |
2 files changed, 42 insertions, 1 deletions
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index aff1d22223bd..6ce5c8835efe 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c | |||
@@ -131,6 +131,7 @@ static void qca_tlv_check_data(struct rome_config *config, | |||
131 | * In case VSE is skipped, only the last segment is acked. | 131 | * In case VSE is skipped, only the last segment is acked. |
132 | */ | 132 | */ |
133 | config->dnld_mode = tlv_patch->download_mode; | 133 | config->dnld_mode = tlv_patch->download_mode; |
134 | config->dnld_type = config->dnld_mode; | ||
134 | 135 | ||
135 | BT_DBG("Total Length : %d bytes", | 136 | BT_DBG("Total Length : %d bytes", |
136 | le32_to_cpu(tlv_patch->total_size)); | 137 | le32_to_cpu(tlv_patch->total_size)); |
@@ -251,6 +252,31 @@ out: | |||
251 | return err; | 252 | return err; |
252 | } | 253 | } |
253 | 254 | ||
255 | static int qca_inject_cmd_complete_event(struct hci_dev *hdev) | ||
256 | { | ||
257 | struct hci_event_hdr *hdr; | ||
258 | struct hci_ev_cmd_complete *evt; | ||
259 | struct sk_buff *skb; | ||
260 | |||
261 | skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL); | ||
262 | if (!skb) | ||
263 | return -ENOMEM; | ||
264 | |||
265 | hdr = skb_put(skb, sizeof(*hdr)); | ||
266 | hdr->evt = HCI_EV_CMD_COMPLETE; | ||
267 | hdr->plen = sizeof(*evt) + 1; | ||
268 | |||
269 | evt = skb_put(skb, sizeof(*evt)); | ||
270 | evt->ncmd = 1; | ||
271 | evt->opcode = QCA_HCI_CC_OPCODE; | ||
272 | |||
273 | skb_put_u8(skb, QCA_HCI_CC_SUCCESS); | ||
274 | |||
275 | hci_skb_pkt_type(skb) = HCI_EVENT_PKT; | ||
276 | |||
277 | return hci_recv_frame(hdev, skb); | ||
278 | } | ||
279 | |||
254 | static int qca_download_firmware(struct hci_dev *hdev, | 280 | static int qca_download_firmware(struct hci_dev *hdev, |
255 | struct rome_config *config) | 281 | struct rome_config *config) |
256 | { | 282 | { |
@@ -284,11 +310,22 @@ static int qca_download_firmware(struct hci_dev *hdev, | |||
284 | ret = qca_tlv_send_segment(hdev, segsize, segment, | 310 | ret = qca_tlv_send_segment(hdev, segsize, segment, |
285 | config->dnld_mode); | 311 | config->dnld_mode); |
286 | if (ret) | 312 | if (ret) |
287 | break; | 313 | goto out; |
288 | 314 | ||
289 | segment += segsize; | 315 | segment += segsize; |
290 | } | 316 | } |
291 | 317 | ||
318 | /* Latest qualcomm chipsets are not sending a command complete event | ||
319 | * for every fw packet sent. They only respond with a vendor specific | ||
320 | * event for the last packet. This optimization in the chip will | ||
321 | * decrease the BT in initialization time. Here we will inject a command | ||
322 | * complete event to avoid a command timeout error message. | ||
323 | */ | ||
324 | if (config->dnld_type == ROME_SKIP_EVT_VSE_CC || | ||
325 | config->dnld_type == ROME_SKIP_EVT_VSE) | ||
326 | return qca_inject_cmd_complete_event(hdev); | ||
327 | |||
328 | out: | ||
292 | release_firmware(fw); | 329 | release_firmware(fw); |
293 | 330 | ||
294 | return ret; | 331 | return ret; |
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h index e9c999959603..03fdec20730b 100644 --- a/drivers/bluetooth/btqca.h +++ b/drivers/bluetooth/btqca.h | |||
@@ -28,6 +28,9 @@ | |||
28 | #define QCA_WCN3990_POWERON_PULSE 0xFC | 28 | #define QCA_WCN3990_POWERON_PULSE 0xFC |
29 | #define QCA_WCN3990_POWEROFF_PULSE 0xC0 | 29 | #define QCA_WCN3990_POWEROFF_PULSE 0xC0 |
30 | 30 | ||
31 | #define QCA_HCI_CC_OPCODE 0xFC00 | ||
32 | #define QCA_HCI_CC_SUCCESS 0x00 | ||
33 | |||
31 | enum qca_baudrate { | 34 | enum qca_baudrate { |
32 | QCA_BAUDRATE_115200 = 0, | 35 | QCA_BAUDRATE_115200 = 0, |
33 | QCA_BAUDRATE_57600, | 36 | QCA_BAUDRATE_57600, |
@@ -69,6 +72,7 @@ struct rome_config { | |||
69 | char fwname[64]; | 72 | char fwname[64]; |
70 | uint8_t user_baud_rate; | 73 | uint8_t user_baud_rate; |
71 | enum rome_tlv_dnld_mode dnld_mode; | 74 | enum rome_tlv_dnld_mode dnld_mode; |
75 | enum rome_tlv_dnld_mode dnld_type; | ||
72 | }; | 76 | }; |
73 | 77 | ||
74 | struct edl_event_hdr { | 78 | struct edl_event_hdr { |