2019-05-27 08:55:05 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-04-06 00:52:11 -07:00
/*
*
* Bluetooth support for Intel devices
*
* Copyright ( C ) 2015 Intel Corporation
*/
# include <linux/module.h>
2015-09-04 17:54:34 +02:00
# include <linux/firmware.h>
2015-10-01 18:16:21 +02:00
# include <linux/regmap.h>
2018-01-24 09:19:21 -08:00
# include <asm/unaligned.h>
2015-04-06 00:52:11 -07:00
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
# include "btintel.h"
# define VERSION "0.1"
2020-09-14 18:55:06 +05:30
# 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
2015-04-06 00:52:11 -07:00
2021-03-23 11:58:56 -07:00
# define CMD_WRITE_BOOT_PARAMS 0xfc0e
struct cmd_write_boot_params {
u32 boot_addr ;
u8 fw_build_num ;
u8 fw_build_ww ;
u8 fw_build_yy ;
} __packed ;
2015-04-06 00:52:11 -07:00
int btintel_check_bdaddr ( struct hci_dev * hdev )
{
struct hci_rp_read_bd_addr * bda ;
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , HCI_OP_READ_BD_ADDR , 0 , NULL ,
HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
int err = PTR_ERR ( skb ) ;
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Reading Intel device address failed (%d) " ,
err ) ;
2015-04-06 00:52:11 -07:00
return err ;
}
if ( skb - > len ! = sizeof ( * bda ) ) {
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Intel device address length mismatch " ) ;
2015-04-06 00:52:11 -07:00
kfree_skb ( skb ) ;
return - EIO ;
}
bda = ( struct hci_rp_read_bd_addr * ) skb - > data ;
/* For some Intel based controllers, the default Bluetooth device
* address 00 : 03 : 19 : 9 E : 8 B : 00 can be found . These controllers are
* fully operational , but have the danger of duplicate addresses
* and that in turn can cause problems with Bluetooth operation .
*/
if ( ! bacmp ( & bda - > bdaddr , BDADDR_INTEL ) ) {
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Found Intel default device address (%pMR) " ,
& bda - > bdaddr ) ;
2015-04-06 00:52:11 -07:00
set_bit ( HCI_QUIRK_INVALID_BDADDR , & hdev - > quirks ) ;
}
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_check_bdaddr ) ;
2015-12-03 16:10:22 +01:00
int btintel_enter_mfg ( struct hci_dev * hdev )
{
2018-01-06 16:23:28 +00:00
static const u8 param [ ] = { 0x01 , 0x00 } ;
2015-12-03 16:10:22 +01:00
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , 0xfc11 , 2 , param , HCI_CMD_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
bt_dev_err ( hdev , " Entering manufacturer mode failed (%ld) " ,
PTR_ERR ( skb ) ) ;
return PTR_ERR ( skb ) ;
}
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_enter_mfg ) ;
int btintel_exit_mfg ( struct hci_dev * hdev , bool reset , bool patched )
{
u8 param [ ] = { 0x00 , 0x00 } ;
struct sk_buff * skb ;
/* The 2nd command parameter specifies the manufacturing exit method:
* 0x00 : Just disable the manufacturing mode ( 0x00 ) .
* 0x01 : Disable manufacturing mode and reset with patches deactivated .
* 0x02 : Disable manufacturing mode and reset with patches activated .
*/
if ( reset )
param [ 1 ] | = patched ? 0x02 : 0x01 ;
skb = __hci_cmd_sync ( hdev , 0xfc11 , 2 , param , HCI_CMD_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
bt_dev_err ( hdev , " Exiting manufacturer mode failed (%ld) " ,
PTR_ERR ( skb ) ) ;
return PTR_ERR ( skb ) ;
}
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_exit_mfg ) ;
2015-04-06 00:52:11 -07:00
int btintel_set_bdaddr ( struct hci_dev * hdev , const bdaddr_t * bdaddr )
{
struct sk_buff * skb ;
int err ;
skb = __hci_cmd_sync ( hdev , 0xfc31 , 6 , bdaddr , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Changing Intel device address failed (%d) " ,
err ) ;
2015-04-06 00:52:11 -07:00
return err ;
}
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_set_bdaddr ) ;
2015-10-09 14:42:08 +02:00
int btintel_set_diag ( struct hci_dev * hdev , bool enable )
{
struct sk_buff * skb ;
u8 param [ 3 ] ;
int err ;
if ( enable ) {
param [ 0 ] = 0x03 ;
param [ 1 ] = 0x03 ;
param [ 2 ] = 0x03 ;
} else {
param [ 0 ] = 0x00 ;
param [ 1 ] = 0x00 ;
param [ 2 ] = 0x00 ;
}
skb = __hci_cmd_sync ( hdev , 0xfc43 , 3 , param , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
2015-10-17 16:00:27 +02:00
if ( err = = - ENODATA )
2015-10-21 02:45:19 +02:00
goto done ;
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Changing Intel diagnostic mode failed (%d) " ,
err ) ;
2015-10-09 14:42:08 +02:00
return err ;
}
kfree_skb ( skb ) ;
2015-10-21 02:45:19 +02:00
done :
btintel_set_event_mask ( hdev , enable ) ;
2015-10-09 14:42:08 +02:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_set_diag ) ;
2021-08-04 17:32:10 -07:00
static int btintel_set_diag_mfg ( struct hci_dev * hdev , bool enable )
2015-10-17 16:00:28 +02:00
{
2015-12-03 16:10:22 +01:00
int err , ret ;
2015-10-17 16:00:28 +02:00
2015-12-03 16:10:22 +01:00
err = btintel_enter_mfg ( hdev ) ;
if ( err )
return err ;
2015-10-17 16:00:28 +02:00
2015-12-03 16:10:22 +01:00
ret = btintel_set_diag ( hdev , enable ) ;
2015-10-17 16:00:28 +02:00
2015-12-03 16:10:22 +01:00
err = btintel_exit_mfg ( hdev , false , false ) ;
if ( err )
return err ;
2015-10-17 16:00:28 +02:00
2015-12-03 16:10:22 +01:00
return ret ;
2015-10-17 16:00:28 +02:00
}
2015-07-05 14:37:38 +02:00
void btintel_hw_error ( struct hci_dev * hdev , u8 code )
{
struct sk_buff * skb ;
u8 type = 0x00 ;
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Hardware error 0x%2.2x " , code ) ;
2015-07-05 14:37:38 +02:00
skb = __hci_cmd_sync ( hdev , HCI_OP_RESET , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Reset after hardware error failed (%ld) " ,
PTR_ERR ( skb ) ) ;
2015-07-05 14:37:38 +02:00
return ;
}
kfree_skb ( skb ) ;
skb = __hci_cmd_sync ( hdev , 0xfc22 , 1 , & type , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Retrieving Intel exception info failed (%ld) " ,
PTR_ERR ( skb ) ) ;
2015-07-05 14:37:38 +02:00
return ;
}
if ( skb - > len ! = 13 ) {
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Exception info size mismatch " ) ;
2015-07-05 14:37:38 +02:00
kfree_skb ( skb ) ;
return ;
}
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Exception info %s " , ( char * ) ( skb - > data + 1 ) ) ;
2015-07-05 14:37:38 +02:00
kfree_skb ( skb ) ;
}
EXPORT_SYMBOL_GPL ( btintel_hw_error ) ;
2021-03-23 11:58:59 -07:00
int btintel_version_info ( struct hci_dev * hdev , struct intel_version * ver )
2015-07-05 15:02:07 +02:00
{
const char * variant ;
2021-03-23 11:58:59 -07:00
/* The hardware platform number has a fixed value of 0x37 and
* for now only accept this single value .
*/
if ( ver - > hw_platform ! = 0x37 ) {
bt_dev_err ( hdev , " Unsupported Intel hardware platform (%u) " ,
ver - > hw_platform ) ;
return - EINVAL ;
}
/* Check for supported iBT hardware variants of this firmware
* loading method .
*
* This check has been put in place to ensure correct forward
* compatibility options when newer hardware variants come along .
*/
switch ( ver - > hw_variant ) {
2021-08-04 17:32:09 -07:00
case 0x07 : /* WP - Legacy ROM */
case 0x08 : /* StP - Legacy ROM */
2021-03-23 11:58:59 -07:00
case 0x0b : /* SfP */
case 0x0c : /* WsP */
case 0x11 : /* JfP */
case 0x12 : /* ThP */
case 0x13 : /* HrP */
case 0x14 : /* CcP */
break ;
default :
bt_dev_err ( hdev , " Unsupported Intel hardware variant (%u) " ,
ver - > hw_variant ) ;
return - EINVAL ;
}
2015-07-05 15:02:07 +02:00
switch ( ver - > fw_variant ) {
2021-08-04 17:32:09 -07:00
case 0x01 :
variant = " Legacy ROM 2.5 " ;
break ;
2015-07-05 15:02:07 +02:00
case 0x06 :
variant = " Bootloader " ;
break ;
2021-08-04 17:32:09 -07:00
case 0x22 :
variant = " Legacy ROM 2.x " ;
break ;
2015-07-05 15:02:07 +02:00
case 0x23 :
variant = " Firmware " ;
break ;
default :
2021-03-23 11:58:59 -07:00
bt_dev_err ( hdev , " Unsupported firmware variant(%02x) " , ver - > fw_variant ) ;
return - EINVAL ;
2015-07-05 15:02:07 +02:00
}
2017-10-30 10:42:59 +01:00
bt_dev_info ( hdev , " %s revision %u.%u build %u week %u %u " ,
variant , ver - > fw_revision > > 4 , ver - > fw_revision & 0x0f ,
ver - > fw_build_num , ver - > fw_build_ww ,
2000 + ver - > fw_build_yy ) ;
2021-03-23 11:58:59 -07:00
return 0 ;
2015-07-05 15:02:07 +02:00
}
EXPORT_SYMBOL_GPL ( btintel_version_info ) ;
2015-07-05 14:55:36 +02:00
int btintel_secure_send ( struct hci_dev * hdev , u8 fragment_type , u32 plen ,
const void * param )
{
while ( plen > 0 ) {
struct sk_buff * skb ;
u8 cmd_param [ 253 ] , fragment_len = ( plen > 252 ) ? 252 : plen ;
cmd_param [ 0 ] = fragment_type ;
memcpy ( cmd_param + 1 , param , fragment_len ) ;
skb = __hci_cmd_sync ( hdev , 0xfc09 , fragment_len + 1 ,
cmd_param , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
kfree_skb ( skb ) ;
plen - = fragment_len ;
param + = fragment_len ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_secure_send ) ;
2015-09-04 17:54:34 +02:00
int btintel_load_ddc_config ( struct hci_dev * hdev , const char * ddc_name )
{
const struct firmware * fw ;
struct sk_buff * skb ;
const u8 * fw_ptr ;
int err ;
err = request_firmware_direct ( & fw , ddc_name , & hdev - > dev ) ;
if ( err < 0 ) {
bt_dev_err ( hdev , " Failed to load Intel DDC file %s (%d) " ,
ddc_name , err ) ;
return err ;
}
bt_dev_info ( hdev , " Found Intel DDC parameters: %s " , ddc_name ) ;
fw_ptr = fw - > data ;
/* DDC file contains one or more DDC structure which has
* Length ( 1 byte ) , DDC ID ( 2 bytes ) , and DDC value ( Length - 2 ) .
*/
while ( fw - > size > fw_ptr - fw - > data ) {
u8 cmd_plen = fw_ptr [ 0 ] + sizeof ( u8 ) ;
skb = __hci_cmd_sync ( hdev , 0xfc8b , cmd_plen , fw_ptr ,
HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
bt_dev_err ( hdev , " Failed to send Intel_Write_DDC (%ld) " ,
PTR_ERR ( skb ) ) ;
release_firmware ( fw ) ;
return PTR_ERR ( skb ) ;
}
fw_ptr + = cmd_plen ;
kfree_skb ( skb ) ;
}
release_firmware ( fw ) ;
bt_dev_info ( hdev , " Applying Intel DDC parameters completed " ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_load_ddc_config ) ;
2015-10-21 02:45:19 +02:00
int btintel_set_event_mask ( struct hci_dev * hdev , bool debug )
{
u8 mask [ 8 ] = { 0x87 , 0x0c , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
struct sk_buff * skb ;
int err ;
if ( debug )
mask [ 1 ] | = 0x62 ;
skb = __hci_cmd_sync ( hdev , 0xfc52 , 8 , mask , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
2017-10-30 10:42:59 +01:00
bt_dev_err ( hdev , " Setting Intel event mask failed (%d) " , err ) ;
2015-10-21 02:45:19 +02:00
return err ;
}
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_set_event_mask ) ;
int btintel_set_event_mask_mfg ( struct hci_dev * hdev , bool debug )
{
2015-12-03 16:10:22 +01:00
int err , ret ;
2015-10-21 02:45:19 +02:00
2015-12-03 16:10:22 +01:00
err = btintel_enter_mfg ( hdev ) ;
if ( err )
return err ;
2015-10-21 02:45:19 +02:00
2015-12-03 16:10:22 +01:00
ret = btintel_set_event_mask ( hdev , debug ) ;
2015-10-21 02:45:19 +02:00
2015-12-03 16:10:22 +01:00
err = btintel_exit_mfg ( hdev , false , false ) ;
if ( err )
return err ;
2015-10-21 02:45:19 +02:00
2015-12-03 16:10:22 +01:00
return ret ;
2015-10-21 02:45:19 +02:00
}
EXPORT_SYMBOL_GPL ( btintel_set_event_mask_mfg ) ;
2015-12-06 16:18:34 +01:00
int btintel_read_version ( struct hci_dev * hdev , struct intel_version * ver )
{
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , 0xfc05 , 0 , NULL , 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 - > len ! = sizeof ( * ver ) ) {
bt_dev_err ( hdev , " Intel version event size mismatch " ) ;
kfree_skb ( skb ) ;
return - EILSEQ ;
}
memcpy ( ver , skb - > data , sizeof ( * ver ) ) ;
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_read_version ) ;
2021-03-23 11:58:58 -07:00
int btintel_version_info_tlv ( struct hci_dev * hdev , struct intel_version_tlv * version )
2020-09-14 18:55:05 +05:30
{
const char * variant ;
2021-03-23 11:58:58 -07:00
/* The hardware platform number has a fixed value of 0x37 and
* for now only accept this single value .
*/
if ( INTEL_HW_PLATFORM ( version - > cnvi_bt ) ! = 0x37 ) {
bt_dev_err ( hdev , " Unsupported Intel hardware platform (0x%2x) " ,
INTEL_HW_PLATFORM ( version - > cnvi_bt ) ) ;
return - EINVAL ;
}
/* Check for supported iBT hardware variants of this firmware
* loading method .
*
* This check has been put in place to ensure correct forward
* compatibility options when newer hardware variants come along .
*/
switch ( INTEL_HW_VARIANT ( version - > cnvi_bt ) ) {
case 0x17 : /* TyP */
case 0x18 : /* Slr */
case 0x19 : /* Slr-F */
break ;
default :
bt_dev_err ( hdev , " Unsupported Intel hardware variant (0x%x) " ,
INTEL_HW_VARIANT ( version - > cnvi_bt ) ) ;
return - EINVAL ;
}
2020-09-14 18:55:05 +05:30
switch ( version - > img_type ) {
case 0x01 :
variant = " Bootloader " ;
2021-03-23 11:59:02 -07:00
/* It is required that every single firmware fragment is acknowledged
* with a command complete event . If the boot parameters indicate
* that this bootloader does not send them , then abort the setup .
*/
if ( version - > limited_cce ! = 0x00 ) {
bt_dev_err ( hdev , " Unsupported Intel firmware loading method (0x%x) " ,
version - > limited_cce ) ;
return - EINVAL ;
}
/* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */
if ( version - > sbe_type > 0x01 ) {
bt_dev_err ( hdev , " Unsupported Intel secure boot engine type (0x%x) " ,
version - > sbe_type ) ;
return - EINVAL ;
}
2020-09-14 18:55:05 +05:30
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 ) ;
2021-03-23 11:58:58 -07:00
return - EINVAL ;
2020-09-14 18:55:05 +05:30
}
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 ) ;
2021-03-23 11:58:58 -07:00
return 0 ;
2020-09-14 18:55:05 +05:30
}
EXPORT_SYMBOL_GPL ( btintel_version_info_tlv ) ;
2021-08-04 17:32:09 -07:00
static int btintel_parse_version_tlv ( struct hci_dev * hdev ,
struct intel_version_tlv * version ,
struct sk_buff * skb )
{
/* 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 ;
/* Make sure skb has a minimum length of the header */
if ( skb - > len < sizeof ( * tlv ) )
return - EINVAL ;
tlv = ( struct intel_tlv * ) skb - > data ;
/* Make sure skb has a enough data */
if ( skb - > len < tlv - > len + sizeof ( * tlv ) )
return - EINVAL ;
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 :
/* If image type is Operational firmware (0x03), then
* running FW Calendar Week and Year information can
* be extracted from Timestamp information
*/
version - > min_fw_build_cw = tlv - > val [ 0 ] ;
version - > min_fw_build_yy = tlv - > val [ 1 ] ;
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 :
/* If image type is Operational firmware (0x03), then
* running FW build number can be extracted from the
* Build information
*/
version - > min_fw_build_nn = tlv - > val [ 0 ] ;
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 ,
sizeof ( bdaddr_t ) ) ;
break ;
default :
/* Ignore rest of information */
break ;
}
/* consume the current tlv and move to next*/
skb_pull ( skb , tlv - > len + sizeof ( * tlv ) ) ;
}
return 0 ;
}
2020-09-14 18:55:05 +05:30
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 :
2020-12-16 05:10:38 +05:30
version - > cnvi_top = get_unaligned_le32 ( tlv - > val ) ;
2020-09-14 18:55:05 +05:30
break ;
case INTEL_TLV_CNVR_TOP :
2020-12-16 05:10:38 +05:30
version - > cnvr_top = get_unaligned_le32 ( tlv - > val ) ;
2020-09-14 18:55:05 +05:30
break ;
case INTEL_TLV_CNVI_BT :
2020-12-16 05:10:38 +05:30
version - > cnvi_bt = get_unaligned_le32 ( tlv - > val ) ;
2020-09-14 18:55:05 +05:30
break ;
case INTEL_TLV_CNVR_BT :
2020-12-16 05:10:38 +05:30
version - > cnvr_bt = get_unaligned_le32 ( tlv - > val ) ;
2020-09-14 18:55:05 +05:30
break ;
case INTEL_TLV_DEV_REV_ID :
2020-12-16 05:10:38 +05:30
version - > dev_rev_id = get_unaligned_le16 ( tlv - > val ) ;
2020-09-14 18:55:05 +05:30
break ;
case INTEL_TLV_IMAGE_TYPE :
version - > img_type = tlv - > val [ 0 ] ;
break ;
case INTEL_TLV_TIME_STAMP :
2021-03-23 11:59:03 -07:00
/* If image type is Operational firmware (0x03), then
* running FW Calendar Week and Year information can
* be extracted from Timestamp information
*/
version - > min_fw_build_cw = tlv - > val [ 0 ] ;
version - > min_fw_build_yy = tlv - > val [ 1 ] ;
2020-12-16 05:10:38 +05:30
version - > timestamp = get_unaligned_le16 ( tlv - > val ) ;
2020-09-14 18:55:05 +05:30
break ;
case INTEL_TLV_BUILD_TYPE :
version - > build_type = tlv - > val [ 0 ] ;
break ;
case INTEL_TLV_BUILD_NUM :
2021-03-23 11:59:03 -07:00
/* If image type is Operational firmware (0x03), then
* running FW build number can be extracted from the
* Build information
*/
version - > min_fw_build_nn = tlv - > val [ 0 ] ;
2020-12-16 05:10:38 +05:30
version - > build_num = get_unaligned_le32 ( tlv - > val ) ;
2020-09-14 18:55:05 +05:30
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 ) ;
2015-10-01 18:16:21 +02:00
/* ------- REGMAP IBT SUPPORT ------- */
# define IBT_REG_MODE_8BIT 0x00
# define IBT_REG_MODE_16BIT 0x01
# define IBT_REG_MODE_32BIT 0x02
struct regmap_ibt_context {
struct hci_dev * hdev ;
__u16 op_write ;
__u16 op_read ;
} ;
struct ibt_cp_reg_access {
__le32 addr ;
__u8 mode ;
__u8 len ;
2020-02-12 13:28:07 -06:00
__u8 data [ ] ;
2015-10-01 18:16:21 +02:00
} __packed ;
struct ibt_rp_reg_access {
__u8 status ;
__le32 addr ;
2020-02-12 13:28:07 -06:00
__u8 data [ ] ;
2015-10-01 18:16:21 +02:00
} __packed ;
static int regmap_ibt_read ( void * context , const void * addr , size_t reg_size ,
void * val , size_t val_size )
{
struct regmap_ibt_context * ctx = context ;
struct ibt_cp_reg_access cp ;
struct ibt_rp_reg_access * rp ;
struct sk_buff * skb ;
int err = 0 ;
if ( reg_size ! = sizeof ( __le32 ) )
return - EINVAL ;
switch ( val_size ) {
case 1 :
cp . mode = IBT_REG_MODE_8BIT ;
break ;
case 2 :
cp . mode = IBT_REG_MODE_16BIT ;
break ;
case 4 :
cp . mode = IBT_REG_MODE_32BIT ;
break ;
default :
return - EINVAL ;
}
/* regmap provides a little-endian formatted addr */
cp . addr = * ( __le32 * ) addr ;
cp . len = val_size ;
bt_dev_dbg ( ctx - > hdev , " Register (0x%x) read " , le32_to_cpu ( cp . addr ) ) ;
skb = hci_cmd_sync ( ctx - > hdev , ctx - > op_read , sizeof ( cp ) , & cp ,
HCI_CMD_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
bt_dev_err ( ctx - > hdev , " regmap: Register (0x%x) read error (%d) " ,
le32_to_cpu ( cp . addr ) , err ) ;
return err ;
}
if ( skb - > len ! = sizeof ( * rp ) + val_size ) {
bt_dev_err ( ctx - > hdev , " regmap: Register (0x%x) read error, bad len " ,
le32_to_cpu ( cp . addr ) ) ;
err = - EINVAL ;
goto done ;
}
rp = ( struct ibt_rp_reg_access * ) skb - > data ;
if ( rp - > addr ! = cp . addr ) {
bt_dev_err ( ctx - > hdev , " regmap: Register (0x%x) read error, bad addr " ,
le32_to_cpu ( rp - > addr ) ) ;
err = - EINVAL ;
goto done ;
}
memcpy ( val , rp - > data , val_size ) ;
done :
kfree_skb ( skb ) ;
return err ;
}
static int regmap_ibt_gather_write ( void * context ,
const void * addr , size_t reg_size ,
const void * val , size_t val_size )
{
struct regmap_ibt_context * ctx = context ;
struct ibt_cp_reg_access * cp ;
struct sk_buff * skb ;
int plen = sizeof ( * cp ) + val_size ;
u8 mode ;
int err = 0 ;
if ( reg_size ! = sizeof ( __le32 ) )
return - EINVAL ;
switch ( val_size ) {
case 1 :
mode = IBT_REG_MODE_8BIT ;
break ;
case 2 :
mode = IBT_REG_MODE_16BIT ;
break ;
case 4 :
mode = IBT_REG_MODE_32BIT ;
break ;
default :
return - EINVAL ;
}
cp = kmalloc ( plen , GFP_KERNEL ) ;
if ( ! cp )
return - ENOMEM ;
/* regmap provides a little-endian formatted addr/value */
cp - > addr = * ( __le32 * ) addr ;
cp - > mode = mode ;
cp - > len = val_size ;
memcpy ( & cp - > data , val , val_size ) ;
bt_dev_dbg ( ctx - > hdev , " Register (0x%x) write " , le32_to_cpu ( cp - > addr ) ) ;
skb = hci_cmd_sync ( ctx - > hdev , ctx - > op_write , plen , cp , HCI_CMD_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
bt_dev_err ( ctx - > hdev , " regmap: Register (0x%x) write error (%d) " ,
le32_to_cpu ( cp - > addr ) , err ) ;
goto done ;
}
kfree_skb ( skb ) ;
done :
kfree ( cp ) ;
return err ;
}
static int regmap_ibt_write ( void * context , const void * data , size_t count )
{
/* data contains register+value, since we only support 32bit addr,
* minimum data size is 4 bytes .
*/
if ( WARN_ONCE ( count < 4 , " Invalid register access " ) )
return - EINVAL ;
return regmap_ibt_gather_write ( context , data , 4 , data + 4 , count - 4 ) ;
}
static void regmap_ibt_free_context ( void * context )
{
kfree ( context ) ;
}
static struct regmap_bus regmap_ibt = {
. read = regmap_ibt_read ,
. write = regmap_ibt_write ,
. gather_write = regmap_ibt_gather_write ,
. free_context = regmap_ibt_free_context ,
. reg_format_endian_default = REGMAP_ENDIAN_LITTLE ,
. val_format_endian_default = REGMAP_ENDIAN_LITTLE ,
} ;
/* Config is the same for all register regions */
static const struct regmap_config regmap_ibt_cfg = {
. name = " btintel_regmap " ,
. reg_bits = 32 ,
. val_bits = 32 ,
} ;
struct regmap * btintel_regmap_init ( struct hci_dev * hdev , u16 opcode_read ,
u16 opcode_write )
{
struct regmap_ibt_context * ctx ;
bt_dev_info ( hdev , " regmap: Init R%x-W%x region " , opcode_read ,
opcode_write ) ;
ctx = kzalloc ( sizeof ( * ctx ) , GFP_KERNEL ) ;
if ( ! ctx )
return ERR_PTR ( - ENOMEM ) ;
ctx - > op_read = opcode_read ;
ctx - > op_write = opcode_write ;
ctx - > hdev = hdev ;
return regmap_init ( & hdev - > dev , & regmap_ibt , ctx , & regmap_ibt_cfg ) ;
}
EXPORT_SYMBOL_GPL ( btintel_regmap_init ) ;
2018-01-24 09:19:18 -08:00
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 ) ;
2018-01-24 09:19:20 -08:00
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 ) ;
2020-09-11 17:14:17 +05:30
static int btintel_sfi_rsa_header_secure_send ( struct hci_dev * hdev ,
const struct firmware * fw )
2018-01-24 09:19:21 -08:00
{
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 ) ;
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 ;
}
2020-09-11 17:14:17 +05:30
done :
return err ;
}
2020-09-14 18:55:06 +05:30
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 ;
}
2020-09-11 17:14:17 +05:30
static int btintel_download_firmware_payload ( struct hci_dev * hdev ,
const struct firmware * fw ,
2021-03-23 11:58:56 -07:00
size_t offset )
2020-09-11 17:14:17 +05:30
{
int err ;
const u8 * fw_ptr ;
u32 frag_len ;
fw_ptr = fw - > data + offset ;
2018-01-24 09:19:21 -08:00
frag_len = 0 ;
2020-09-11 17:14:17 +05:30
err = - EINVAL ;
2018-01-24 09:19:21 -08:00
while ( fw_ptr - fw - > data < fw - > size ) {
struct hci_command_hdr * cmd = ( void * ) ( fw_ptr + frag_len ) ;
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 ;
}
2020-09-11 17:14:17 +05:30
2021-03-23 11:58:56 -07:00
static bool btintel_firmware_version ( struct hci_dev * hdev ,
u8 num , u8 ww , u8 yy ,
const struct firmware * fw ,
u32 * boot_addr )
{
const u8 * fw_ptr ;
fw_ptr = fw - > data ;
while ( fw_ptr - fw - > data < fw - > size ) {
struct hci_command_hdr * cmd = ( void * ) ( fw_ptr ) ;
/* 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 ) = = CMD_WRITE_BOOT_PARAMS ) {
struct cmd_write_boot_params * params ;
params = ( void * ) ( fw_ptr + sizeof ( * cmd ) ) ;
bt_dev_info ( hdev , " Boot Address: 0x%x " ,
le32_to_cpu ( params - > boot_addr ) ) ;
bt_dev_info ( hdev , " Firmware Version: %u-%u.%u " ,
params - > fw_build_num , params - > fw_build_ww ,
params - > fw_build_yy ) ;
return ( num = = params - > fw_build_num & &
ww = = params - > fw_build_ww & &
yy = = params - > fw_build_yy ) ;
}
fw_ptr + = sizeof ( * cmd ) + cmd - > plen ;
}
return false ;
}
2020-09-11 17:14:17 +05:30
int btintel_download_firmware ( struct hci_dev * hdev ,
2021-03-23 11:58:56 -07:00
struct intel_version * ver ,
2020-09-11 17:14:17 +05:30
const struct firmware * fw ,
u32 * boot_param )
{
int err ;
2021-03-23 11:58:56 -07:00
/* SfP and WsP don't seem to update the firmware version on file
* so version checking is currently not possible .
*/
switch ( ver - > hw_variant ) {
case 0x0b : /* SfP */
case 0x0c : /* WsP */
/* Skip version checking */
break ;
default :
2021-03-23 11:59:04 -07:00
/* Skip reading firmware file version in bootloader mode */
if ( ver - > fw_variant = = 0x06 )
break ;
2021-03-23 11:58:56 -07:00
/* Skip download if firmware has the same version */
if ( btintel_firmware_version ( hdev , ver - > fw_build_num ,
ver - > fw_build_ww , ver - > fw_build_yy ,
fw , boot_param ) ) {
bt_dev_info ( hdev , " Firmware already loaded " ) ;
/* Return -EALREADY to indicate that the firmware has
* already been loaded .
*/
return - EALREADY ;
}
}
2021-03-23 11:58:57 -07:00
/* The firmware variant determines if the device is in bootloader
* mode or is running operational firmware . The value 0x06 identifies
* the bootloader and the value 0x23 identifies the operational
* firmware .
*
* If the firmware version has changed that means it needs to be reset
* to bootloader when operational so the new firmware can be loaded .
*/
if ( ver - > fw_variant = = 0x23 )
return - EINVAL ;
2020-09-11 17:14:17 +05:30
err = btintel_sfi_rsa_header_secure_send ( hdev , fw ) ;
if ( err )
return err ;
2021-03-23 11:58:56 -07:00
return btintel_download_firmware_payload ( hdev , fw , RSA_HEADER_LEN ) ;
2020-09-11 17:14:17 +05:30
}
2018-01-24 09:19:21 -08:00
EXPORT_SYMBOL_GPL ( btintel_download_firmware ) ;
2020-09-14 18:55:06 +05:30
int btintel_download_firmware_newgen ( struct hci_dev * hdev ,
2021-03-23 11:58:56 -07:00
struct intel_version_tlv * ver ,
2020-09-14 18:55:06 +05:30
const struct firmware * fw , u32 * boot_param ,
u8 hw_variant , u8 sbe_type )
{
int err ;
u32 css_header_ver ;
2021-03-23 11:59:04 -07:00
/* Skip reading firmware file version in bootloader mode */
if ( ver - > img_type ! = 0x01 ) {
/* Skip download if firmware has the same version */
if ( btintel_firmware_version ( hdev , ver - > min_fw_build_nn ,
ver - > min_fw_build_cw ,
ver - > min_fw_build_yy ,
fw , boot_param ) ) {
bt_dev_info ( hdev , " Firmware already loaded " ) ;
/* Return -EALREADY to indicate that firmware has
* already been loaded .
*/
return - EALREADY ;
}
2021-03-23 11:58:56 -07:00
}
2021-03-23 11:58:57 -07:00
/* The firmware variant determines if the device is in bootloader
* mode or is running operational firmware . The value 0x01 identifies
* the bootloader and the value 0x03 identifies the operational
* firmware .
*
* If the firmware version has changed that means it needs to be reset
* to bootloader when operational so the new firmware can be loaded .
*/
if ( ver - > img_type = = 0x03 )
return - EINVAL ;
2020-09-14 18:55:06 +05:30
/* 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 ;
2021-03-23 11:58:56 -07:00
err = btintel_download_firmware_payload ( hdev , fw , RSA_HEADER_LEN ) ;
2020-09-14 18:55:06 +05:30
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 ,
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 ,
RSA_HEADER_LEN + ECDSA_HEADER_LEN ) ;
if ( err )
return err ;
}
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_download_firmware_newgen ) ;
2019-10-17 13:52:29 +05:30
void btintel_reset_to_bootloader ( struct hci_dev * hdev )
{
struct intel_reset params ;
struct sk_buff * skb ;
/* Send Intel Reset command. This will result in
* re - enumeration of BT controller .
*
* Intel Reset parameter description :
* reset_type : 0x00 ( Soft reset ) ,
* 0x01 ( Hard reset )
* patch_enable : 0x00 ( Do not enable ) ,
* 0x01 ( Enable )
* ddc_reload : 0x00 ( Do not reload ) ,
* 0x01 ( Reload )
* boot_option : 0x00 ( Current image ) ,
* 0x01 ( Specified boot address )
* boot_param : Boot address
*
*/
params . reset_type = 0x01 ;
params . patch_enable = 0x01 ;
params . ddc_reload = 0x01 ;
params . boot_option = 0x00 ;
params . boot_param = cpu_to_le32 ( 0x00000000 ) ;
skb = __hci_cmd_sync ( hdev , 0xfc01 , sizeof ( params ) ,
& params , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
bt_dev_err ( hdev , " FW download error recovery failed (%ld) " ,
PTR_ERR ( skb ) ) ;
return ;
}
bt_dev_info ( hdev , " Intel reset sent to retry FW download " ) ;
kfree_skb ( skb ) ;
/* Current Intel BT controllers(ThP/JfP) hold the USB reset
* lines for 2 ms when it receives Intel Reset in bootloader mode .
* Whereas , the upcoming Intel BT controllers will hold USB reset
* for 150 ms . To keep the delay generic , 150 ms is chosen here .
*/
msleep ( 150 ) ;
}
EXPORT_SYMBOL_GPL ( btintel_reset_to_bootloader ) ;
2020-06-08 17:57:46 +05:30
int btintel_read_debug_features ( struct hci_dev * hdev ,
struct intel_debug_features * features )
{
struct sk_buff * skb ;
u8 page_no = 1 ;
/* Intel controller supports two pages, each page is of 128-bit
* feature bit mask . And each bit defines specific feature support
*/
skb = __hci_cmd_sync ( hdev , 0xfca6 , sizeof ( page_no ) , & page_no ,
HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
bt_dev_err ( hdev , " Reading supported features failed (%ld) " ,
PTR_ERR ( skb ) ) ;
return PTR_ERR ( skb ) ;
}
if ( skb - > len ! = ( sizeof ( features - > page1 ) + 3 ) ) {
bt_dev_err ( hdev , " Supported features event size mismatch " ) ;
kfree_skb ( skb ) ;
return - EILSEQ ;
}
memcpy ( features - > page1 , skb - > data + 3 , sizeof ( features - > page1 ) ) ;
/* Read the supported features page2 if required in future.
*/
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_read_debug_features ) ;
2020-06-08 17:57:47 +05:30
int btintel_set_debug_features ( struct hci_dev * hdev ,
const struct intel_debug_features * features )
{
u8 mask [ 11 ] = { 0x0a , 0x92 , 0x02 , 0x07 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 } ;
struct sk_buff * skb ;
if ( ! features )
return - EINVAL ;
if ( ! ( features - > page1 [ 0 ] & 0x3f ) ) {
bt_dev_info ( hdev , " Telemetry exception format not supported " ) ;
return 0 ;
}
skb = __hci_cmd_sync ( hdev , 0xfc8b , 11 , mask , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
bt_dev_err ( hdev , " Setting Intel telemetry ddc write event mask failed (%ld) " ,
PTR_ERR ( skb ) ) ;
return PTR_ERR ( skb ) ;
}
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_set_debug_features ) ;
2021-08-04 17:32:10 -07:00
static const struct firmware * btintel_legacy_rom_get_fw ( struct hci_dev * hdev ,
struct intel_version * ver )
{
const struct firmware * fw ;
char fwname [ 64 ] ;
int ret ;
snprintf ( fwname , sizeof ( fwname ) ,
" intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq " ,
ver - > hw_platform , ver - > hw_variant , ver - > hw_revision ,
ver - > fw_variant , ver - > fw_revision , ver - > fw_build_num ,
ver - > fw_build_ww , ver - > fw_build_yy ) ;
ret = request_firmware ( & fw , fwname , & hdev - > dev ) ;
if ( ret < 0 ) {
if ( ret = = - EINVAL ) {
bt_dev_err ( hdev , " Intel firmware file request failed (%d) " ,
ret ) ;
return NULL ;
}
bt_dev_err ( hdev , " failed to open Intel firmware file: %s (%d) " ,
fwname , ret ) ;
/* If the correct firmware patch file is not found, use the
* default firmware patch file instead
*/
snprintf ( fwname , sizeof ( fwname ) , " intel/ibt-hw-%x.%x.bseq " ,
ver - > hw_platform , ver - > hw_variant ) ;
if ( request_firmware ( & fw , fwname , & hdev - > dev ) < 0 ) {
bt_dev_err ( hdev , " failed to open default fw file: %s " ,
fwname ) ;
return NULL ;
}
}
bt_dev_info ( hdev , " Intel Bluetooth firmware file: %s " , fwname ) ;
return fw ;
}
static int btintel_legacy_rom_patching ( struct hci_dev * hdev ,
const struct firmware * fw ,
const u8 * * fw_ptr , int * disable_patch )
{
struct sk_buff * skb ;
struct hci_command_hdr * cmd ;
const u8 * cmd_param ;
struct hci_event_hdr * evt = NULL ;
const u8 * evt_param = NULL ;
int remain = fw - > size - ( * fw_ptr - fw - > data ) ;
/* The first byte indicates the types of the patch command or event.
* 0x01 means HCI command and 0x02 is HCI event . If the first bytes
* in the current firmware buffer doesn ' t start with 0x01 or
* the size of remain buffer is smaller than HCI command header ,
* the firmware file is corrupted and it should stop the patching
* process .
*/
if ( remain > HCI_COMMAND_HDR_SIZE & & * fw_ptr [ 0 ] ! = 0x01 ) {
bt_dev_err ( hdev , " Intel fw corrupted: invalid cmd read " ) ;
return - EINVAL ;
}
( * fw_ptr ) + + ;
remain - - ;
cmd = ( struct hci_command_hdr * ) ( * fw_ptr ) ;
* fw_ptr + = sizeof ( * cmd ) ;
remain - = sizeof ( * cmd ) ;
/* Ensure that the remain firmware data is long enough than the length
* of command parameter . If not , the firmware file is corrupted .
*/
if ( remain < cmd - > plen ) {
bt_dev_err ( hdev , " Intel fw corrupted: invalid cmd len " ) ;
return - EFAULT ;
}
/* If there is a command that loads a patch in the firmware
* file , then enable the patch upon success , otherwise just
* disable the manufacturer mode , for example patch activation
* is not required when the default firmware patch file is used
* because there are no patch data to load .
*/
if ( * disable_patch & & le16_to_cpu ( cmd - > opcode ) = = 0xfc8e )
* disable_patch = 0 ;
cmd_param = * fw_ptr ;
* fw_ptr + = cmd - > plen ;
remain - = cmd - > plen ;
/* This reads the expected events when the above command is sent to the
* device . Some vendor commands expects more than one events , for
* example command status event followed by vendor specific event .
* For this case , it only keeps the last expected event . so the command
* can be sent with __hci_cmd_sync_ev ( ) which returns the sk_buff of
* last expected event .
*/
while ( remain > HCI_EVENT_HDR_SIZE & & * fw_ptr [ 0 ] = = 0x02 ) {
( * fw_ptr ) + + ;
remain - - ;
evt = ( struct hci_event_hdr * ) ( * fw_ptr ) ;
* fw_ptr + = sizeof ( * evt ) ;
remain - = sizeof ( * evt ) ;
if ( remain < evt - > plen ) {
bt_dev_err ( hdev , " Intel fw corrupted: invalid evt len " ) ;
return - EFAULT ;
}
evt_param = * fw_ptr ;
* fw_ptr + = evt - > plen ;
remain - = evt - > plen ;
}
/* Every HCI commands in the firmware file has its correspond event.
* If event is not found or remain is smaller than zero , the firmware
* file is corrupted .
*/
if ( ! evt | | ! evt_param | | remain < 0 ) {
bt_dev_err ( hdev , " Intel fw corrupted: invalid evt read " ) ;
return - EFAULT ;
}
skb = __hci_cmd_sync_ev ( hdev , le16_to_cpu ( cmd - > opcode ) , cmd - > plen ,
cmd_param , evt - > evt , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
bt_dev_err ( hdev , " sending Intel patch command (0x%4.4x) failed (%ld) " ,
cmd - > opcode , PTR_ERR ( skb ) ) ;
return PTR_ERR ( skb ) ;
}
/* It ensures that the returned event matches the event data read from
* the firmware file . At fist , it checks the length and then
* the contents of the event .
*/
if ( skb - > len ! = evt - > plen ) {
bt_dev_err ( hdev , " mismatch event length (opcode 0x%4.4x) " ,
le16_to_cpu ( cmd - > opcode ) ) ;
kfree_skb ( skb ) ;
return - EFAULT ;
}
if ( memcmp ( skb - > data , evt_param , evt - > plen ) ) {
bt_dev_err ( hdev , " mismatch event parameter (opcode 0x%4.4x) " ,
le16_to_cpu ( cmd - > opcode ) ) ;
kfree_skb ( skb ) ;
return - EFAULT ;
}
kfree_skb ( skb ) ;
return 0 ;
}
static int btintel_legacy_rom_setup ( struct hci_dev * hdev ,
struct intel_version * ver )
{
const struct firmware * fw ;
const u8 * fw_ptr ;
int disable_patch , err ;
struct intel_version new_ver ;
BT_DBG ( " %s " , hdev - > name ) ;
/* fw_patch_num indicates the version of patch the device currently
* have . If there is no patch data in the device , it is always 0x00 .
* So , if it is other than 0x00 , no need to patch the device again .
*/
if ( ver - > fw_patch_num ) {
bt_dev_info ( hdev ,
" Intel device is already patched. patch num: %02x " ,
ver - > fw_patch_num ) ;
goto complete ;
}
/* Opens the firmware patch file based on the firmware version read
* from the controller . If it fails to open the matching firmware
* patch file , it tries to open the default firmware patch file .
* If no patch file is found , allow the device to operate without
* a patch .
*/
fw = btintel_legacy_rom_get_fw ( hdev , ver ) ;
if ( ! fw )
goto complete ;
fw_ptr = fw - > data ;
/* Enable the manufacturer mode of the controller.
* Only while this mode is enabled , the driver can download the
* firmware patch data and configuration parameters .
*/
err = btintel_enter_mfg ( hdev ) ;
if ( err ) {
release_firmware ( fw ) ;
return err ;
}
disable_patch = 1 ;
/* The firmware data file consists of list of Intel specific HCI
* commands and its expected events . The first byte indicates the
* type of the message , either HCI command or HCI event .
*
* It reads the command and its expected event from the firmware file ,
* and send to the controller . Once __hci_cmd_sync_ev ( ) returns ,
* the returned event is compared with the event read from the firmware
* file and it will continue until all the messages are downloaded to
* the controller .
*
* Once the firmware patching is completed successfully ,
* the manufacturer mode is disabled with reset and activating the
* downloaded patch .
*
* If the firmware patching fails , the manufacturer mode is
* disabled with reset and deactivating the patch .
*
* If the default patch file is used , no reset is done when disabling
* the manufacturer .
*/
while ( fw - > size > fw_ptr - fw - > data ) {
int ret ;
ret = btintel_legacy_rom_patching ( hdev , fw , & fw_ptr ,
& disable_patch ) ;
if ( ret < 0 )
goto exit_mfg_deactivate ;
}
release_firmware ( fw ) ;
if ( disable_patch )
goto exit_mfg_disable ;
/* Patching completed successfully and disable the manufacturer mode
* with reset and activate the downloaded firmware patches .
*/
err = btintel_exit_mfg ( hdev , true , true ) ;
if ( err )
return err ;
/* Need build number for downloaded fw patches in
* every power - on boot
*/
err = btintel_read_version ( hdev , & new_ver ) ;
if ( err )
return err ;
bt_dev_info ( hdev , " Intel BT fw patch 0x%02x completed & activated " ,
new_ver . fw_patch_num ) ;
goto complete ;
exit_mfg_disable :
/* Disable the manufacturer mode without reset */
err = btintel_exit_mfg ( hdev , false , false ) ;
if ( err )
return err ;
bt_dev_info ( hdev , " Intel firmware patch completed " ) ;
goto complete ;
exit_mfg_deactivate :
release_firmware ( fw ) ;
/* Patching failed. Disable the manufacturer mode with reset and
* deactivate the downloaded firmware patches .
*/
err = btintel_exit_mfg ( hdev , true , false ) ;
if ( err )
return err ;
bt_dev_info ( hdev , " Intel firmware patch completed and deactivated " ) ;
complete :
/* Set the event mask for Intel specific vendor events. This enables
* a few extra events that are useful during general operation .
*/
btintel_set_event_mask_mfg ( hdev , false ) ;
btintel_check_bdaddr ( hdev ) ;
return 0 ;
}
2021-08-04 17:32:09 -07:00
static int btintel_setup_combined ( struct hci_dev * hdev )
{
const u8 param [ 1 ] = { 0xFF } ;
struct intel_version ver ;
struct intel_version_tlv ver_tlv ;
struct sk_buff * skb ;
int err ;
BT_DBG ( " %s " , hdev - > name ) ;
/* Starting from TyP device, the command parameter and response are
* changed even though the OCF for HCI_Intel_Read_Version command
* remains same . The legacy devices can handle even if the
* command has a parameter and returns a correct version information .
* So , it uses new format to support both legacy and new format .
*/
skb = __hci_cmd_sync ( hdev , 0xfc05 , 1 , param , HCI_CMD_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
bt_dev_err ( hdev , " Reading Intel version command failed (%ld) " ,
PTR_ERR ( skb ) ) ;
return PTR_ERR ( skb ) ;
}
/* Check the status */
if ( skb - > data [ 0 ] ) {
bt_dev_err ( hdev , " Intel Read Version command failed (%02x) " ,
skb - > data [ 0 ] ) ;
err = - EIO ;
goto exit_error ;
}
/* For Legacy device, check the HW platform value and size */
if ( skb - > len = = sizeof ( ver ) & & skb - > data [ 1 ] = = 0x37 ) {
bt_dev_dbg ( hdev , " Read the legacy Intel version information " ) ;
memcpy ( & ver , skb - > data , sizeof ( ver ) ) ;
/* Display version information */
btintel_version_info ( hdev , & ver ) ;
/* Check for supported iBT hardware variants of this firmware
* loading method .
*
* This check has been put in place to ensure correct forward
* compatibility options when newer hardware variants come
* along .
*/
switch ( ver . hw_variant ) {
case 0x07 : /* WP */
case 0x08 : /* StP */
/* Legacy ROM product */
2021-08-04 17:32:10 -07:00
err = btintel_legacy_rom_setup ( hdev , & ver ) ;
2021-08-04 17:32:09 -07:00
break ;
case 0x0b : /* SfP */
case 0x0c : /* WsP */
case 0x11 : /* JfP */
case 0x12 : /* ThP */
case 0x13 : /* HrP */
case 0x14 : /* CcP */
/* TODO: call setup routine for bootloader product */
break ;
default :
bt_dev_err ( hdev , " Unsupported Intel hw variant (%u) " ,
ver . hw_variant ) ;
err = - EINVAL ;
}
goto exit_error ;
}
/* For TLV type device, parse the tlv data */
err = btintel_parse_version_tlv ( hdev , & ver_tlv , skb ) ;
if ( err ) {
bt_dev_err ( hdev , " Failed to parse TLV version information " ) ;
goto exit_error ;
}
if ( INTEL_HW_PLATFORM ( ver_tlv . cnvi_bt ) ! = 0x37 ) {
bt_dev_err ( hdev , " Unsupported Intel hardware platform (0x%2x) " ,
INTEL_HW_PLATFORM ( ver_tlv . cnvi_bt ) ) ;
err = - EINVAL ;
goto exit_error ;
}
/* Display version information of TLV type */
btintel_version_info_tlv ( hdev , & ver_tlv ) ;
/* TODO: Need to filter the device for new generation */
/* TODO: call setup routine for tlv based bootloader product */
exit_error :
kfree_skb ( skb ) ;
return err ;
}
static int btintel_shutdown_combined ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
/* Send HCI Reset to the controller to stop any BT activity which
* were triggered . This will help to save power and maintain the
* sync b / w Host and controller
*/
skb = __hci_cmd_sync ( hdev , HCI_OP_RESET , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
bt_dev_err ( hdev , " HCI reset during shutdown failed " ) ;
return PTR_ERR ( skb ) ;
}
kfree_skb ( skb ) ;
return 0 ;
}
int btintel_configure_setup ( struct hci_dev * hdev )
{
hdev - > manufacturer = 2 ;
hdev - > setup = btintel_setup_combined ;
hdev - > shutdown = btintel_shutdown_combined ;
2021-08-04 17:32:10 -07:00
hdev - > set_diag = btintel_set_diag_mfg ;
hdev - > set_bdaddr = btintel_set_bdaddr ;
2021-08-04 17:32:09 -07:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( btintel_configure_setup ) ;
2015-04-06 00:52:11 -07:00
MODULE_AUTHOR ( " Marcel Holtmann <marcel@holtmann.org> " ) ;
MODULE_DESCRIPTION ( " Bluetooth support for Intel devices ver " VERSION ) ;
MODULE_VERSION ( VERSION ) ;
MODULE_LICENSE ( " GPL " ) ;
2015-08-27 08:57:39 +02:00
MODULE_FIRMWARE ( " intel/ibt-11-5.sfi " ) ;
MODULE_FIRMWARE ( " intel/ibt-11-5.ddc " ) ;
2017-05-23 18:46:25 +02:00
MODULE_FIRMWARE ( " intel/ibt-12-16.sfi " ) ;
MODULE_FIRMWARE ( " intel/ibt-12-16.ddc " ) ;