Hi Loic, > This patch adds rampatch download compatibility for ROME >= 3.2. > Starting with ROME 3.2, the 'download mode' field of the rampatch > header indicates if the controller acknowledges (or not) the received > rampatch segments. If not, we need to send all the segments without > expecting any event from the controller (except for the last segment). > Goal is (I assume) to speed-up rampatch download. WHYYYYYYYYYY ??? I have done the measurement with the Intel chips and it is insignificant on Linux. The Linux USB subsystem is a lot better than the one from Windows. Is there any chance we can just switch this back on and keep waiting for the event? > This fixes BT on Dragonboard-600c P2 which includes the following BT > controller: > > hci0: ROME Patch Version Request > hci0: Product:0x00000008 > hci0: Patch :0x00000111 > hci0: ROM :0x00000302 > hci0: SOC :0x00000023 > > Signed-off-by: Loic Poulain <loic.poulain@xxxxxxxxxx> > --- > drivers/bluetooth/btqca.c | 106 ++++++++++++++++++++++------------------------ > drivers/bluetooth/btqca.h | 11 ++++- > 2 files changed, 61 insertions(+), 56 deletions(-) > > diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c > index 2793d41..129779e 100644 > --- a/drivers/bluetooth/btqca.c > +++ b/drivers/bluetooth/btqca.c > @@ -127,28 +127,42 @@ static void rome_tlv_check_data(struct rome_config *config, > BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff); > BT_DBG("Length\t\t : %d bytes", length); > > + config->dnld_mode = ROME_SKIP_EVT_NONE; > + > switch (config->type) { > case TLV_TYPE_PATCH: > tlv_patch = (struct tlv_type_patch *)tlv->data; > - BT_DBG("Total Length\t\t : %d bytes", > + > + /* For Rome version 1.1 to 3.1, all segment commands > + * are acked by a vendor specific event (VSE). > + * For Rome >= 3.2, the download mode field indicates > + * if VSE is skipped by the controller. > + * In case VSE is skipped, only the last segment is acked. > + */ > + if (le16_to_cpu(tlv_patch->rom_build) >= 0x0302) > + config->dnld_mode = tlv_patch->download_mode; > + > + BT_DBG("Total Length : %d bytes", > le32_to_cpu(tlv_patch->total_size)); > - BT_DBG("Patch Data Length\t : %d bytes", > + BT_DBG("Patch Data Length : %d bytes", > le32_to_cpu(tlv_patch->data_length)); > BT_DBG("Signing Format Version : 0x%x", > tlv_patch->format_version); > - BT_DBG("Signature Algorithm\t : 0x%x", > + BT_DBG("Signature Algorithm : 0x%x", > tlv_patch->signature); > - BT_DBG("Reserved\t\t : 0x%x", > - le16_to_cpu(tlv_patch->reserved1)); > - BT_DBG("Product ID\t\t : 0x%04x", > + BT_DBG("Download mode : 0x%x", > + tlv_patch->download_mode); > + BT_DBG("Reserved : 0x%x", > + tlv_patch->reserved1); > + BT_DBG("Product ID : 0x%04x", > le16_to_cpu(tlv_patch->product_id)); > - BT_DBG("Rom Build Version\t : 0x%04x", > + BT_DBG("Rom Build Version : 0x%04x", > le16_to_cpu(tlv_patch->rom_build)); > - BT_DBG("Patch Version\t\t : 0x%04x", > + BT_DBG("Patch Version : 0x%04x", > le16_to_cpu(tlv_patch->patch_version)); > - BT_DBG("Reserved\t\t : 0x%x", > + BT_DBG("Reserved : 0x%x", > le16_to_cpu(tlv_patch->reserved2)); > - BT_DBG("Patch Entry Address\t : 0x%x", > + BT_DBG("Patch Entry Address : 0x%x", > le32_to_cpu(tlv_patch->entry)); > break; > > @@ -194,8 +208,8 @@ static void rome_tlv_check_data(struct rome_config *config, > } > } > > -static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size, > - const u8 *data) > +static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size, > + const u8 *data, enum rome_tlv_dnld_mode mode) > { > struct sk_buff *skb; > struct edl_event_hdr *edl; > @@ -203,12 +217,15 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size, > u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2]; > int err = 0; > > - BT_DBG("%s: Download segment #%d size %d", hdev->name, idx, seg_size); > - > cmd[0] = EDL_PATCH_TLV_REQ_CMD; > cmd[1] = seg_size; > memcpy(cmd + 2, data, seg_size); > > + if (mode == ROME_SKIP_EVT_VSE_CC || mode == ROME_SKIP_EVT_VSE) { > + return __hci_cmd_sync_noev(hdev, EDL_PATCH_CMD_OPCODE, > + seg_size + 2, cmd); > + } > + No need for {} here. > skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd, > HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); > if (IS_ERR(skb)) { > @@ -245,47 +262,12 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size, > return err; > } > > -static int rome_tlv_download_request(struct hci_dev *hdev, > - const struct firmware *fw) > -{ > - const u8 *buffer, *data; > - int total_segment, remain_size; > - int ret, i; > - > - if (!fw || !fw->data) > - return -EINVAL; > - > - total_segment = fw->size / MAX_SIZE_PER_TLV_SEGMENT; > - remain_size = fw->size % MAX_SIZE_PER_TLV_SEGMENT; > - > - BT_DBG("%s: Total segment num %d remain size %d total size %zu", > - hdev->name, total_segment, remain_size, fw->size); > - > - data = fw->data; > - for (i = 0; i < total_segment; i++) { > - buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT; > - ret = rome_tlv_send_segment(hdev, i, MAX_SIZE_PER_TLV_SEGMENT, > - buffer); > - if (ret < 0) > - return -EIO; > - } > - > - if (remain_size) { > - buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT; > - ret = rome_tlv_send_segment(hdev, total_segment, remain_size, > - buffer); > - if (ret < 0) > - return -EIO; > - } > - > - return 0; > -} > - > static int rome_download_firmware(struct hci_dev *hdev, > struct rome_config *config) > { > const struct firmware *fw; > - int ret; > + const u8 *segment; > + int ret, remain, i = 0; > > bt_dev_info(hdev, "ROME Downloading %s", config->fwname); > > @@ -298,10 +280,24 @@ static int rome_download_firmware(struct hci_dev *hdev, > > rome_tlv_check_data(config, fw); > > - ret = rome_tlv_download_request(hdev, fw); > - if (ret) { > - BT_ERR("%s: Failed to download file: %s (%d)", hdev->name, > - config->fwname, ret); > + segment = fw->data; > + remain = fw->size; > + while (remain > 0) { > + int segsize = min(MAX_SIZE_PER_TLV_SEGMENT, remain); > + > + bt_dev_dbg(hdev, "Send segment %d, size %d", i++, segsize); > + > + remain -= segsize; > + /* The last segment is always acked regardless download mode */ > + if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT) > + config->dnld_mode = ROME_SKIP_EVT_NONE; > + > + ret = rome_tlv_send_segment(hdev, segsize, segment, > + config->dnld_mode); > + if (ret) > + break; > + > + segment += segsize; > } > > release_firmware(fw); > diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h > index 65e994b..13d77fd 100644 > --- a/drivers/bluetooth/btqca.h > +++ b/drivers/bluetooth/btqca.h > @@ -61,6 +61,13 @@ enum qca_bardrate { > QCA_BAUDRATE_RESERVED > }; > > +enum rome_tlv_dnld_mode { > + ROME_SKIP_EVT_NONE, > + ROME_SKIP_EVT_VSE, > + ROME_SKIP_EVT_CC, > + ROME_SKIP_EVT_VSE_CC > +}; > + > enum rome_tlv_type { > TLV_TYPE_PATCH = 1, > TLV_TYPE_NVM > @@ -70,6 +77,7 @@ struct rome_config { > u8 type; > char fwname[64]; > uint8_t user_baud_rate; > + enum rome_tlv_dnld_mode dnld_mode; > }; > > struct edl_event_hdr { > @@ -94,7 +102,8 @@ struct tlv_type_patch { > __le32 data_length; > __u8 format_version; > __u8 signature; > - __le16 reserved1; > + __u8 download_mode; > + __u8 reserved1; > __le16 product_id; > __le16 rom_build; > __le16 patch_version; Regards Marcel -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html