Skip to content

Commit

Permalink
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/bluetooth/bluetooth-next

Johan Hedberg says:

====================
pull request: bluetooth-next 2020-09-29

Here's the main bluetooth-next pull request for 5.10:

 - Multiple fixes to suspend/resume handling
 - Added mgmt events for controller suspend/resume state
 - Improved extended advertising support
 - btintel: Enhanced support for next generation controllers
 - Added Qualcomm Bluetooth SoC WCN6855 support
 - Several other smaller fixes & improvements
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Sep 29, 2020
2 parents fe38d95 + b40f58b commit 2bd056f
Show file tree
Hide file tree
Showing 22 changed files with 851 additions and 174 deletions.
291 changes: 285 additions & 6 deletions drivers/bluetooth/btintel.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@

#define VERSION "0.1"

#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}})
#define BDADDR_INTEL (&(bdaddr_t){{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}})
#define RSA_HEADER_LEN 644
#define CSS_HEADER_OFFSET 8
#define ECDSA_OFFSET 644
#define ECDSA_HEADER_LEN 320

int btintel_check_bdaddr(struct hci_dev *hdev)
{
Expand Down Expand Up @@ -360,6 +364,144 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)
}
EXPORT_SYMBOL_GPL(btintel_read_version);

void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
{
const char *variant;

switch (version->img_type) {
case 0x01:
variant = "Bootloader";
bt_dev_info(hdev, "Device revision is %u", version->dev_rev_id);
bt_dev_info(hdev, "Secure boot is %s",
version->secure_boot ? "enabled" : "disabled");
bt_dev_info(hdev, "OTP lock is %s",
version->otp_lock ? "enabled" : "disabled");
bt_dev_info(hdev, "API lock is %s",
version->api_lock ? "enabled" : "disabled");
bt_dev_info(hdev, "Debug lock is %s",
version->debug_lock ? "enabled" : "disabled");
bt_dev_info(hdev, "Minimum firmware build %u week %u %u",
version->min_fw_build_nn, version->min_fw_build_cw,
2000 + version->min_fw_build_yy);
break;
case 0x03:
variant = "Firmware";
break;
default:
bt_dev_err(hdev, "Unsupported image type(%02x)", version->img_type);
goto done;
}

bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
2000 + (version->timestamp >> 8), version->timestamp & 0xff,
version->build_type, version->build_num);

done:
return;
}
EXPORT_SYMBOL_GPL(btintel_version_info_tlv);

int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
{
struct sk_buff *skb;
const u8 param[1] = { 0xFF };

if (!version)
return -EINVAL;

skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}

if (skb->data[0]) {
bt_dev_err(hdev, "Intel Read Version command failed (%02x)",
skb->data[0]);
kfree_skb(skb);
return -EIO;
}

/* Consume Command Complete Status field */
skb_pull(skb, 1);

/* Event parameters contatin multiple TLVs. Read each of them
* and only keep the required data. Also, it use existing legacy
* version field like hw_platform, hw_variant, and fw_variant
* to keep the existing setup flow
*/
while (skb->len) {
struct intel_tlv *tlv;

tlv = (struct intel_tlv *)skb->data;
switch (tlv->type) {
case INTEL_TLV_CNVI_TOP:
version->cnvi_top = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_CNVR_TOP:
version->cnvr_top = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_CNVI_BT:
version->cnvi_bt = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_CNVR_BT:
version->cnvr_bt = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_DEV_REV_ID:
version->dev_rev_id = get_unaligned_le16(tlv->val);
break;
case INTEL_TLV_IMAGE_TYPE:
version->img_type = tlv->val[0];
break;
case INTEL_TLV_TIME_STAMP:
version->timestamp = get_unaligned_le16(tlv->val);
break;
case INTEL_TLV_BUILD_TYPE:
version->build_type = tlv->val[0];
break;
case INTEL_TLV_BUILD_NUM:
version->build_num = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_SECURE_BOOT:
version->secure_boot = tlv->val[0];
break;
case INTEL_TLV_OTP_LOCK:
version->otp_lock = tlv->val[0];
break;
case INTEL_TLV_API_LOCK:
version->api_lock = tlv->val[0];
break;
case INTEL_TLV_DEBUG_LOCK:
version->debug_lock = tlv->val[0];
break;
case INTEL_TLV_MIN_FW:
version->min_fw_build_nn = tlv->val[0];
version->min_fw_build_cw = tlv->val[1];
version->min_fw_build_yy = tlv->val[2];
break;
case INTEL_TLV_LIMITED_CCE:
version->limited_cce = tlv->val[0];
break;
case INTEL_TLV_SBE_TYPE:
version->sbe_type = tlv->val[0];
break;
case INTEL_TLV_OTP_BDADDR:
memcpy(&version->otp_bd_addr, tlv->val, tlv->len);
break;
default:
/* Ignore rest of information */
break;
}
/* consume the current tlv and move to next*/
skb_pull(skb, tlv->len + sizeof(*tlv));
}

