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 2018-01-25

Here's one last bluetooth-next pull request for the 4.16 kernel:

 - Improved support for Intel controllers
 - New set_parity method to serdev (agreed with maintainers to be taken
   through bluetooth-next)
 - Fix error path in hci_bcm (missing call to serdev close)
 - New ID for BCM4343A0 UART controller

Please let me know if there are any issues pulling. Thanks.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Jan 25, 2018
2 parents d9ac2d9 + fbbe83c commit 525d0ae
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 231 deletions.
1 change: 1 addition & 0 deletions drivers/bluetooth/btbcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ static const struct {
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
{ 0x4406, "BCM4324B3" }, /* 002.004.006 */
{ 0x610c, "BCM4354" }, /* 003.001.012 */
{ 0x2122, "BCM4343A0" }, /* 001.001.034 */
{ 0x2209, "BCM43430A1" }, /* 001.002.009 */
{ 0x6119, "BCM4345C0" }, /* 003.001.025 */
{ 0x230f, "BCM4356A2" }, /* 001.003.015 */
Expand Down
155 changes: 155 additions & 0 deletions drivers/bluetooth/btintel.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/regmap.h>
#include <asm/unaligned.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
Expand Down Expand Up @@ -569,6 +570,160 @@ struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
}
EXPORT_SYMBOL_GPL(btintel_regmap_init);

int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param)
{
struct intel_reset params = { 0x00, 0x01, 0x00, 0x01, 0x00000000 };
struct sk_buff *skb;

params.boot_param = cpu_to_le32(boot_param);

skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), &params,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to send Intel Reset command");
return PTR_ERR(skb);
}

kfree_skb(skb);

return 0;
}
EXPORT_SYMBOL_GPL(btintel_send_intel_reset);

int btintel_read_boot_params(struct hci_dev *hdev,
struct intel_boot_params *params)
{
struct sk_buff *skb;

skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reading Intel boot parameters failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}

if (skb->len != sizeof(*params)) {
bt_dev_err(hdev, "Intel boot parameters size mismatch");
kfree_skb(skb);
return -EILSEQ;
}

memcpy(params, skb->data, sizeof(*params));

kfree_skb(skb);

if (params->status) {
bt_dev_err(hdev, "Intel boot parameters command failed (%02x)",
params->status);
return -bt_to_errno(params->status);
}

bt_dev_info(hdev, "Device revision is %u",
le16_to_cpu(params->dev_revid));

bt_dev_info(hdev, "Secure boot is %s",
params->secure_boot ? "enabled" : "disabled");

bt_dev_info(hdev, "OTP lock is %s",
params->otp_lock ? "enabled" : "disabled");

bt_dev_info(hdev, "API lock is %s",
params->api_lock ? "enabled" : "disabled");

bt_dev_info(hdev, "Debug lock is %s",
params->debug_lock ? "enabled" : "disabled");

bt_dev_info(hdev, "Minimum firmware build %u week %u %u",
params->min_fw_build_nn, params->min_fw_build_cw,
2000 + params->min_fw_build_yy);

return 0;
}
EXPORT_SYMBOL_GPL(btintel_read_boot_params);

int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
u32 *boot_param)
{
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.
*/
err = btintel_secure_send(hdev, 0x00, 128, fw->data);
if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
goto done;
}

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

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

fw_ptr = fw->data + 644;
frag_len = 0;

while (fw_ptr - fw->data < fw->size) {
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);

/* Each SKU has a different reset parameter to use in the
* HCI_Intel_Reset command and it is embedded in the firmware
* data. So, instead of using static value per SKU, check
* the firmware data and save it for later use.
*/
if (le16_to_cpu(cmd->opcode) == 0xfc0e) {
/* The boot parameter is the first 32-bit value
* and rest of 3 octets are reserved.
*/
*boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd));

bt_dev_dbg(hdev, "boot_param=0x%x", *boot_param);
}

frag_len += sizeof(*cmd) + cmd->plen;

/* The parameter length of the secure send command requires
* a 4 byte alignment. It happens so that the firmware file
* contains proper Intel_NOP commands to align the fragments
* as needed.
*
* Send set of commands with 4 byte alignment from the
* firmware data buffer as a single Data fragement.
*/
if (!(frag_len % 4)) {
err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
if (err < 0) {
bt_dev_err(hdev,
"Failed to send firmware data (%d)",
err);
goto done;
}

fw_ptr += frag_len;
frag_len = 0;
}
}

done:
return err;
}
EXPORT_SYMBOL_GPL(btintel_download_firmware);

MODULE_AUTHOR("Marcel Holtmann <[email protected]>");
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
MODULE_VERSION(VERSION);
Expand Down
33 changes: 32 additions & 1 deletion drivers/bluetooth/btintel.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ struct intel_secure_send_result {
__u8 status;
} __packed;

struct intel_reset {
__u8 reset_type;
__u8 patch_enable;
__u8 ddc_reload;
__u8 boot_option;
__le32 boot_param;
} __packed;

#if IS_ENABLED(CONFIG_BT_INTEL)

int btintel_check_bdaddr(struct hci_dev *hdev);
Expand All @@ -89,7 +97,11 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver);

struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
u16 opcode_write);

int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param);
int btintel_read_boot_params(struct hci_dev *hdev,
struct intel_boot_params *params);
int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
u32 *boot_param);
#else

static inline int btintel_check_bdaddr(struct hci_dev *hdev)
Expand Down Expand Up @@ -165,4 +177,23 @@ static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev,
{
return ERR_PTR(-EINVAL);
}

static inline int btintel_send_intel_reset(struct hci_dev *hdev,
u32 reset_param)
{
return -EOPNOTSUPP;
}

static inline int btintel_read_boot_params(struct hci_dev *hdev,
struct intel_boot_params *params)
{
return -EOPNOTSUPP;
}

static inline int btintel_download_firmware(struct hci_dev *dev,
const struct firmware *fw,
u32 *boot_param)
{
return -EOPNOTSUPP;
}
#endif
Loading

0 comments on commit 525d0ae

Please sign in to comment.