kfree_skb(skb);
return 0;
}
EXPORT_SYMBOL_GPL(btintel_read_version_tlv);

/* ------- REGMAP IBT SUPPORT ------- */

#define IBT_REG_MODE_8BIT 0x00
Expand Down Expand Up @@ -626,12 +768,10 @@ int btintel_read_boot_params(struct hci_dev *hdev,
}
EXPORT_SYMBOL_GPL(btintel_read_boot_params);

int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
u32 *boot_param)
static int btintel_sfi_rsa_header_secure_send(struct hci_dev *hdev,
const struct firmware *fw)
{
int err;
const u8 *fw_ptr;
u32 frag_len;

/* Start the firmware download transaction with the Init fragment
* represented by the 128 bytes of CSS header.
Expand Down Expand Up @@ -660,8 +800,56 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
goto done;
}

fw_ptr = fw->data + 644;
done:
return err;
}

static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev,
const struct firmware *fw)
{
int err;

/* Start the firmware download transaction with the Init fragment
* represented by the 128 bytes of CSS header.
*/
err = btintel_secure_send(hdev, 0x00, 128, fw->data + 644);
if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
return err;
}

/* Send the 96 bytes of public key information from the firmware
* as the PKey fragment.
*/
err = btintel_secure_send(hdev, 0x03, 96, fw->data + 644 + 128);
if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err);
return err;
}

/* Send the 96 bytes of signature information from the firmware
* as the Sign fragment
*/
err = btintel_secure_send(hdev, 0x02, 96, fw->data + 644 + 224);
if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware signature (%d)",
err);
return err;
}
return 0;
}

static int btintel_download_firmware_payload(struct hci_dev *hdev,
const struct firmware *fw,
u32 *boot_param, size_t offset)
{
int err;
const u8 *fw_ptr;
u32 frag_len;

fw_ptr = fw->data + offset;
frag_len = 0;
err = -EINVAL;

while (fw_ptr - fw->data < fw->size) {
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
Expand Down Expand Up @@ -707,8 +895,99 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
done:
return err;
}

int btintel_download_firmware(struct hci_dev *hdev,
const struct firmware *fw,
u32 *boot_param)
{
int err;

err = btintel_sfi_rsa_header_secure_send(hdev, fw);
if (err)
return err;

return btintel_download_firmware_payload(hdev, fw, boot_param,
RSA_HEADER_LEN);
}
EXPORT_SYMBOL_GPL(btintel_download_firmware);

int btintel_download_firmware_newgen(struct hci_dev *hdev,
const struct firmware *fw, u32 *boot_param,
u8 hw_variant, u8 sbe_type)
{
int err;
u32 css_header_ver;

/* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support
* only RSA secure boot engine. Hence, the corresponding sfi file will
* have RSA header of 644 bytes followed by Command Buffer.
*
* iBT hardware variants 0x17, 0x18 onwards support both RSA and ECDSA
* secure boot engine. As a result, the corresponding sfi file will
* have RSA header of 644, ECDSA header of 320 bytes followed by
* Command Buffer.
*
* CSS Header byte positions 0x08 to 0x0B represent the CSS Header
* version: RSA(0x00010000) , ECDSA (0x00020000)
*/
css_header_ver = get_unaligned_le32(fw->data + CSS_HEADER_OFFSET);
if (css_header_ver != 0x00010000) {
bt_dev_err(hdev, "Invalid CSS Header version");
return -EINVAL;
}

if (hw_variant <= 0x14) {
if (sbe_type != 0x00) {
bt_dev_err(hdev, "Invalid SBE type for hardware variant (%d)",
hw_variant);
return -EINVAL;
}

err = btintel_sfi_rsa_header_secure_send(hdev, fw);
if (err)
return err;

err = btintel_download_firmware_payload(hdev, fw, boot_param, RSA_HEADER_LEN);
if (err)
return err;
} else if (hw_variant >= 0x17) {
/* Check if CSS header for ECDSA follows the RSA header */
if (fw->data[ECDSA_OFFSET] != 0x06)
return -EINVAL;

/* Check if the CSS Header version is ECDSA(0x00020000) */
css_header_ver = get_unaligned_le32(fw->data + ECDSA_OFFSET + CSS_HEADER_OFFSET);
if (css_header_ver != 0x00020000) {
bt_dev_err(hdev, "Invalid CSS Header version");
return -EINVAL;
}

if (sbe_type == 0x00) {
err = btintel_sfi_rsa_header_secure_send(hdev, fw);
if (err)
return err;

err = btintel_download_firmware_payload(hdev, fw,
boot_param,
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
if (err)
return err;
} else if (sbe_type == 0x01) {
err = btintel_sfi_ecdsa_header_secure_send(hdev, fw);
if (err)
return err;

err = btintel_download_firmware_payload(hdev, fw,
boot_param,
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
if (err)
return err;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(btintel_download_firmware_newgen);

void btintel_reset_to_bootloader(struct hci_dev *hdev)
{
struct intel_reset params;
Expand Down
Loading

0 comments on commit 2bd056f

Please sign in to comment.